RubyのDSLはまったくDSLではありません。Rubyのドキュメントは、それらが実際にどのように機能するかを完全に説明しているため、使用することは絶対に嫌いです。ActiveRecordを例にとってみましょう。モデル間の関連付けを「宣言」できます。
class Foo < ActiveRecord::Base
has_one :bar
has_one :baz
end
しかし、この「DSL」の宣言性(Rubyのclass
構文自体の宣言性のような)は恐ろしい嘘であり、Rubyの「DSL」が実際にどのように機能するかを理解している人なら誰でも暴露することができます。
class Foo < ActiveRecord::Base
[:bar,:baz,:qux,:quux].each do |table|
has_one table if i_feel_like_it?(table)
end
puts "Just for shits and giggles, and to show"
puts "just how fucked up Ruby really is, we're gonna ask you"
puts "which SQL table you want the Foo model to have an"
puts "association with.\n"
puts "Type the name of a table here: "
has_one gets.chomp.to_sym
end
(Lisp フォームの本体内でそれに近いものを試してみてくださいdefclass
!)
上記のようなコードがコードベースにあるとすぐに、プロジェクトのすべての開発者は、Ruby DSLが実際にどのように動作するか(作成した幻想だけでなく)を完全に理解してからコードを維持する必要があります。利用可能なドキュメントは、宣言的な錯覚を保持する慣用的な使用法のみをドキュメント化するため、まったく役に立ちません。
RSpecは、デバッグするために広範なリバースエンジニアリングを必要とする奇妙なエッジケースを持っているため、上記よりもさらに悪いです。(テストケースの1つがスキップされた理由を解明するために丸1日を費やしました。RSpecは、ソースに表示される順序に関係なく、コンテキストのないテストケースの後にコンテキストを持つすべてのテストケースを実行することが判明しました、context
メソッドがブロックを通常のデータ構造とは異なるデータ構造に配置するため。
Lisp DSLはマクロによって実装されますが、マクロは小さなコンパイラです。この方法で作成できるDSLは、Lispの既存の構文の単なる乱用ではありません。それらは、独自の文法を持つことができるため、完全にシームレスになるように記述できる実際のミニ言語です。たとえば、LispのLOOP
マクロはRubyのeach
メソッドよりもはるかに強力です。
(あなたがすでに答えを受け入れていることは知っていますが、これを読むすべての人がOn Lisp全体を読みたいとは限りません。)