オライリーの本をGoogle Playで400円前後で購入
O'Reillyの一部の書籍はGoogle Playでアプリとしても販売されています。
O'Reilly Media - Google Play の Android アプリ
JavaScript: The Definitive Guildeが399円。安い。
Part IIIの Core JavaScript Referenceもついてきます。
アプリはAldikoというeBookリーダーにバンドルされた形でインストールされます。ただ、このリーダーがスワイプしようとするとテキストを選択してしまったりと使い勝手がイマイチです(単体でインストールしたAldikoはそんなことないので、バンドル版のバージョンの問題かもしれません)。
しかしありがたいことに、メニューからePubをエクスポートすることができます。
ただこのePubに少々問題があるようで、例えばGoogle Play Booksにアップロードするとエラーとなってしまいました。EPUB Validator (beta)で調べてみたところ、フォントが同梱されていないようです。
ePubをunzipして、OEBPS/content.opfを開いて、
<item id="epub.embedded.font.1" href="LiberationMono-Bold.otf" media-type="font/opentype"/> <item id="epub.embedded.font.2" href="LiberationMono-BoldItalic.otf" media-type="font/opentype"/> <item id="epub.embedded.font.3" href="LiberationMono-Italic.otf" media-type="font/opentype"/> <item id="epub.embedded.font.4" href="LiberationMono.otf" media-type="font/opentype"/> <item id="epub.embedded.font.5" href="LiberationSerif.otf" media-type="font/opentype"/>
この辺をざっくり消してしまうか、あるいは他のフォントに置き換えてしまうとよさそうです。置き換える場合は、フォントファイルをOEBPSフォルダに追加し、OEBPS/core.cssファイルを適当に直します。
蛇足ですがこの本、Google Play Booksで買うと4110円です。
Brackets Sprint 36 & 37
Adobe BracketsのSprint 36について書こうと思っている間にSprint 37も出ました。
注目はPreferences。プロジェクトのルートフォルダの.brackets.json
というファイルで、jslintのオプションやらインデントの幅やらを設定できるようになりました。まーテキストエディタならインデント幅くらい設定できて当たり前だろという感じもしますが。まだ改行コードは設定できないし。
How to Use Brackets · adobe/brackets Wiki
また、マルチカーソルモードの開発が始まったようです。 BracketsチームはTrelloを使っているので、のぞいてみると夢が広がります。
"Minimal .editorconfig support"ほしいなあ。
1つのSubjectに集中せよ - phpspecのコンセプト
1つ前のエントリで「知らないうちに」と書きましたが、実際は2012年からphpspec2という名前で存在していて、途中でphpspecのリポジトリに統合されたようです。
commit f6b8f26c563cfd07af28a7d4bdcf41a1aee33556 Author: Marcello Duarte <marcello.duarte@gmail.com> Date: Mon Apr 29 16:49:28 2013 +0100 Initial commit commit 5e277377ae015f9fc226864edfbbb7dc47efea27 Author: Marcello Duarte <marcello.duarte@gmail.com> Date: Mon Apr 29 16:37:12 2013 +0100 Wipe phpspec 1.x
phpspec2と呼ばれていたころのブログ記事で、コンセプトがわかりやすく紹介されていました。サンプルコードは今のAPIとはちょっと違います。
everzet's blog • phpspec2: SUS and collaborators
翻訳する英語力は無いので雰囲気だけ。
- SUSとは、Subject Under Specificationのこと。1つのSpecificationでは1つのSUSの振る舞いについて記述することが超重要。複数に集中しようとするのは自殺行為だ
- Specificationとは、これから実装しようとしているオブジェクトがどのように振る舞うべきかの例(example)のリスト
- phpspec2は、1つのSpecificationに1つのSUTというスタイルを強制する。
$this
はSUTをProphet
という特殊なオブジェクトでラップしたもの。SUTのProxyをしつつ、Matcherで期待する振る舞いについて記述できたり、未実装のメソッドを呼び出すとfatal errorの代わりに色々(メソッドを生成するか聞いてきたりとか)してくれる。 - なのでSpecification内で
$this
の振る舞いの例を書いていけばよい - とはいえ、普通はSUSと協調する他のオブジェクト(collaborators)があるよね。そいつらは全部Mockして、実際の振る舞いについて考えるのは後回しにしよう。それがMockists approachだ
- SpecBDDは言っている — 1つのオブジェクトに集中せよ。その唯一の方法がMockである — と
Mockists approachのことをLondonTDDとかLondon-styleとかいうらしいですよ。使ってみたいですね。TDD Bootcampとかで隣の人に「キミってLondon-style?」って。
Mockの書き方をPHPUnitと比較してみましょう。コードはPHPUnitのドキュメントのものです
<?php class SubjectTest extends PHPUnit_Framework_TestCase { public function testObserversAreUpdated() { $observer = $this->getMock('Observer', array('update')); $observer->expects($this->once()) ->method('update') ->with($this->equalTo('something')); $subject = new Subject('My subject'); $subject->attach($observer); $subject->doSomething(); } }
phpspecだとこうなります(説明面倒なのでコンストラクタの引数は省略してますが)
<?php namespace spec; use PhpSpec\ObjectBehavior; class SubjectSpec extends ObjectBehavior { function it_updates_observers(\Observer $observer) { $observer->update('something')->shouldBeCalledTimes(1); $this->attach($observer); $this->doSomething(); } }
シンプルですね。SubjectSpecの中では$this
はSubjectのインスタンスのラッパーになるという決まりになっています。また引数があればphpspecが自動的にMockを生成してくれます。
但しPASSするにはObserver#update()の空の実装かインターフェースが必要です。逆に言えば、PASSしたときには、Collaboratorsに何が要求されるかはわかっているので、次はCollaboratorsのどれかをSUSに選んでSpecificationを書きながら空の実装を埋めていけばいいわけです。
最後に注意事項
- 正直phpspecのドキュメントはイマイチです。phpspec/prophecyは見ておいた方がいいです。他にもいじってみて色々わかったことがあるのでまた書くかも. まー上のコードみたいに常に簡単にかけるわけでもないです
- 1つのやり方を強制するので、0から何かを作るのにはいいかもしれませんが、既存のレガシーコードと戦うのに向いているかどうかは疑問です
知らないうちにphpspecがすごいことになっていた件
昔あったphpspecが進化したものなのかそれとも別のものなのかは知りませんが。
すごい。軽くキモい。17分の動画です。
まず、いきなり「MovieCollectionにMovieをadd()するとcountが1になること」というのスペックを書きます。MovieCollectionクラスもMovieクラスもまだ作ってません。
phpspec run
を実行すると当然失敗して、「MovieCollectionクラスが無いけど作ってほしい?」と尋ねてきます。Y
なら空のMovieCollectionクラスが作られます。
関係ないけどこういうスクリーンキャストを作ったりライブコーディングする人は、ターミナルの色の設定したほうがいいですね。GitHubにいろいろカラーテーマがあるので。
その後いろいろ説明を省きますが、今度は「MovieCollection::add()メソッドが無いけど作る?」と言ってきたりします。ローカライズすると色々楽しめそうです(謎)。
また、引数で使っているMovieクラスの方は、空の実装だけあればphpspecが勝手にスタブを生成してくれる(newする必要すらない)というのも面白いところです。type hintを本来とは全然違う目的で使うというナウいPHPerに人気の手法ですね。
さらに進んで、MovieCollection#markAllAsWatched()メソッドのスペックを書くところ。
「ここではMovieのテストをしてるんじゃなく、MovieCollectionのテストをしているんだ」と、markAllAsWatched()がMovieの状態を変更することではなく、Movie#watch()メソッドが呼び出されることをモックを使ってテストしています。
<?php class MovieCollectionSpec extends ObjectBehavior { ... function it_can_mark_all_movies_as_watched(Movie $movie1, Movie $movie2) { $movie1->watch()->shouldBeCalled(); $movie2->watch()->shouldBeCalled(); $this->add([$movie1, $movie2]); $this->markAllAsWatched(); }
簡潔ですね。Movieクラスに空のwatch()メソッドを作り、MovieCollection#markAllAsWatched()を実装することでこのテストは成功します。
スペックを書く対象は1つだけ、コラボレーターは全部Fake Object、というスタイルで書きやすさをつきつめてみたという感じです。
スタブやモックの使い方については、prophecyを見るのがよさそうです。
あと、PhpStormのリファクタリング機能の強力さもこの動画の見所です。
Pimple 2.0がリリースされたのでPimpleについて復習してみる
ぶっちゃけ出るなんて思ってませんでしたが、Pimple 2.0がリリースされたので、1.xの復習と2.0での変更について調べてみます。
Pimple - A simple PHP Dependency Injection Container
Pimple(1.x)の基本
DIコンテナとは何か、という説明をはぶいてPimpleの動作を単に説明すれば、
- コンテナ(Pimpleのインスタンス)は連想配列のように見えて、そこに値や無名関数をセットできる
- 値を取り出す時、セットされたものが値であれば、単にその値が返却される
- 値を取り出す時、セットされたものが無名関数であれば、その無名関数を呼び出した戻り値が返却される。この時、無名関数の第一引数にはコンテナそのものが渡される
というこれだけのものです。
Inversion of Control コンテナと Dependency Injection パターンの例でいえば
<?php $c = new \Pimple(); $c['filename'] = 'movies1.txt'; $c['movie_finder'] = function($c) { return new ColonMovieFinder($c['filename']); }; $c['movie_lister'] = function($c) { return new MovieLister($c['movie_finder']); };
こんな感じで依存関係を定義します。どこからみてもPHPのコードに見えますがこれは設定ファイルみたいなものだと考えてください。ここまでの段階ではColonMovieFinderのインスタンスもMovieLiserのインスタンスも作成されていません。
使う側は、
<?php $lister = $c['movie_lister'];
としてやれば、無名関数が2つ呼ばれてガラガラポンとMovieListerのインスタンスを取得できるという寸法です。
shareメソッド(1.x)
上の例では、$c['movie_lister']
が参照されるたびに無名関数が呼ばれ、新しいMovieListerのインスタンスが返却されていました。そうではなくSingleton風に毎回同じインスタンスを返却してほしい場合は、
$c['movie_lister'] = $c->share(function($c) {
return new MovieLister($c['movie_finder']);
});
と書く必要があります。
extendメソッド(1.x)
サービスを定義したところを直接変更できない。でもサービスに何かしら手を加えたい。でもまだインスタンスは作成したくない、みたいなときにextendメソッドを使います。実際どういうことなのか最初はピンとこなかったのですが、GitlistというGitリポジトリビュワーにfabpot(Pimple、Silexの作者)が投げたPullRequestをみてなるほどなと思いました。
元のコードは、
// Register Git and Twig service providersclass_path $app->register(new Silex\Provider\TwigServiceProvider(), array( 'twig.path' => __DIR__.'/views', 'twig.options' => array('cache' => __DIR__.'/cache'), ));
この辺はSilexの決まり事なのですが、ここで$app['twig']
を参照するとTwig_Environment
のインスタンスを作成して色々設定してくれることになってます。で、このインスタンスに対して機能を追加したいので
、
// Add the md5() function to Twig scope
$app['twig']->addFilter('md5', new Twig_Filter_Function('md5'));
と書いていたのですが、これだと使うかどうかにかかわらずTwig_Environment
のインスタンスが作成されてしまいます。もしTwig_Environment
のインスタンスを作成する部分を自分で書いていたのであれば、
$app['twig'] = $app->share(function () { $twig = new Twig_Environment(); $twig->addFilter('md5', new Twig_Filter_Function('md5')); return $twig; });
と書けていたわけです。PRではこれを、
$app['twig'] = $app->share($app->extend('twig', function($twig, $app) { // Add the md5() function to Twig scope $twig->addFilter('md5', new Twig_Filter_Function('md5')); return $twig; }));
と変更していました。SilexのServiceProvierを使う場合は覚えておきたいパターンですね。
2.0での変更点
shareがデフォルトに
2.0では、以前のshare()の動作がデフォルトになりました。すなわちセットされたものが無名関数であれば、常にキャッシュされた値を返します。またshareというメソッドは無くなりました。
別のインスタンスを返してほしい場合は、factoryメソッドを使います。
$c['movie_lister'] = $c->factory(function($c) {
return new MovieLister($c['movie_finder']);
});
extendの変更
1.xでは、extendメソッドの戻り値をコンテナにアサインしなおしていましたが、その必要がなくなりました
// 1.x $c['movie_finder'] = $c->extend('movie_finder', function($movie_finder, $c) { $movie_finder->setFilename($c['filename']); return $movie_finder; }); // 2.0 $c->extend('movie_finder', function($movie_finder, $c) { $movie_finder->setFilename($c['filename']); return $movie_finder; });
2013年はこんな年でした
- お仕事的にはほぼPHP、ちょっとJavaScript
- Ruby札幌、Sapporo.js、CSS Nite、SaCSSあたりに参加しました
- Kindle PaperWhiteを買いました。辞書を引けるのが便利
- 技術系ポッドキャストrebuild.fm。面白いです
- フロントエンドのエディタにBracketsを使うようになりました
- 万年筆kakunoを買いました
- 2013年はこんな年でした - データベース関連 - iakioの日記
発表資料
つぶやき
「Xcode,Gitくらい使えるだろ」vs「PhotoShopくらい使えるだろ」実際全部やろうとすると結構大変だよね
— ISHIDA Akio (@iakio) 2013, 9月 9
昔のアプリケーションって、デザインなんてたいして気にしていなくて、プログラマーが適当に灰色の画面にポチポチボタンを並べていたわけです。で、今、Webの世界ではデザインはとても重要視されていて、デザインと実装の橋渡しをするマークアップエンジニアというお仕事があります。
じゃあネイティブアプリケーションはどうなんだろう。特にAndroidやiOS。それぞれのデザインガイドを知っていて、ブワッと出てきたりズリッと動かしたりみたいな動きを把握していて、OSのバージョンによってデザインがどう違うかとかも知っていてみたいな。デザインと実装の橋渡しを誰がするんだろうなあ。