オープンソースこねこね

Webプログラミングなどについてあれこれ。

LaravelのRouteクラスがグローバル空間で呼び出せる仕組み

最近Laravelを触っています。

で、LaravelだとURLと実行するアクションを関連付けるルーティング部分を

Route::get('/', function()
{
    return 'Hello World';
});

こんなふうに、RubySinatraっぽくかけるんですよね。ところがこのRouteというクラス、事前にuseで使う名前空間の指定もしていないし、実際にどのPHPクラスが使われているかよくわからない。そこでソースを追ってみました。

エイリアス

フロントコントローラのpubic/index.phpを起点に読み始めていくと、

pubic/index.php->bootstrap/start.php->vendor/laravel/framework/src/Illuminate/Foundation/start.phpとファイルが読み込まれて、この中で、

$aliases = $config['aliases'];

AliasLoader::getInstance($aliases)->register();

ということをやっている。でregisterメソッドで$aliasesのデータつかってspl_autoload_register関数を呼び出してオートローディングを設定している。$aliasesの内容はメインのコンフィグファイルconfig/app.phpにかかれていて、デフォルトは以下のようになっている。

'aliases' => array(

                'App'             => 'Illuminate\Support\Facades\App',
                'Artisan'         => 'Illuminate\Support\Facades\Artisan',
                'Auth'            => 'Illuminate\Support\Facades\Auth',
                'Blade'           => 'Illuminate\Support\Facades\Blade',
                'Cache'           => 'Illuminate\Support\Facades\Cache',
                'ClassLoader'     => 'Illuminate\Support\ClassLoader',
                'Config'          => 'Illuminate\Support\Facades\Config',
                'Controller'      => 'Illuminate\Routing\Controller',
                'Cookie'          => 'Illuminate\Support\Facades\Cookie',
                'Crypt'           => 'Illuminate\Support\Facades\Crypt',
                'DB'              => 'Illuminate\Support\Facades\DB',
                'Eloquent'        => 'Illuminate\Database\Eloquent\Model',
                'Event'           => 'Illuminate\Support\Facades\Event',
                'File'            => 'Illuminate\Support\Facades\File',
                'Form'            => 'Illuminate\Support\Facades\Form',
                'Hash'            => 'Illuminate\Support\Facades\Hash',
                'HTML'            => 'Illuminate\Support\Facades\HTML',
                'Input'           => 'Illuminate\Support\Facades\Input',
                'Lang'            => 'Illuminate\Support\Facades\Lang',
                'Log'             => 'Illuminate\Support\Facades\Log',
                'Mail'            => 'Illuminate\Support\Facades\Mail',
                'Paginator'       => 'Illuminate\Support\Facades\Paginator',
                'Password'        => 'Illuminate\Support\Facades\Password',
                'Queue'           => 'Illuminate\Support\Facades\Queue',
                'Redirect'        => 'Illuminate\Support\Facades\Redirect',
                'Redis'           => 'Illuminate\Support\Facades\Redis',
                'Request'         => 'Illuminate\Support\Facades\Request',
                'Response'        => 'Illuminate\Support\Facades\Response',
                'Route'           => 'Illuminate\Support\Facades\Route',
                'Schema'          => 'Illuminate\Support\Facades\Schema',
                'Seeder'          => 'Illuminate\Database\Seeder',
                'Session'         => 'Illuminate\Support\Facades\Session',
                'SSH'             => 'Illuminate\Support\Facades\SSH',
                'Str'             => 'Illuminate\Support\Str',
                'URL'             => 'Illuminate\Support\Facades\URL',
                'Validator'       => 'Illuminate\Support\Facades\Validator',
                'View'            => 'Illuminate\Support\Facades\View',

        ),

つまりRouteクラスの実体はIlluminate\Support\Facades\Routeということがわかる。

Laravelは自前で設定ファイルからオートローディングの登録を行うロジックをもっていて、それをつかってグローバル空間にクラスのエイリアスを作るという機能を実装していたわけだった。

※じつはIlluminate\Support\Facades\Routeにはルーティングに使用していた上記のgetメソッドは直接定義されておらず、ここからさらにFacadeという仕組みをつかって、別のクラスに実装を移しているのだけど割愛。

PHPDSLっぽいこと

調べてみると、どうってことはない作りでした。でもこの仕組みは、クラスの実装はネームスペースで構造化された空間に定義でき、インターフェースのみグローバル空間に公開するというのが、うまく出来てると思う。これに無名関数を組み合わせることで、LaravelのRoute定義のような、Rubyの内部DSL的な記述をPHP上に表現しているのだな、とちょっと感心したのでした。

おしまい。

epelにdockerがキタ━(゚∀゚)━!ので、CentOSにインストールした。

ローカルのVirtualBox上のCentOS6で動かしました。epelリポジトリは事前に設定してあるものとします。

インストール

# yum install --enablerepo=epel docker-io

サービスの起動

# /etc/init.d/docker start

doceker runする!

# docker run -t -i centos /bin/bash

コンテナ内でシェルが起動します。echoとか打ってみる。

bash-4.1# echo hello world!
hello world!
bash-4.1# exit

うごく~( ´∀`)♪

Dockerfileからimageつくってみる

Dockerfile

FROM centos
RUN yum clean all
RUN yum install -y openssh-server
RUN yum install -y passwd
RUN echo d0cker | passwd --stdin root

## https://github.com/dotcloud/docker/issues/1240#issuecomment-21807183
RUN echo "NETWORKING=yes" > /etc/sysconfig/network

## http://gaijin-nippon.blogspot.com/2013/07/audit-on-lxc-host.html
RUN sed -i -e '/pam_loginuid\.so/ d' /etc/pam.d/sshd

EXPOSE 22
CMD /sbin/init

docker buildする!

# docker build -t test .
Uploading context 10240 bytes
Step 1 : FROM centos
 ---> 539c0211cd76
Step 2 : RUN yum clean all
 ---> Using cache
 ---> f738a5199bab
Step 3 : RUN yum install -y openssh-server
 ---> Running in 033f90a21823
Loaded plugins: fastestmirror
Determining fastest mirrors
Error: Cannot find a valid baseurl for repo: base
Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=6&arch=x86_64&repo=os error was
14: PYCURL ERROR 6 - "Couldn't resolve host 'mirrorlist.centos.org'"
Error build: The command [/bin/sh -c yum install -y openssh-server] returned a non-zero code: 1

おちた~(T_T)!!なんでかコンテナからインターネットに接続できん。のおおお!

2013-12-07追記:とおもったらVirtulaBoxのVMから作りなおしたら出来た。何がわるかったかわからんす。

2013-12-10追記:ネット接続できない問題は/etc/sysctl.confnet.ipv4.ip_forward = 1にしたら治ったのかもしれない。でもCMD /sbin/initは結局うまく動いてくれない。Dockerで/sbin/initを動かすのはGithubのissuseにもあがっていて、みんな試行錯誤してるようだけど、まだ解決していないっぽいですな。

ElasticsearchでCentOS上にNgram全文検索サーバを構築する - (その2)Ngramアナライザを設定する

前回に引き続きElasticsearchの設定を行います。

elasticsearch-headプラグインをインストールする

いろいろ設定を試していたりすると、設定内容やデータの確認のためにコンソールからcurlを実行してREST APIを実行するのが面倒になります。そこでElasticsearchにはWebUIからデータや設定内容を参照するための機能がプラグインで用意されているので、これを導入します。

インストールは以下のコマンドを実行するだけでOKです。

$ sudo /usr/share/elasticsearch/bin/plugin --install mobz/elasticsearch-head

あとはブラウザから

http://localhost:9200/_plugin/head/

にアクセスすればWebUIからデータの操作ができるようになります。

アナライザ

アナライザは、文字列タイプのフィールドをElasticsearchにインデックスする(データを保存する)ときや検索クエリを投げるときに行われる処理で、データを品詞分解したり、大文字小文字の入力を変換したりするテキストの解析処理のことです。インデックスするときと検索時に別々のアナライザを使うこともできます。

デフォルトでいくつかアナライザが用意されていますが、自分で定義することもできます。 今回は日本語をNgram検索をしたいのでカスタムアナライザを定義しました。なおNgramについてはググる

http://gihyo.jp/dev/serial/01/make-findspot/0005

などの参照してください。

/etc/elasticsearch/elasticsearch.ymlに以下の定義を追加します

# default analyzer (1-gram and 2-gram)
index.analysis.analyzer.default.tokenizer: custom_ngram_tokenizer
index.analysis.analyzer.default.filter.0: lowercase

index.analysis.tokenizer.custom_ngram_tokenizer.type: nGram
index.analysis.tokenizer.custom_ngram_tokenizer.min_gram: 1
index.analysis.tokenizer.custom_ngram_tokenizer.max_gram: 2
index.analysis.tokenizer.custom_ngram_tokenizer.token_chars.0: letter
index.analysis.tokenizer.custom_ngram_tokenizer.token_chars.1: digit

# default_search analayzer(2-gram)
index.analysis.analyzer.default_search.tokenizer: custom_bigram_tokenizer
index.analysis.analyzer.default_search.filter.0: lowercase

index.analysis.tokenizer.custom_bigram_tokenizer.type: nGram
index.analysis.tokenizer.custom_bigram_tokenizer.min_gram: 2
index.analysis.tokenizer.custom_bigram_tokenizer.max_gram: 2
index.analysis.tokenizer.custom_bigram_tokenizer.token_chars.0: letter
index.analysis.tokenizer.custom_bigram_tokenizer.token_chars.1: digit

設定を反映させるため、Elasticsearchを再起動し、データを再投入します。

さて、上記のアナライザの定義ですが、2つのカスタムアナライザを定義しています。まず最初の

# default analyzer (1-gram and 2-gram)
index.analysis.analyzer.default.tokenizer: custom_ngram_tokenizer
index.analysis.analyzer.default.filter.0: lowercase

部分ですが、index.analysis.analyzer.defaultというキーでデフォルトのアナライザを定義しています。index.analysis.analyzer.default.tokenizer: custom_ngram_tokenizerはトークナイザ(品詞分解する処理)にcustom_ngram_tokenizerを使うことを設定しています。で、このcustom_ngram_tokenizerはその下に設定内容が書いてあります。

index.analysis.tokenizer.custom_ngram_tokenizer.type: nGram
index.analysis.tokenizer.custom_ngram_tokenizer.min_gram: 1
index.analysis.tokenizer.custom_ngram_tokenizer.max_gram: 2
index.analysis.tokenizer.custom_ngram_tokenizer.token_chars.0: letter
index.analysis.tokenizer.custom_ngram_tokenizer.token_chars.1: digit

文字を1-gramおよび2-gramで分解する設定となっています。つまり、

こんにちは

という文字は

こん, んに, にち, ちは
こ,ん,に,ち,は

というように分解されインデックスされます。さて、もう一つのアナライザですが、

# default_search analayzer(2-gram)
index.analysis.analyzer.default_search.tokenizer: custom_bigram_tokenizer
index.analysis.analyzer.default_search.filter.0: lowercase

という定義になっています。このindex.analysis.analyzer.default_searchという設定は、検索時のみに使われるアナライザのデフォルトになります。こちらのトークナイザの設定はcustom_bigram_tokenizerで、これは

index.analysis.tokenizer.custom_bigram_tokenizer.type: nGram
index.analysis.tokenizer.custom_bigram_tokenizer.min_gram: 2
index.analysis.tokenizer.custom_bigram_tokenizer.max_gram: 2
index.analysis.tokenizer.custom_bigram_tokenizer.token_chars.0: letter
index.analysis.tokenizer.custom_bigram_tokenizer.token_chars.1: digit

となっており、2-gramで分解する設定です。こんにちはの例ですと

こん, んに, にち, ちは

という分解を行います。 で、なんでインデックス時と検索時のアナライザを別々に定義しているのかというと、1文字による検索でも何らかの検索結果を返したいと考えて設計したからです。

2-gramのみでインデックスしてしまうと、1文字による検索に一切マッチしません。 一方、検索時は2-gramのみをおこなっていますが、このアナライザに1文字の検索クエリをなげると、

# 以下はアナライザの動作確認をおこなうリクエスト
$ curl -XGET 'http://localhost:9200/blog/_analyze?analyzer=default_search&pretty=true' -d 'a'
{
  "tokens" : [ ]
}

# 検索
$ curl -XGET http://localhost:9200/blog/article/_search?pretty=true -d '{"query": {"match":{"_all":"a"}}}'
{
  "took" : 10,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : null,
    "hits" : [ ]
  }

のように、トークンが空になってしまい、そのままですとやはり検索に引っかかりません。 そこで一文字の時は、検索にアナライザを利用しないようにqueryをmatchからtermに変更して、以下のようなリクエストをなげるようにしました。

$ curl -XGET http://localhost:9200/blog/article/_search?pretty=true -d '{"query": {"term":{"_all":"a"}}}'

これで一文字のときも検索に引っかかるようになります。

マッピング

今回はまず導入ということで、フィールドに対してマッピングは行いませんでした。 マッピングは個々のフィールドに詳細な設定ができる、RDBMSでいうところのスキーマ定義に当たります。 マッピングを使えば特定のフィールド(たとえばブログのタイトル部分だけ)に特定のアナライザを適用したりとか、もっと高度で効率的な検索もできると思います。 しかし上記のデフォルトアナライザの設定だけでも、ドキュメントのテキスト部分全体に対してNgram検索がかけられて、いい感じの検索結果を得ることができています。

ElasticsearchでCentOS上にNgram全文検索サーバを構築する - (その1)インストールと基本のデータ操作

ここしばらくオープンソース全文検索エンジンElasticsearchを調べてました。

今回はNgramによる検索ができるように設定したので、その時のことをインストール方法から書きます。 どうにも同じ全文検索エンジンであるApache Solrに比べて新しいせいか、ネットの情報が少ないと感じたのと、検索エンジンをまじめに導入したのが初めてだったので、結構大変でした。 なお、この記事は自分用の備忘録をかねているので、いろいろ長くなりそうです。 よって何回かにわけて書く予定です。

Elasticsearchの概要

  • 全文検索エンジン全文検索機能をもつデータベース)
  • データ構造はJSON。スキーマレス。(MongoDBに似ている)
  • Javaで実装されている。内部にLuceneを使用している。(solrに似ている)
  • foursquare、Githubなどでの利用実績。
  • HTTPのREST APIがデータ操作のインターフェース。
  • AWSとは何にも関係ない。

買って参考にした書籍

ElasticSearch Server(Kindle版)

ちょっと情報古いですけど情報は網羅されているし、アーキテクチャの解説もあるのでかなり参考になりました。 あとは、公式サイトのドキュメントを見ながら作業しました。

やったこと

CentOS6をプラットフォームとした自前検索サーバの構築。 検索サーバはシンプルに一台のみ。分散環境やレプリケーションはやってないです。

インストールと起動

ElasticsearchはJavaによる実装なのでyumでまずjavaを入れます。

$ yum install java-1.7.0-openjdk

その後公式サイトからRPMをダウンロードしてインストール。

$ rpm -ivh elasticsearch-0.90.7.noarch.rpm

起動

$ /etc/init.d/elasticsearch start

ポート9200をListenしてデーモンが起動します。インストールはこれだけです。

なおディレクトリ構造は以下のようになっています。

  • /etc/elasticsearch/:設定ファイル
  • /var/lib/elasticsearch/:データディレクトリ
  • /usr/share/elasticsearch/bin/:実行ファイル
  • /usr/share/elasticsearch/lib/:ライブラリ(Javaなのでjarがある)

基本の論理構成

Elasticsearchのデータは以下のような構成要素からなります。

  • インデックス

    RDBMSの「データベース」に相当する要素。

  • タイプ

    RDBMSの「テーブル」に相当する要素。

  • ドキュメント

    RDBMSの「レコード」に相当する要素。 さらにドキュメントは複数の「フィールド」からなっていて、「フィールド」はRDBMSの「カラム」に相当します。 ドキュメントのフィールドは固定の構造である必要はなく、スキーマレスな構成にできます。 ドキュメントはJSONで構造化されたデータとして保存されます。

基本のデータ操作

データの操作はHTTPのREST APIによって行います。アクセスする先のURLは

http://localhost:9200/{インデックス}/{タイプ}/{ドキュメントのid} 

が基本の構造。インデックスやタイプはデータが最初に登録されたときに自動的に(動的に定義されるスキーマをともなって)構築されます。

ドキュメントの入力

PUTメソッドで入力します。

$ curl -XPUT http://localhost:9200/blog/article/1 -d '{"title": "記事のタイトル", "content": "本文テキスト"}'

pretty=trueをつけるとレスポンスが読みやすくなります。

$ curl -XPUT http://localhost:9200/blog/article/1?pretty=true -d '{"title": "記事のタイトル", "content": "本文テキスト"}'

POSTメソッドを使うとドキュメントIDを指定しない場合自動でIDが振られます。

$ curl -XPOST http://localhost:9200/blog/article/?pretty=true -d '{"title": "記事のタイトル", "content": "本文テキスト"}'

ドキュメントの検索

GETメソッド、id指定で取得します。

$ curl -XGET http://localhost:9200/blog/article/1?pretty=true

検索クエリは以下のような感じに。

$ curl -XGET http://localhost:9200/blog/article/_search?pretty=true -d '{"query": {"match":{"title":"検索文字ほげほげ"}}}'

※この時点ではアナライザ(次回以降に説明予定)が指定されていないので、デフォルトの検索アルゴリズムが適用されます。

ドキュメントの更新

データを上書き。

$ curl -XPOST http://localhost:9200/blog/article/1?pretty=true -d '{"title": "更新するタイトル", "content": "更新する本文"}'

一部のみ変更することもできます。

$ curl -XPOST http://localhost:9200/blog/article/1/_update?pretty=true -d '{"script": "ctx._source.content = \"更新する本文\""}'

ドキュメントの削除

DELETEメソッド、ドキュメントのid指定して削除。

$ curl -XDELETE http://localhost:9200/blog/article/1?pretty=true

タイプの削除。

$ curl -XDELETE http://localhost:9200/blog/article?pretty=true

インデックスの削除。

$ curl -XDELETE http://localhost:9200/blog?pretty=true

まとめ

インストールと基本操作は以上です。 ここまでで、ElasticsearchはいわゆるKVSのようなデータベースとして振る舞えることがわかります。 この後アナライザの定義を行い、ドキュメントにたいしてNgram全文検索できるようにしていきます。

そんなわけで次回に続く。。。

TravisCIでSSHクライアントのテストをする。

AltaxというPHPで並列SSHするデプロイツールを作っているのですが、 これのSSH接続部分のテストは当然SSHサーバが必要で、そのへんをTravisでどーやるのかわからず、ずっと悩んでいました。

で、調べていたら、

https://github.com/libgit2/libgit2/pull/1774

が検索に引っかかって、これを見ながらやってみたらうまくできたので、メモしておきます。

やり方

以下のようなシェルスクリプトを用意します。

setup_ssh_server.sh

#!/bin/sh 

sudo apt-get update -qq
sudo apt-get install -qq libssh2-1-dev openssh-client openssh-server

sudo start ssh

ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" -q
cat ~/.ssh/id_rsa.pub >>~/.ssh/authorized_keys
ssh-keyscan -t rsa localhost >>~/.ssh/known_hosts

export SSH_PRIVATE_KEY="$HOME/.ssh/id_rsa"
export SSH_PUBLIC_KEY="$HOME/.ssh/id_rsa.pub"

apt-getでSSHサーバ入れて起動して、ssh-keygenで鍵を作っているわけです。 あとはこれを.travis.ymlでbefore_scriptとかに設定してテスト前に実行するようにすれば、 SSHサーバがローカルホストで起動するので、SSH接続のテストができるようになります。

.travis.yml

language: php

php:
  - 5.3
  - 5.4
  - 5.5

before_script:
  - sh setup_ssh_server.sh

script:
  - php vendor/bin/phpunit

ヽ(=´▽`=)ノ

JenkinsをCentOSにインストールしたときのメモ

f:id:kohkimakimoto:20131120194039p:plain

Githubで公開しているプロジェクトのCIにはTravisが使えて便利なのですが、 仕事で開発しているWebアプリとかは公開するわけには行かなかったりするので、Travisは使えません。

そんなわけで、仕事でもCIの環境が欲しくなったので、今更ながらjenkinsをインストールしてみましたので、メモを残しておきます。

目的

PHPのWebアプリのユニットテスト

環境

ローカルのVirtualBox上に構成したCentOS6。

Jenkinsのインストール

Javaが必要なので先にyumとかで入れておきます

$ yum install java-1.7.0-openjdk

http://pkg.jenkins-ci.org/redhat/

redhat,centos用のRPMがあるのでそれをダウンロードしてインストールします。

$ rpm -ivh jenkins-1.540-1.1.noarch.rpm

実際はchefのレシピを用意してインストールしているので以下のようなrecipeを書いて実行しています。

jenkins/attributes/default.rb

default['jenkins']['rpm'] = "jenkins-1.540-1.1.noarch.rpm"
default['jenkins']['rpm_url'] = "http://pkg.jenkins-ci.org/redhat/jenkins-1.540-1.1.noarch.rpm"

jenkins/recipes/default.rb

remote_file '/tmp/' + node['jenkins']['rpm'] do
  source node['jenkins']['rpm_url']
  owner "root"
  group "root"
  mode "0755"
  not_if "test -e " + '/tmp/' + node['jenkins']['rpm']
end

package "jenkins" do
  action :install
  source '/tmp/' + node['jenkins']['rpm']
  provider Chef::Provider::Package::Rpm
  not_if "rpm -q jenkins"
end

service "jenkins" do
  action [:enable, :start]
end

インストールすると

/usr/lib/jenkins/jenkins.war

にjenkins本体のwarが

/var/lib/jenkins/

にデータディレクトリが作成されます。

WebUIにアクセス

http://xx.xx.xx.xx:8080/

仮想サーバの8080ポートにブラウザでアクセスするとjenkinsの画面が表示されます。

設定

ローカル環境なので、セキュリティとか気にしない。というわけで特に環境設定なし。デフォルトのまま。

ジョブ

ジョブはjenkinsに実行させたい処理を定義します。今回はリポジトリからPHPアプリのソースをとってきて、PHPUnitでテストを実行させたいと思います。まず、

  • 左メニューの[新規ジョブ作成]→[ジョブ名]に適当な名前をつけて[フリースタイル・プロジェクトのビルド]を選択して[OK]。

その後、最低限の設定だけします。

  • [ソースコード管理]は使っているVCSを選択します。お仕事ではsvnを使っているので[Subversion]。[リポジトリURL]を入力します。

  • [ビルド・トリガ]は[SCMをポーリング]を選択。スケジュールには1分ごとにチェックさせたいので以下のようにしました。

      */1 * * * *
    
  • [ビルド]の箇所では[ビルド手順の追加]→[シェルの実行]を選んで、svnからソースを落としてきたあとに行う実際のタスクを書きます。私の場合は以下のようになりました。

      /usr/local/bin/composer install --no-interaction
      php vendor/bin/phpunit -c phpunit-ci.xml.dist
    

なんでかJenkinsからの実行だと/usr/local/bin/にパスが通っていないので、グローバルインストールしてあるcomposerをフルパスで実行してます。 composer installのあとにphpunitを実行していますが、jenkins用のテストの設定(カバレッジをとるなど、後述します)を使いたいので-cオプションで専用のphpunitの設定ファイルを指定しています。

これで[保存]をクリックして完了。トップに戻って、時計アイコンをクリックして、試しに実行してみます。

カバレッジ

テストがうまくできたら、カバレッジもとりたくなりました。PHPカバレッジをとるには、Clover PHP pluginを使います。 左メニューの[Jenkinsの管理]→[プラグインの管理]から

  • Jenkins Clover PHP plugin

をインストール。Jenkinsを再起動。

ジョブの設定画面に行くと[ビルド後の処理の追加]に[Clover PHP カバレッジレポートを集計]という項目が増えているので、これをクリックして処理を追加します。

  • Clover XMLパス:reports/coverage/coverage.xml
  • Clover HTMLレポート ディレクトリ:reports/coverage

のように設定します。その後phpunit実行時に指定する設定ファイルphpunit-ci.xml.distに、以下のようなカバレッジを出力する設定を追加します。

<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" berbose="true" bootstrap="test/bootstrap.php">

  ...いろいろ設定

  <logging>
    <log type="coverage-clover" target="reports/coverage/coverage.xml"/>
    <log type="coverage-html"   target="reports/coverage" charset="UTF-8" yui="true" highlight="true" lowUpperBound="35" highLowerBound="70"/>
  </logging>
</phpunit>

以上でOK。テストとともにカバレッジを出力してくれるようになります。

終わりに

というわけで開発作業中、ローカルPCに開発環境用とCI用の2つのVMを常時起動させて作業するようになりました。 なんでもできることはローカルで、というのが最近の作業スタイルになっています。 基本一人で作業している身なので、サーバが外にある必要がないんですよね、あんまし。

あと、Jenkinsのジョブの設定とかもWebからやらないでchefでやりたいのですが、このへんは今後調べようかと思っています。

Composerのドキュメントを日本語訳してみてる話

先週末からComposerのドキュメントを個人的に日本語訳してみてます。

英語むずいいぃぃぃ~~~~~!

はい。英語が苦手なんです。キライなんです。使えるようになりたくはあるのだけど、本腰入れる気合もなくて、なんというかだらだら勉強してる。 とりあえず、通勤時間に電車で単語帳見たり、iPhoneに英語教材のオーディオブック入れて流し聞いたりしてます。 で、そんな英語学習のひとつとして、ちょっとプログラミングに関連させてドキュメントの和訳をやってみてます。

正直、続くかわからんけど。

ひとまず、IntroductionとBasic Usageのとこだけ和訳してみたので、そのことをブログに書いてみました。

なお、一応補足しておくと、ComposerはPHPの依存管理ツールです。RubyのBundlerみたいなやつですね。

Grunt

ところで英語の話とは別に、最近買ったWebDBPressにGruntの話があって、 これをちょっと使ってみたいのもあって、HTMLのビルド周りをGruntで自動化してみました。

GruntはJavaScriptのタスクランナーとのこと。要はmakeのJavaScript版みたいな感じだと思う。 特徴的なのがプラグインでタスクを簡単に追加、拡張できて、Webフロントエンド開発に便利なタスクが最初からいっぱい用意されていること。 今回使ったのは以下のプラグイン

  • grunt-contrib-watch: 作業中のファイル更新を監視して、タスクを自動実行させる。
  • grunt-contrib-connect: 作業中の確認用HTTPサーバ。livereloadサーバも立ててブラウザの自動再読み込みもできる。
  • grunt-contrib-cssmin: CSSのミニファイ。
  • grunt-markdown: MarkdownをHTMLに変換。
  • grunt-contrib-copy: ファイルのコピー。
  • grunt-contrib-clean: ファイルの削除。
  • grunt-contrib-uglify: JavaScriptのミニファイ。

ちょっとした静的サイトジェネレータのようなものが構築できてしまって、大変便利なのでした。( ´∀`)

TravisCIでGithubPagesを自動更新

ついでにGithubのリポジトリにソース一式Pushしたら、自動でGithubPagesをジェネレートしたサイトで更新するようにしてみました。以下が参考サイト。

参考サイトでやってることほとんどそのまんまです。 travisでgruntを実行しサイトをジェネレートして、生成物をgh-pagesブランチにコミット、Pushする。

こりゃ便利だわ~( ´∀`)。

後になって気づいたこと

getcomposer.org_doc_jpというリポジトリ名だけどgetcomposer.org_doc_jaのほうが良かったんじゃないかと。 でもtravisの設定とかやり直したくないので、このままにします。。。

あと、えいごガンバル。