トップ «前の日記(2008-10-19) 最新 次の日記(2008-10-22)» 編集

Route 477



2008-10-20

[ruby] Rubyで広がる日本語DSLの世界!!

昨日のネタウケたので、悪ノリしてみました。

Rubyを使って自然言語(というか英語)っぽい記述を行うライブラリといえばRSpecがまず例に上がるんですけど、 最近はもう英語に近くなりすぎて、日本人にとっては逆に使いにくくなっているんじゃないかという気がするんですよ。

このままでは英語圏と日本人のプログラマの生産性の格差は高まるばかり、 ていうか正直に言って英語ばっかりずるい、ここは一つ日本語を生かしたコード、日本語DSLの登場が待ち望まれているのではないか。 以下「それなでしこでできるよ」禁止。

というわけで妄想してみました、日本語でBDDを行うライブラリ、その名も「Japanespec」。

require 'japanespec'
include Japanespec

"Ruby".の 仕様{
  # ==
  Math.sqrt(4).は 2.に なる      #案1
  Math.sqrt(4).は 3.に ならない
  Math.sqrt(4).は 2, である      #案2
  Math.sqrt(4).は 3, ではない

  # be
  [1,2,3].include?(3).は 正しい     # be_true
  [1,2,3].include?(4).は 正しくない # be_false
  [].first.は nil.に なる           # be_nil
  [1].first.は nil.に ならない      # not be_nil

  # equal?
  5.は 5.と 同一である
  "5".は "5".と 同一ではない

  # should change
  obj = 1
  lambda{ }.は obj.の :prop.を 変える
  lambda{ }.は obj.の :prop.を 1.から 2.に 変える

  # has, include
  ary = [1,2,3]
  ary.は 2.を 含む
  ary.は 3.個の :item, を持つ
  ary.は 3.個以上の :item, を持つ
  ary.は 3.個未満の :item, を持つ

  # respond_to
  ary.は :size, :length, に応答する

  # raise
  lambda{ }.は 例外 を投げる
  lambda{ }.は 例外 ArgumentError, を投げる
  lambda{ }.は 例外 ArgumentError, "foobar", を投げる

  # match
  str = "abcde"
  str.は /abc/.に マッチする

  # satisfy
  obj = 1
  obj.は {|o| o<3 and o%3 == 1 }.を 満たす
}

どうでしょうか?

まだ中身の実装はしてないんですけど、恐ろしいことにこれ、ちゃんとパーズが通ります。ソースはgithub。

暇な人は冬休みの課題として実装してみるといいよ!

テクニカルなこと

以下、Rubyで日本語DSLを設計する際の注意点など。

まず、Ruby 1.8だとwarning出まくるんで1.9でやりましょう。1行目の「# coding: utf-8」も忘れずに。

上のソースがどのように解釈されるかですが、一つだけ例を挙げると

 str.は /abc/.に マッチする

というコード(コードですよ)は、

 str.は(/abc/.に(マッチする))

と解釈されます。より分かりやすく書き換えると、

 str.foo(/abc/.bar baz())

ということ。foo, bar, bazというメソッドの呼び出しがネストしてるわけです。日本語版ではそれぞれ「String#は」、「Regexp#に」、「Japanespec#マッチする」ね。 こんな感じで、

 obj.foo bar baz

のようにメソッドや関数を並べるのがRubyによる日本語DSLの定石です。

ちょっと凝ったことをしたいときには、つい

 foo(bar, 3) baz

みたいにカッコを使いたくなりますが、これはパースエラーになってしまいます。 「あれ、fooがProcオブジェクトを返したらいけるんじゃね?」と思ったあなたはScheme脳(もしくはHaskell脳)(もしくはPython脳)で、 Procオブジェクトを実行するには

 foo(bar, 3).call baz
 foo(bar, 3)[baz]

のようにcallか[]が必要です。まあcallは論外ですが[]も記号だらけになってあんまりよろしくないですね。

なのであり得る形としては、

 a.foo b.bar baz, 3

のように一番右のメソッド呼び出しだけ引数をカンマで区切るくらいかと思われます。 もっとクール(笑)な書き方を見つけた方はご一報ください。

本日のツッコミ(全4件) [ツッコミを入れる]
ujihisa (2008-10-21 01:48)

Proc#callの別名として<br>Proc#は<br>Proc#の<br>Proc#みたいな<br>とかを作るのはどうかlang:ja

yhara (2008-10-21 09:32)

例えば(ary.は 3.個以上の(:item).を 持つ).みたいな? "これはすごい"

星一 (2008-10-21 10:19)

ケータイ小説プログラミングの予感!

yhara (2008-10-22 00:32)

あたし 彼女.スイーツ(笑)