【Ruby】言語内DSLとは。
Railsチュートリアルを勉強しています。
すごくわかりやすい。楽しい。
この中ででてくるRSpec↓
require 'spec_helper' describe User do pending "add some examples to (or delete) #{__FILE__}" end
普通だったらメソッドの定義は def だよね?
describe?
あ、これが言語内DSLというやつか!!??
調べてみるとやっぱりそう。
RSpecはDSLなんだ!
調べてみると「るびま」の記事が見つかった。
スはスペックのス 【第 1 回】 RSpec の概要と、RSpec on Rails (モデル編)
RSpec はプログラムの振舞を記述する言語として、Ruby を拡張することを選びま した。このような、DSL を定義する言語と DSL を実行する言語 (ホスト言語) とが 同じである DSL の実装アプローチを「言語内 (internal) DSL」と呼びます。
なるほど!
RSpec が「振舞定義用の DSL」を提供して、プログラマに Test::Unit とは異なる 書き方をさせているのは、ある考え方を私たちに伝えるためです。その考え方とは、 テスト駆動開発 (Test Driven Development:TDD) です。
なるほど!
常々思うけど言語って「思想」だよね。
2 行目の自動生成されたメッセージは RSpec ならではの機能です。メッセージは、 describe メソッドや it メソッドに渡したクラス定数や文字列を利用して作成し ています。スペックを定義する場合には、この失敗メッセージを、失敗したテ ストの内容を表すように構成するのがコツです。
うーん、、
まだ慣れてないからかもしれないけれど、
この独特のエラーメッセージ、
あまりにセンテンスになりすぎていて好きになれない。
Array when initialized with object should not affect others' FAILED
こういうメッセージ。
まあでも、Junitとかプロジェクトで使うと、
無意味なコメント(そして整合性が取れず嘘のコメントになる)
を山ほど書く、人/チーム/会社は必ずあるから、
そういう意味では、防止策といえるかな。
スペックファイルは Ruby スクリプトですから、振舞の記述に必要なヘルパメ ソッド、クラスやモジュールも通常の Ruby スクリプトと同様、自由に定義できます。 共通の処理をまとめたり、可読性を高めるために積極的に利用するとよいでしょう。
ふんふん。言語内DSL!
it "#empty? は true であること" do...
「日本語で書い たら "it" が意味不明でどうしても気持ち悪い」と思われる方は、 互換性のために残されている旧来の API を使うこともできます。
うーん、、分かった。日本語は使わないようにする。
でも「英語として意味が通じるか」を考えながらプログラミングするって、あまり本質的ではない気がする。
チュートリアルでも、itが不自然な場合はspecifyメソッドを使ってテストを書いているけど、
「it should not equal wrong user」(itはユーザーなど) とするのは英語として自然ですが、「user: user with invalid password should be false」は不自然であり、「specify: user with invalid password should be false」とすれば自然になります。
って、なんだか判断が難しい気がする。
「人間の言葉そのままにプログラミングする」って
たぶん大きな一分野だと思うれど。
「it」って何?を考えなきゃ書けない。
もやもやっとしてた「言語内DSL」が分かったぞ!
Gemfile もシンボルが使えるし、多分言語内DSLだ。
そんなに複雑なものでもない。
ホスト言語がRubyという点では
このあいだ考えた"せかい言語"と変わりはないと思う。
一方、schema.rbは
一見DSLぽくみえる(設定ファイルのように見えて、Rubyを拡張しているように見える)けれどもそうじゃない。
Schema.defineメソッドを実行しているだけ。
doブロックのおかげで表現が豊かになってる。
レシーバーを省略しているから独自の拡張ぽくみえるけど
create_table なんかも単なるメソッド実行。
ActiveRecord::Schema.define(:version => 20130907****) do create_table "users", :force => true do |t| t.string "name" t.string "email" end add_index "users", ["email"], :name => "index_users_on_email", :unique => true end
doブロックって面白い。