Fukuoka.rbで Ruby で連続するダブルクオートの扱いについて @nagachika さんに聞いたら面白い話が聞けた。
Lokka のテストで FactoryGril でフィクスチャーデータ作ってるところに、以下のような文字列があった。
factory :post do
association :user
sequence(:title){|n| “Test Post #{n}” }
body “<p>Welcome to Lokka!</p><p><a href=“”/admin/“”>Admin login</a> (user / password : test / test)</p>”
type ‘Post’
created_at create_time
updated_at update_time
end
この body の部分で、ダブルクオートが連続して書いてある場所があって、ここがらみでテストを流してたら失敗する現象に遭遇した。テストに失敗したときのメッセージは以下。
Failures:
1) Post markup default should == “<p>Welcome to Lokka!</p><p><a href=/admin/>Admin login</a> (user / password : test / test)</p>”
Failure/Error: it { post.body.should == post.raw_body }
expected: “<p>Welcome to Lokka!</p><p><a href=/admin/>Admin login</a> (user / password : test / test)</p>”
got: “<p>Welcome to Lokka!</p><p><a href=\”/admin/\”>Admin login</a> (user / password : test / test)</p>” (using ==)
# ./spec/unit/post_spec.rb:56:in `block (4 levels) in <top (required)>’
なんか expect の方で HTML 内のダブルクオートが省略されてる。ダブルクオートが連続してるのが怪しいなと思って、文字列内でダブルクオートが連続したら、一つ目の ”
はエスケープ文字列みたいな扱いになるのかなと思った。
しかし実はそうではなくて、 @nagachika さんの説明によると、ダブルクオートが連続した場合、一つ目の "
で文字列の終端と判定される。すぐ右隣の "
は新しい文字列の開始と見なされ、結果としては文字列として連結されるらしい(C 言語由来の慣習とのこと)。
たとえば、次のような文字列は
“<p>Welcome to Lokka!</p><p><a href=“”/admin/“”>Admin login</a> (user / password : test / test)</p>”
“<p>Welcome to Lokka!</p><p><a href=“
と ”/admin/“
と ”>Admin login</a> (user / password : test / test)</p>”
という三つの文字列と見なされ、クオートとクオートの間に何も挟まらないので自動的に一つの文字列として連結され、以下のようになる。
“<p>Welcome to Lokka!</p><p><a href=/admin/>Admin login</a> (user / password : test / test)</p>”
これ、なぜいままで Lokka でこの状態で CI のテスト通ってたのかわからないけど、今日 wercker で CI の設定していてテストが通らなくてこの問題に気がついた。同じように手元でテスト実行しても落ちた。ひょっとすると Ruby 2.1.0 で落ちるのかも知れない。いずれにせよ ""
は使わない方が良さそうなので修正して Pull Request 出そう。