読者です 読者をやめる 読者になる 読者になる

bonar note

京都のエンジニア bonar の技術的なことや技術的でない日常のブログです。

git における stage, commit, branch

git は難しいと良く言われます。僕もそう思います。個人的には Pro Git Pro Git 日本語版電子書籍公開サイト の説明が最高に分かり易いのでとてもオススメです。

コマンド体系であったりトラブルシューティングであったり色々な視点があると思うのですが、どちらかというと git 特有の世界観が掴めるとぐっと理解が進むような部分があるなと感じていました。初歩的な内容ではありますが、特に、stage, commit, branch に関して「新しく git に入ってきた人が、これを知っておくとスムーズ」と思った物を書いてみます。
(変な所があったらツッコミをお願いします)

stage と local repository

svn 等と同じく git でも多くの場合チーム全員で共有する中央レポジトリがあります。ただ、そこに修正を送り込む前に stage と local repository があるというのが git の特徴的な所です。git に触れ始めた頃はわけもわからず git commit -a していたのですが、stage と local repository をうまく使う事でコミットを整える事が出来るようになります。

以下は、origin という remtote repository が登録された状態で master ブランチを編集しているという想定の図です。

f:id:bonar:20140826002818p:plain

stage は次にコミットするものを一時的にのせておく発射台です。手元(Local change)でファイルを編集し、git add でファイルを stage に追加します。やっぱりやめたという時は git reset で stage から降ろします。修正の一時的な置き場である stage がある事で、修正を意味のある単位に纏める事が出来るのがとても便利です。コミットログも書き易くなります(「今日の作業分」よさらば)。

ちなみに stage, local repository 間の差分は以下のコマンドで確認します。

git diff # 手元の修正と stage の差分
git diff --cached # stage と local repository の差分 (= --staged)

git commit すると stage にある内容が local repository にコミットされます。まだこの時点では全ては自分のマシンの中の出来事なので好きに修正する事が出来ます。コミットした内容を取り消したい場合は戻したい地点のコミットハッシュ(一つ前のコミット)を指定して、

git checkout master
git reset --soft {commit hash}

で local repository の master の状態が指定した地点まで戻ります。--soft はローカルのファイルの状態は変えません(git status で差分が出る)が、--hard だとローカルのファイルもその地点の状態に更新します(変更が失われる)。

この後 git push origin master すると、local repository 内の master ブランチが remote repository の master に送信されます。svn だと local の修正からいきなり remote repository に行く感じなので大分違いますね。

git fetch すると remote repository の内容が local repository の origin/master(repository名/ブランチ名)ブランチに落ちてきます。いきなり local repository の master ブランチに入らないところが特徴的です。この状態で

git diff master..origin/master

することで local/remote repository の master の差を確認する事が出来ます。これを確認した上で

git checkout master
git merge origin/master

すると remote repository の master の内容を local repository に取り込む事が出来ます。この fetch & merge を一度に行うのが git pull です。

コマンドは少しややこしいのですが、どちらかというと上記のような登場人物がいるという事と、その位置関係をイメージとして知っておく事が重要なのかなと思います。

コミットはスナップッショット

特に svn から git に来ると、「svn は revision というスナップショットの集合で歴史が出来るけど、git はコミットという差分の集合で歴史が出来ている」という理解に至りがちな気がしますが、これは正確な理解では無いと思います。git のコミットもスナップショットだからです。

実際にコミットオブジェクトの中身を見るのが分かり易いです。例えば以下のように、README.txt に line1, line2, line3 というテキストを一行ずつコミットしていくようなシチュエーションを考えます。

$ mkdir gitsample
$ cd gitsample
$ git init
Initialized empty Git repository in /Users/bonar/git/gitsample/.git/
$ echo "line 1" >> README.txt; git add README.txt; git commit -m "line 1"
[master (root-commit) c5d5c04] line 1
 1 file changed, 1 insertion(+)
 create mode 100644 README.txt
$ echo "line 2" >> README.txt; git add README.txt; git commit -m "line 2"
[master 8a61b67] line 2
 1 file changed, 1 insertion(+)
$ echo "line 3" >> README.txt; git add README.txt; git commit -m "line 3"
[master 6c946b8] line 3
 1 file changed, 1 insertion(+)
$ git log
commit 6c946b8e1bc1f988b7d795517be3cb62aa963bdb
Author: bonar <bonamonchy@gmail.com>
Date:   Wed Sep 3 22:39:58 2014 +0900

    line 3

commit 8a61b6756863c292d94791e87b8765fd788d18c8
Author: bonar <bonamonchy@gmail.com>
Date:   Wed Sep 3 22:39:51 2014 +0900

    line 2

commit c5d5c04376593fdb76754996d0322dd0005cd797
Author: bonar <bonamonchy@gmail.com>
Date:   Wed Sep 3 22:39:42 2014 +0900

    line 1

例えば line3 のコミットオブジェクトは具体的には .git/objects/6c/946b8e1bc1f988b7d795517be3cb62aa963bdb に保存されています。コミットオブジェクトの中身を詳しく見るには、git cat-file -p でコミットハッシュを指定します。

$ git cat-file -p 6c946b8e1bc1f988b7d795517be3cb62aa963bdb
tree bf3461315080f6ca4e73ab1eb42f3389415758c6
parent 8a61b6756863c292d94791e87b8765fd788d18c8
author bonar <bonamonchy@gmail.com> 1409751598 +0900
committer bonar <bonamonchy@gmail.com> 1409751598 +0900

line 3

tree, parent と、コミットのメタ情報(author, comment)でコミットが構成されていることがわかります。tree というのはその時点でのファイルの一覧とそのハッシュ値が記録されたもので、まさにスナップショットです。この中身も git cat-file で確認する事が出来ます。

$ git cat-file -p bf3461315080f6ca4e73ab1eb42f3389415758c6
100644 blob a92d664bc20a04b1621b1fc893d1196b41182fdf	README.txt
$ git cat-file -p a92d664bc20a04b1621b1fc893d1196b41182fdf
line 1
line 2
line 3

ファイルの中身そのものもハッシュ値と対応する形で blob として .git/object 以下に格納されています。

重要なのは、コミットオブジェクトが「どのファイルがどのように変更されたか」を直接的に記録している訳ではないという点です。例えば git show するとこのコミットでの差分が出ますが、

$ git show 6c946b8e1bc1f988b7d795517be3cb62aa963bdb
commit 6c946b8e1bc1f988b7d795517be3cb62aa963bdb
Author: bonar <bonamonchy@gmail.com>
Date:   Wed Sep 3 22:39:58 2014 +0900

    line 3

diff --git a/README.txt b/README.txt
index 7bba8c8..a92d664 100644
--- a/README.txt
+++ b/README.txt
@@ -1,2 +1,3 @@
 line 1
 line 2
+line 3

これは parent のコミットオブジェクトが持つ tree との比較によって得られます。つまり上記は line 3 の tree と line 2 の tree の比較結果です。この事は line 3 のコミットと同じ tree を持ち、且つ parent が line 1 のコミットオブジェクトを作ってみると分かります。新しいコミットオブジェクトは git commit-tree で作成出来ます。

$ git commit-tree -p c5d5c04376593fdb76754996d0322dd0005cd797 -m "line 3'" bf3461315080f6ca4e73ab1eb42f3389415758c6
446e26265ba55c115dce2f62407a481e44010968
$ git cat-file -p 446e26265ba55c115dce2f62407a481e44010968
tree bf3461315080f6ca4e73ab1eb42f3389415758c6
parent c5d5c04376593fdb76754996d0322dd0005cd797
author bonar <bonamonchy@gmail.com> 1409752954 +0900
committer bonar <bonamonchy@gmail.com> 1409752954 +0900

line 3'

新しく作ったこのコミットを git show すると、同じ tree を持っているにも関わらず line1 と line3 の差分が出ます。

$ git show 446e26265ba55c115dce2f62407a481e44010968
commit 446e26265ba55c115dce2f62407a481e44010968
Author: bonar <bonamonchy@gmail.com>
Date:   Wed Sep 3 23:02:34 2014 +0900

    line 3'

diff --git a/README.txt b/README.txt
index 89b24ec..a92d664 100644
--- a/README.txt
+++ b/README.txt
@@ -1 +1,3 @@
 line 1
+line 2
+line 3

「コミットの差分」というのが parent コミットとの関係で決まる相対的な物であるという事が分かります。これは git のコミットがその時点でのファイル全体のスナップショットであることを表していて、「コミット」という言葉の語幹からはイメージ出来ないものかもしれません。この認識は merge を行う際にとても重要になります。

ブランチはコミットを指すポインタ

ブランチは単に特定のコミットハッシュに名前をつけた物でしかなく、特定のコミット郡に名前をつけてグルーピングしておく入れ物ではありません。

例えば以下のようなブランチ群を考えます。
f:id:bonar:20140904213148p:plain

1 のコミットの後に branch A が切られ、4, 5, 6 と3つのコミットをした後に branch B が切られ、7, 8 というコミットが行われた状態です。この状態において、branch A というのは 6 のコミットを指すポインタで、branch B は 8 のコミットを指すポインタです。

.git/refs/heads を見ると、ブランチの HEAD のコミットハッシュが書かれたファイルがあります。これがブランチの正体です。

$ ls -1 .git/refs/heads
branch_a
branch_b
master
$ cat .git/refs/heads/branch_b
9c15300bc1789e9f3ddbf4fc32f3965813879828

ここで branch B を master に merge しようとした場合、「branch B を checkout した後にこのブランチに対して行った修正である 7, 8 が master に入るのだろう」と思いがちです。しかし実際に起こる事は「branch B というポインタが指しているコミット(=8)の tree を master に merge する」になります。8 の時点でのスナップショットが master に merge されるわけなので、4, 5, 6 の修正も入る事になります(branch B の修正じゃないのに!)。

とても当たり前の事なのですが、「ブランチという箱に差分を入れている」という脳内イメージだと、上記のような勘違いに至りがちです(僕もよくします)。特に merge する際には「ブランチはコミットへのポインタであって、コミットはスナップショットである」という認識に立ち戻ると訳が分からなくなる事が少ないかなと思いました。

次号:「git rebase とは何なのか」に続く

ruby ブロック内からの return

例えば受け取った配列内を一つずつ見ていって偶数の場合のみ puts する、という処理をしようとして以下のようなコードを書いたとします。

def print_evens(nums)
  nums.each do |num|
    return if 1 == (num % 2)
    puts num
  end
end

print_evens((1..10).to_a)

each に与えられたブロックの最初の行で奇数の場合はブロックの処理を終え(次の num の実行に移り)、そうじゃない場合(偶数の場合)には puts num するという意図ですが、このコードを実行しても何も表示されません。

ブロック内の return で print_evens メソッドそのものを抜けてしまうからです。
意図した動きにするためには return を next に変える必要があります。

def print_evens(nums)
  nums.each do |num|
    next if 1 == (num % 2)
    puts num
  end
end

print_evens((1..10).to_a)
2
4
6
8
10

break にした場合には each のループのみを抜けて print_evens は抜けず、次の文に制御が移ります。

驚くほど当たり前の事を書いている感じなのですが、JavaScript のコードと行き来しているとこういうミスをしてしまいがちで、特に文法エラーになるわけでもないので分かりにくいバグとして潜伏しがちかなと思いました。

また、next が値を受け取れるという事は見逃されがちです。これはとても便利に使えて、例えば fizzbuzz を以下のように書けます。

def multiple?(a, b)
  !!(0 == (a % b))
end

def fizzbuzz(nums)
  nums.map do |num|
    next "fizzbuzz" if multiple?(num, 3) && multiple?(num, 5)
    next "fizz" if multiple?(num, 3)
    next "buzz" if multiple?(num, 5)
    next num
  end
end

puts fizzbuzz((1..20).to_a)

ブロック内で最後に評価される値を意図した物にしようとしてネストが深くなったり複雑化するよりは、next で早めに返す方が見通しがいい、という局面は結構ありそうですね。

PaceSlider - 片手でペース計算

ランニングをしていて、以下のように思う事はありませんか?

  • ハーフマラソンを1時間45分で走るには、どれくらいのペースで走ればいいんだろう
  • 6'30/km のペースで 100マイルのレースを走ったらどれくらいのタイムになるだろう
  • ゴールまであと 20km、制限時間が3時間 ということは、必要なペースはいくつだろう

なかなか厄介な計算です。こういう計算をしたい事が結構あるのですが、なかなか暗算出来るようにならないので、JavaScript で計算機を作りました。以下から使用可能です。

http://app.bonar.jp/

f:id:bonar:20131119213623p:plain

f:id:bonar:20131119213625p:plain

まず距離を選択して、スライダーを動かします。するとペースと時間が連動して変化します。
あとは自分が目指すペースやタイムまでスライドして行くだけです。キロメートルとマイルの両方に対応し、1km〜160km までの任意の距離を設定可能です。

スライダーを左右の端にくっつけると時間とともにペースが増減する、っていうのが工夫したポイントです。iPhone 5 でしか動作確認していないので、他の端末だと何かおかしいかもしれません。

ペース計算機は巷に色々ありますが、入力フォームが多かったり、少しずつずらして調節する、というのがやりにくい UI になっている事が多いです。ペースの計算は「速さ/時間/距離」の三項の関係性ですが、PaceSlider では「速さと時間をいじって距離を調節する」という部分を切り捨てて簡素化したという点が特徴です。僕のユースケースではそれは必要なかったからです。「自分が使えればいい」と考えると気楽ですね。

たったこれだけのものでも、UI 等を自分なりに考えて作るのは意外と時間がかかるものです。
が、逆に基本的な部分は良いパーツが既にあるのでだいぶ楽ですね。UI は boottrap を使ってますし、ファイルは S3 に置いています。
本当に楽ですね。良い時代です。

YAPC::Asia 2013 に参加してきました!

Perl と関係ない話題も多くて、色々な人と技術の同窓会みたいな とても楽しい2日間でした。

ベストスピーカーは yusukebe さん、myfinder さん、kazeburo さんでしたね。
yusukebe さんのは聴けなかったのですが、myfinder さんのテストを並列実行する話は恐らく色々な人にとって現実的な課題だし、具体的な内容だったので面白かったですね。しかも凄く良い声でした。

フルテストも50msで終わらせたい 〜 FreakOutの取り組み 〜 - YAPC::Asia Tokyo 2013

kazeburo さんの話は Monoceros の紹介に加えて、PSGI Server の選び方や実装方法に関して step by step で説明されていて、かなりイメージし易かったですね。「なんか出来るかも」という気がしてきて刺激されました。

PSGI/Plack・Monocerosで学ぶハイパフォーマンスWebアプリケーションサーバの作り方 - YAPC::Asia Tokyo 2013

あと印象に残ったトークといえば hiratara さんの型の話ですね。かなり楽しみに言ったのですが、正直まったく理解出来ず、久々に打ちのめされました。型システム入門を呼んで出直します。

Types and Perl Language - YAPC::Asia Tokyo 2013

型システム入門 −プログラミング言語と型の理論−

型システム入門 −プログラミング言語と型の理論−

  • 作者: Benjamin C. Pierce,住井英二郎,遠藤侑介,酒井政裕,今井敬吾,黒木裕介,今井宜洋,才川隆文,今井健男
  • 出版社/メーカー: オーム社
  • 発売日: 2013/03/26
  • メディア: 単行本(ソフトカバー)
  • クリック: 68回
  • この商品を含むブログ (8件) を見る

PerlRuby

rubyist との座談会企画がとても面白かったです。

YAPC::Asia Tokyo 2013 特別座談会 「Rubyの良いところ語ってください 〜そんなPerlで大丈夫か?〜」 - YAPC::Asia Tokyo 2013

結論としては「適材適所だよね」という事で、そうですよね、と感じました。webアプリのパフォーマンス全体で見れば言語自体の性能差は小さいし、言語そのものの生産性という話も 現在のコード資産や担当者の熟練度、採用コスト等の話になってしまうので客観的な評価になり辛い傾向があると思います。

RubyKaigi に行った時に特徴的だなと思ったのが、「みんなが良いデフォルトを使用している」感じです。rails/rspec/bundler/capistrano みたいなツールをみんなが使っていて、その辺りを知っている前提で話が進んでいて凄いなと思ったのを思い出しました。

Perl で良いコードを書くためには訓練された CPANソムリエになる必要があり、そこへ至る道がよく見えない、という辺りが個人的には難しいポイントなのかなと感じました。

モダンPerl入門 (CodeZine BOOKS)

モダンPerl入門 (CodeZine BOOKS)

Perl CPANモジュールガイド

Perl CPANモジュールガイド

一定レベルの Perl Hacker の間では「こういう時はこれだよね」というコンセンサスがあって、実際は問題ないのかもしれません。

再発見した Perl の良さ

「イケてる ruby」と「停滞する Perl」というコンテキストで語られがちだけど、座談会で tokuhirom さんが言っていた、

Perl の文化では(言語そのものの)コミッターを崇めるような事は少なく、CPANオーサーが讃えられる」

という言葉が Perl の魅力を非常に端的に表しているなと思いました。言語としての機能が少なくて、それを補うようなモジュールの集合体が Perl という言語全体を作っている。そこに沢山の小さなプロジェクトがあって、誰もがちょっとした成功を掴むチャンスがある、というワクワク感が Perl 文化圏にはある気がします。rubygemsCPAN の存在感の違いかもしれません。

また、そういった構造ゆえに外部の言語(やツール)の良い所を持ってこようという動きも活発で、言語自体の大きな変化が無いにも関わらず色々な話題が定期的に出てきている気がします。

この「みんながヒーロー」な感じが Perl の魅力なんだなと再確認しました。

Kindle Paperwhite と 紙の本の素晴らしさ

念願だった Kindle Paperwhite を購入しました。

f:id:bonar:20130630212738j:plain

噂通りの見やすさで素晴らしい端末でした。Kindle が来てから僕の読書量もかなり増えました。読書に対するスタイルを一変させる力があると感じました。具体的に以下のような点が素晴らしかったです。

良い点

とても見やすく疲れない

E-Ink は本当に目が疲れず、素晴らしいの一言です。ライトもついているので寝ながら読む事ができ、ついつい深夜まで本を読んでしまいます。タブレットのような透過光メディアには無い圧倒的な優位性です。

沢山入るので、いくつもの本を気分に合わせて平行して読める

これも非常に大きなメメリットで、通常の読書体験から大きく向上した点です。

何冊も入れておけるので、その時の気分に合わせて読む本を変える事が出来ます。この事で常に何か読みたい本が読める状態になっているので、ぐっと読書が身近になりました。

完成されたエコシステム

Amazon の Kindle ストアで 1-Click 購入すると、Wi-fi に接続されたデバイスに勝手にダウンロードされて読める状態になっています。検索等も使い慣れた Amazon のインターフェイスで行えますし、無料でサンプルが読めて サンプル読了後に製品版の購入ダイアログが出たりと システム全体として非常に高いレベルで完成されていると思います。

安い

これほどのデバイスが 8000円 で購入出来るなんて凄いですね。
手触りもしっとりしていて安っぽくないです。ふちも大きく取られていて持ちやすく、マットな素材で滑りにくいです。

物足りない点

逆に以下の点は少し物足りないと感じました。

動作のもっさり感

iPhone のヌルヌルしたUIのような体験を期待しているとガッカリすると思います。タッチへの反応は鈍く、少し遅れて画面が切り替わるような感じです。

本を読む分には問題ないですが、本を検索する時には「もうちょっとキビキビ動いて欲しいな」と感じる事もあります。まあ、これは「電子書籍リーダーであってスマホじゃない」という点を考えれば許容出来る範囲かなと個人的には思いました。

まだちょっと重い

Kindle Paperwhite はそのデバイスの性能から考えると非常に軽いですが、まだもう少し軽くなる必要があると感じました。男の人でも片手でずっと読み続けるのは辛いかもしれません。片手でつり革 片手で Kindle という体勢で通勤時間を乗り切るにはもうちょっとダイエットが必要だと思われます。

コンテンツがまだまだ足りない

これが最も深刻です。

Kindle でもっと沢山を本を読みたいのですが、新しく出る話題の本や新書等がほとんど Kindle Store に無いので、結局紙の本を買う事になります。僕のお気に入りリストには20冊位本が登録してあったのですが、Kindle でも販売しているものは一冊もありませんでした。

この辺りは時間とともに充実してくると信じて待っています。

bookscan で自炊

コンテンツが少ないので bookscan で自炊しました。プレミアムプランに申し込んだのですが、送付用の段ボールを送ってくれたり、スキャンと同時に Kindle 用の最適化をしてくれたりしてとても楽でした。

ただし、Kindle Paperwhite の画面サイズだと、B5サイズ(「Effective C++」 とか)くらいでかなりきついです。まあ頑張ればギリギリ識別出来るかな、、という感じです。

f:id:bonar:20130617215125j:plain

B6サイズ(「いかにして問題を解くか」とか)だとかなり奇麗に読めます。

f:id:bonar:20130617215220j:plain


中間の A5 とかはちょっと小さいけどなんとか読める感じですね。

ただし、Kindle ストアで販売されている書籍はもちろん文字もくっきりで大きく見やすいので、それと比べてしまうと自炊で作成した PDF はかなり辛いな、というのが僕の印象です。

技術書とかは B5 サイズが多いと思うのですが、これらを本格的に読むならもうちょっと大きい画面が欲しいですね。

紙の書籍の素晴らしさ

紙の書籍の良さを語る際にはかならず「紙の質感」や「余白のメモ」みたいな事が語られがちですが、個人的にはこれらはあんまり魅力を感じないんですよね。。

むしろ、Kindle の読書で一番もどかしく感じたのは「ザッピング」です。

目次をぱらっと見て、全体を俯瞰して見る。読み進めて行って、何か分からない事があったときにいったん目次に戻ってどこかの章をた見返して、また戻る、という行った事がし辛いんです。もちろん目次や指定したページへのジャンプは出来るのですが、ページ遷移がもっさりしているのでなかなか思うように行きません。

紙の本のように高速にページをめくりながら目的のもの探すということが、技術書を読む上では個人的に結構重要なので、この点は苦しいなと感じました。新書や小説のように最初から常にシリアルに読み続けるタイプの読書であれば気にならないかもしれません。

Kindle の素晴らしさ

Kindle の E-Ink は素晴らしいですが、1冊の本を読む体験ではやはり紙の書籍にはかなわないと感じています。

ただしその差は小さく、「同時に沢山持ち運べる」というメリットが買っているかもしれません。少なくとも僕の場合はより細切れに色々な本を読むようになりました。

また、場所と取らないという点も重要です。家の本棚はもういっぱいで新しい本が入れられず、結構深刻な問題です。何万冊もの本が印刷されずに済み、本棚のスペースが節約出来るんだとするとそれだけで素晴らしい事です。

あとは Kindle ストアが充実してくれるか、色々なストアでオープンなフォーマットのデータが販売されるようになって、大体の本はオンラインで買える、という状態になれば最高ですね。

というわけで、Kindle Paperwhite オススメです。

File::Visitor - ファイルを指定条件で集める

ruby

普段の開発やちょっとしたコードを書くときに、特定のディレクトリ以下で指定した条件にマッチしたファイルだけを集めて何か処理をしたいということがよくあります。例えば、

  • 最終更新日が一週間以上前のログファイルを圧縮
  • .conf で終わるファイル名のファイルを読み込む
  • YYYY-MM-DD.txt という形式のファイル名で、且つその日付が1ヶ月以上前のファイルを削除

みたいなものです。

ruby であれば Dir.glob で持ってきてから filter 処理するかもしれません。find コマンドで絞り込んで、その出力をスクリプト言語で拾って、そこからさらに絞り込んだりするかもしれません。ほとんどの場合それで問題ないのですが、「ファイルを持ってきて、特定の条件で絞り込んで、何か処理する」というコードを何度も書いている気がしていたたまれなくなってきたので、この作業を行うための gem を作成しました。

file-visitor
https://github.com/bonar/file-visitor
http://rubygems.org/gems/file-visitor

Install

gem install file-visitor

File::Visitor インスタンスを作成して、そこに必要なフィルタを設定し、visit メソッドにブロックを与えて処理を行います。

require 'file/visitor'

visitor = File::Visitor.new

# files with extension .log
visitor.add_filter(:ext, :log)

# and last modified is more than 30 days ago
visitor.add_filter(:mtime, :passed, 30, :days)

# remove all the matched files
visitor.visit(root_dir) do |path|
  FileUtils.rm(path)
end

これで、「.log という拡張子を持っていて、且つ最終更新日が30日以上前のファイル」を削除する事が出来ます。add_filter できるフィルタは :ext, :name(完全一致、正規表現)、:mtime が用意されていますが、以下のように自分で作成する事も出来ます。

class BigFileFilter

  def initialize(size)
    @size = size
  end

  # filter must implement match?(path)
  def match?(path)
    File.size(path) > @size
  end

end

filter = BigFileFilter(2048)
visitor.add_filter(filter)

match?(path) を持ったインスタンスであれば何でも受け取ります。このようなバッチ処理内の小さな条件は以外とテストされずに残っているものです。バッチ処理が稼働してある程度時間が経ってからバグが発覚し(ファイル名を絞り込む正規表現が間違ってたとか)、自分を呪った事が何度もあります。file-visitor を使うことで、この小さな条件に名前を付けて切り出し テスト可能にする事を後押ししようと考えました。

あと、最終更新日を基準にして何か処理をする事がよくあって、その度に「〜日前」みたいな指定が結構面倒だなと感じていました。それだけであれば find すればいいのですが、find コマンドのオプションが正しいかどうかはテストし辛いので、すべてスクリプト言語で書きたいと考えていました。このモジュールでは以下のように指定出来ます。

# ある日付と比べてどうか、で判別
# add_filter(:mtime, comparetor_sym, time)
visitor.add_filter(:mtime, :equals_to, Time.parse("2013-01-03 04:59"))
visitor.add_filter(:mtime, :is_less_than, Time.parse("2013-01-03 04:59"))

# 現在時刻と比べてどれくらい経っているか、で判別
# add_filter(:mtime, :passed, number, time_unit)
visitor.add_filter(:mtime, :passed, 3, :days)

atime, ctime はプラットフォームによって内容が違うのと、僕のユースケースでは必要無いので入れていません。

フィルタはブロックで指定する事もできます。

visitor.add_filter do |path|
  # return true/false
end

条件が指定出来たら、visit メソッドにブロックを渡して処理します。file_list(dir) で処理を行わずにファイルの一覧を取得することも可能です。

なんとも小粒なモジュールですが、ご意見ご感想があればフィードバックを下さい。

仮面ライダーMOVIE大戦が傑作だった件

「仮面ライダー×仮面ライダー ウィザード&フォーゼMOVIE大戦アルティメイタム」を子供と観に行ってきたのですが、いやもう凄い傑作でした。

http://www.movie-taisen.com

f:id:bonar:20121211044947j:plain

素晴らしい脚本

 前半のフォーゼパートと後半のウィザードパートに分かれており、フォーゼパートはテレビシリーズから5年後の教師となった弦太朗と超能力少年三郎の物語、ウィザードパートはアンダーワールドに捕われ美少女仮面ポワトリンとなった少女を救出する物語になっています。

 

 この前半のフォーゼパートが特に素晴らしくて、子供に見せるために来たのに自分がウルっと来てしまいました。能力を持っているが故に疎まれ傷つく三郎との衝突を通じて、弦太朗自身も「友達になるというだけでは救えない」という壁を乗り越え、教師として大きく成長するという物語になっています。テレビ版を見てきた人にはなおさら弦太朗の意外な行動にハっとして「大人になっちゃって。。」と思う事請け合いです。

 

 特に感動的なのが、三郎が苦悩を乗り越えてサナギマンから新しい姿に「成長」する瞬間です。三郎の長年蓄積した鬱屈が爆発するのがまさにビジュアルとして誰にでもわかるように表現されているので、その後のアクションの気持ちよさも相まって凄まじいカタルシスです。叫びそうになります。

 

 ウィザードパートはシナリオ的にはテレビシリーズの1エピソードが映画スケールになって、かっこいい晴人君が魔法を使いまくって気持ちいい、という内容。ポワトリンがサタンの洗脳から目覚める動機がちょっと弱いかなという気もしますが、最後には素晴らしいオチがあり、話としては非常に奇麗にまとまっていると感じました。

 

 映画全体を通して定期的にアクションがあり、退屈する時間帯が全くないんです。誰かが言葉で話をダラダラするようなところがなく、お話とアクションがタイトに詰め込まれていて子供たちを長時間集中させる事に成功していました。

どんどん新しいライダーや敵が登場してきたり、魔法やスイッチを使いまくってサービス満点です。僕自身も気がついたら終盤で、「ああ、、終わらないで、、」という感じでした。

 

 また、アクション一辺倒で話が適当かというとまったくそんなことはなくて、このそれぞれ別々っぽい2つのパートが最後にちゃんと繋って奇麗に終わってくれます。

それぞれのライダーのエッセンスをコンパクトに盛り込んで、戦闘を随所にちりばめ、物語としての起伏もしっかり含んでちゃんと終わるというライダー映画に求められる要素をすべて高いレベルで達成しています。最高です。

 

アクションが凄い

インターポール捜査官となった流星のシーンから始まるのですが、この流星のアクションがかっこよすぎです。俳優陣が生身でアクションしているシーンも多いため物語とのつながりもスムーズで没入感があります。

 

それぞれのアクションで、なんというか「重いものがぶつかっている感じ」みたいなものが感じられてとても気持ちよかったです。攻撃があたった際の反動や音の演出だと思うのですが、この基本的な気持ちよさがあるおかげですべての戦闘シーンが爽快感のあるものになっています。仮面ライダーの無双ショーを見るという娯楽エンターテインメントにとってこれは非常に重要な点で、この部分の上質さがあるおかげて沢山ある戦闘シーンを飽きずに見る事が出来ました。

 

最高峰のパルクールムービー

パンフレットで坂本監督も書かれていましたが、かなり大胆にパルクール(Free Running)を取り入れた内容になっています。序盤で弦太朗が三郎を追いかけるシーンがまさにそれで、めちゃくちゃかっこいいんです!町中をスタイリッシュに駆け抜けていくこのスポーツの魅力を凝縮したような映像になっています。

 

パルクールって何?という方は 島田 善 さんの動画を見て驚愕するといいです。

 
ZEN PARKOUR 2012 【JAPAN】

 

最近の tower record のサイトの動画もかっこいいですね。

LIVE LIVEFUL! | TOWER RECORDS SHIBUYA RENEWAL OPEN 

最後のCGはちょっと...

ラスボス戦の最後の5分はスケールが大きくなりすぎてほとんどフルCGになってるのですが、実写部分とのギャップが気になるし、まったく別のCG作品が急に始まったような感じで少し無理があったかなという印象ですね。。子供たちにはあまり違和感を感じないのかもですが、大人には結構飲み込みづらかったと思います。

 

あと「スカートがめくれるたびに面白い効果音が鳴る」みたいな演出があって、1,2回だったらいいと思うのですが 結構しつこく繰り返されるのでどうかなと感じました。

 

が、そんなことは小さな問題です。

 

まとめ

エンターテインメント映画として素晴らしい傑作です。今すぐ観に行って三郎に感情移入して叫びましょう。

子供用の映画と思わずに大人が見るアクション映画としても楽しいです。特にパルクール部分は最高にかっこいいですよ。

 

今年の冬休みはこれで決まりです。