2014年7月9日水曜日

capybaraのpage.execute_scriptとjQueryの組み合わせの汎用性がすごい

Webアプリ開発のテストに便利な Capybara(+Cucumber) ですが、テストに使うdriver がJavascriptに対応していれば、テスト中にJavascriptの実行を含めてブラウザの動きをシミュレートできるという素晴らしい特長があります。Javascript対応のdriverとしては、Capybara-WebkitやPoltergeistなんかが有名です。

ボタンやリンクのクリックなどのユーザの動作で発火するイベントは、Capybaraでclickなどのメソッドで指定すれば、Javascript側のイベントの動作もそのままシミュレートしてくれるようですが、マウスオーバーなどのイベントはどうやったらテストできるのでしょうか。

実は、Capybaraには execute_script メソッドがありまして、これでJavascriptのコード片を直接記述して実行できます。この中ではページで読み込んだライブラリなどが有効です。なのでjQueryが使えます。よってjQueryを使ってイベントを発火させることにより、かなりの汎用性を持ちえます。

例えば、マウスオーバーのステップ定義はこんなふうに書けてしまいます。

もし(/^".*?\((.*?)\)" にマウスポインタを乗せる$/) do |t_css|
  page.execute_script("$('#{t_css}').trigger('mouseenter')")
end

上記ステップ定義に従い、featureファイルにはこんなふうに書けますね。

もし "メニュー1(#menu1)" にマウスポインタを乗せる

カッコ内のCSSセレクタで指定した要素にmouseenterイベントが発生し、マウスオーバーの動作テストを実行することができます。

という感じで、execute_script メソッド内でjQueryを使うと簡単な記述で様々なことが実現出来そうです。特にテスト実行上重要なイベントの発火が非常に簡潔に書けるのでいいですね。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月8日火曜日

vimdiffでより賢いアルゴリズム(patience,histogram)を使う

vimdiff使ってますか?差分を取る際には非常に便利ですよね。git difftoolに設定して使っている人も多いと思います。しかしgit diffは差分計算のアルゴリズムを選択できますが、vimdiffはデフォルトでは差分計算のアルゴリズムを選択できません。

git diffの差分アルゴリズムには標準のもの以外にpatienceやhistogramがあり、より人間に読みやすい差分を表示してくれる「賢い」アルゴリズムになっています。それぞれgit diffコマンドのオプション--patienceや--histogramを付けるか、または~/.gitconfig設定ファイルにアルゴリズムを指定することで利用できます。

具体的なアルゴリズムの詳細は僕も詳しくないですが、patienceアルゴリズムは「ファイル内でユニークかつ比較ファイル同士で一致する行をなるべく"変化していない行"と認識する」よう働きます。また、histogramアルゴリズムは「patienceアルゴリズムの基本的ルールを継承しつつ高速化を図ったアルゴリズム」で、多くのファイルでpatienceアルゴリズムと同一の結果が得られるようです。また、histogramアルゴリズムはEclipseに統合されたGitクライアントEGit(が使うJGit)の標準アルゴリズムです。僕はコマンドラインツールのgitにおいてもhistogramアルゴリズムを使ってます。

さて、vimdiffにおいてもhistogramアルゴリズムを使いたいところです。vimの設定ではvimdiffの差分計算に使用するコマンドをdiffexprという設定値で指定できます。そして、git diffコマンドも--no-indexオプションを指定することでdiffコマンドと同じようにスタンドアロンツールとして利用できます。じゃあ、diffexprにgit diff --no-indexを指定すればいいのか・・・というと実はそれだけでは失敗します。

理由は、vimがdiffexprに設定したコマンドから受け付ける差分形式が、diffコマンドのnormal形式かed形式でなければならないからです(vimのヘルプにはed形式とだけ書いてあるのですが、normal形式も受け付けます)。そして、git diffコマンドでは直接diffコマンドのnormal形式やed形式で出力することができずunified形式のみに対応しています。

そこで、unified形式をnormal形式に変換するrubyスクリプトを書いて使うことにしました。以下がその変換スクリプトです。利用にはrubyが必要です。

#!/usr/bin/env ruby
iwhite = ''
if (ARGV[0] == '-b')
  iwhite = ARGV.shift.dup << ' '
end

diffout = `git diff --no-index --no-color -U0 #{iwhite}#{ARGV[0]} #{ARGV[1]}`
diffout.sub!(/\A.*?@@/m, '@@')
diffout.gsub!(/^\+/, '> ')
diffout.gsub!(/^-/, '< ')
diffout.gsub!(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@.*/) do
  before_start = $1
  before_size = $2
  after_start = $3
  after_size = $4

  action = 'c'
  if (before_size == '0')
    action = 'a'
  elsif (after_size == '0')
    action = 'd'
  end

  before_end = ''
  if (before_size && before_size != '0')
    before_end = ",#{before_start.to_i + before_size.to_i - 1}"
  end

  after_end = ''
  if (after_size && after_size != '0')
    after_end = ",#{after_start.to_i + after_size.to_i - 1}"
  end

  "#{before_start}#{before_end}#{action}#{after_start}#{after_end}"
end
diffout.gsub!(/^(<.*)(\r|\n|\r\n)(>)/, '\1\2---\2\3')
print diffout

上記スクリプトを~/bin/git-diff-normal-formatとして保存し、~/binにPATHを通しておきます。そしたら、.vim設定ファイルに次の記述を追加します。

" diffのコマンド
set diffexpr=MyDiff()
function MyDiff()
  let opt = ""
  if &diffopt =~ "iwhite"
    let opt = opt . "-b "
  endif
  silent execute "!git-diff-normal-format " . opt . v:fname_in . " " . v:fname_new . " > " . v:fname_out
  redraw!
endfunction

最後に、git diffで使うアルゴリズムを指定します。下記記述ではgit difftoolで起動するコマンドにvimdiffを指定する設定も一緒に行っています。

[diff]
  tool = vimdiff
  algorithm = histogram

これでvimdiffやgit difftoolを実行した時にhistogramアルゴリズムが使えるようになります(patienceを使いたい場合は、上記設定のalgorithmの値をpatienceに変えてください)。

では具体的な効果を見てみましょう。サンプルとして用意した2つの比較対象のファイルをvimでウィンドウを分割して並べたものが下の画像です(クリックで拡大できます)。


まずは、今回の設定をする前、デフォルトのアルゴリズムでvimdiffによる差分をとった結果が以下です(クリックで拡大できます)。


そして、今回の設定をした後の、histogramアルゴリズムでvimdiffによる差分をとった結果が以下です(クリックで拡大できます)。


こちらのほうが、より差分内容も分かりやすく、かつ実際に手で行った変更の操作に近いものになっていますね。
※ちなみにこのvimdiffの色設定は過去に書いたこの記事を参照。

※2014/07/10更新:diffupdateを実行した際に画面の描画がおかしくなることがあったので、回避のためMydiff()にredraw!を追加

※参考記事
Making your Git Diff/Merge More Useful | The Interim Developer
Alfedenzo - Patience Diff, a brief summary
Bram Cohen's Journal - Patience Diff Advantages
HistogramDiff (JGit - Core 2.0.0.201206130900-r API)

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月5日土曜日

ググっても解決しない問題にこそ力を注ぐ

今のソフトウェア開発ってフリーソフトとかオープンソースとか皆が共通に利用できる資源が整ってまして、仕事で使うソフトウェアも手に入ります。その結果優れたソフトウェアは皆が同じものを使うようになります。得られたノウハウもウェブページやブログや各種SNSで公開していくために、困ったことがあればググればほとんど解決できるんですよね。その意味でネットが無ければ仕事になりません。

だから知識は重要だし、他人が既に見つけた問題の解決策を素早く見つけることも必要ではあることは確かです。僕も散々そう言ってますし。でも、そこには当然ながら限界がありまして、仕事をしていれば必ず、そう"必ず"いくらググっても解決策を見つけられない問題にぶちあたるものなのですね。

その時こそが本当に力を注ぐべき時です。ググって解決できるものをサッサと片付けるのは、この"いくらググっても解決策を見つけられない問題"に時間を掛けるためだと言っても過言ではありません。

ちなみに僕は"いくらググっても解決策を見つけられない問題"にぶちあたるのを、いつも楽しみにしてます。まあ、ググってサクサク問題を片付けるのもシューティングゲームみたいで楽しくはありますが、やはり本気で頭を使う時が一番楽しかったりするので。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月4日金曜日

gitでマージの事前に衝突するかどうか確認する

gitを使っていて、特定のブランチとマージしたら衝突が起きないかどうか知りたい場合があります。例えば、プロジェクトチームで共有しているリポジトリにコミットをプッシュする前に、現在作業中のブランチがmasterブランチと衝突を起こさないか確認しておきたい、なんて場合です。

そんな時は、mergeコマンドの —no-commit オプションで master をマージしてコミットせずに止めてみればいいです。あとで簡単に元に戻せます。(本来確かめたい向きとは逆向きのマージですが、衝突の確認をするだけなら結果は同じですから問題ありません。)

[user@host]% git merge master --no-commit
Auto-merging /some/file/path
Automatic merge went well; stopped before committing as requested

同一ファイルに編集があったが、自動的にマージされた場合には上記のような表示になります。衝突を起きて自動的に解決できない場合はその旨がここで表示されるはずです。

確認は終わりましたが、そのままではワーキングツリーとインデックスが変更されたままですので、元に戻します。mergeコマンドの --abort オプションを使えばいいです。

[user@host]% git merge --abort

これで元通り。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月3日木曜日

評価されないが重要なメンテナンス性

プログラミングをしていて、つくづくメンテナンス性って重要だと感じます。要するに後から修正や変更をしやすい構造にするってことなんですが、問題は、このメンテナンス性を高くするという行為がすぐに成果に直結しないため評価しにくいってことでしょうね。

まあ、評価されるかどうかはおいといて、エンジニアとしてのこだわり、あるいはポリシーとしてメンテナンス性は上げておきたいわけですよ。そのプログラムが使われれば使われるほど、メンテナンス性は重要になっていくわけです。

それに、他のエンジニアが自分の書いたコードを見るたびに文句をいうことになるか、あるいは逆に賞賛してくれるかは、メンテナンス性の良し悪しにかかっています。その意味でも、自分の書くコードはメンテナンス性は高く保つよう常に努力してます。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月2日水曜日

コーディングには自分なりのポリシーを持つ

ソフトウェア開発をしておりますと、人の個性が出る作業の代表格はプログラムのコーディングでしょう。

性格も出る気がしますし。注意すべきなのは、面と向かって話している時に感じる印象と、プログラムをコーディングしている時に、そのソースコードに現れる印象は違うことがあるということです。

ともあれ、それぞれの個性というのはありますが、その中においても、やはり各自が自分なりのポリシーを持つべきだと思います。

僕だったら、
・コードの簡潔さより、長くても読んで分かりやすい方を優先する
・コメントは積極的に入れる

などですね。自分なりのポリシーを持ち、その運用を改善していくことにおって、コーディング自体のスキルも上がると思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月1日火曜日

ボツになるコードを書く勇気

仕様書通りに動くプログラミングをするのが
我々ソフトウェア開発者にとって仕事の基本ですが
ただ言われた通りのものを作るだけじゃ面白くないわけでしてね。
改善提案をしたいわけですよ。

ところが、人間ってのは実際自分の目で見て動作を実感しないことには
口で行っただけでは提案した改善の効果が伝わらなかったりする、
なんてことが多いです。

そういう場合に、たまに僕がやる手段は、
ボツになるかもしれないのを覚悟で改善提案のコードを
書いてしまうことです。そして目の前で実際に動かしてみせるのです。
もちろんボツになったこともありますが、意外に採用してくれる
ことが多いですね。

言われたことだけ、仕様書に書いてあることだけを創っていては
見えてこない物があると思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。