2011-02-08 19 views
31

RubyでDSLを実装する方法に関する良いオンラインチュートリアルは何ですか?私はプロセス全体を説明する実例を探しています。RubyでDSLを書くためのチュートリアル

私は、DSLとRubyについての良い本にこの質問があることを知っています:Good books on Ruby based DSL

私は、これはRubyでDSLを構築する上での記事の偉大なシリーズだと思い

答えて

34

あなたが宝石を使用することによって、またはthe source codeを読み取ることにより、いずれか、Docilegemで、これは非常に簡単に行うことができますどのように動作するかを理解するために。

は、あなたがDSL

Pizza = Struct.new(:cheese, :pepperoni, :bacon, :sauce) 

経由ピザを作りたいそして、あなたはピザ

class PizzaBuilder 
    def cheese(v=true); @cheese = v; end 
    def pepperoni(v=true); @pepperoni = v; end 
    def bacon(v=true); @bacon = v; end 
    def sauce(v=nil); @sauce = v; end 
    def build 
    Pizza.new([email protected], [email protected], [email protected], @sauce) 
    end 
end 

を作るためにBuilderパターンを使用して、あなたはDSLをしたいと言いますたとえば、次のように言ってください。

@sauce = :extra 
pizza do 
    bacon 
    cheese 
    sauce @sauce 
end 
# => should return Pizza.new(true, false, true, :extra) 

あなたがしなければならないのは、

require 'docile' 

def pizza(&block) 
    Docile.dsl_eval(PizzaBuilder.new, &block).build 
end 

、バンとしてピザ方法を定義し、設定が完了しています。それが明示的にyieldinstance_evalを使用しての2つの非常に重要なパターンカバーとして私は、このチュートリアルは非常に良い見つける

+5

-1 Docileは間違いなく非常に使いやすいですが、これを使用すると、正常なRuby DSLを作成するプロセスをバイパスするので、配列を作成します。 – 00dani

+4

@ 00Davoあなたが意見を表明できるとき、それは非常に非友好的なジェスチャーです。特にDocileのソースコードは、RubyでDSLを作成する方法を学ぶのに最適です。 –

+0

うん。私はソースを見て、あなたは正しいです。それは確かに非常に実例です。投票を変更しますが、Docileソースへの参照を含めるように回答を編集することをお勧めします。 (ああ、ちょうど試しましたが、私の投票は答えが編集されていない限り固定されているようですので、実際に編集する必要がありますか?) – 00dani

0

前提条件が生じるのブロックのようないくつかの高度なプログラミング手法を理解していますRubyのメソッドルックアッププロセスとmethod_missing()などです。これらの高度なRubyスキルを開発するには、Metaprogramming Rubyを読むことが最善の方法です(本書には、内部DSLの記述に関するセクションも含まれています)。

約20行のコードにblog post on how to create a Ruby DSL to generate HTML markupと書きました。 Erectorのようなプロダクショングレードのアプリケーションに入るのではなく、小さなおもちゃの例から始める方がはるかに優れています。 ms-tgで提案されているようにDocile gemのソースコードを勉強するのは優れていますが、最初のDSLとしては圧倒的かもしれません。いくつかの高度なRubyプログラミングテクニックを学び、いくつかのおもちゃの例を作ってから、Docileのソースコードを調べます。

はここでゼロから@ MS-TGで説明したように従順な宝石の機能の一部を取得する方法は次のとおりです。

dsl()方法は、の Docile README例のように、より多くのささいな例のためにも使用することができます
def dsl(obj, &block) 
    obj.instance_eval(&block) 
end 

Pizza = Struct.new(:cheese, :pepperoni, :bacon, :sauce) 
obj = Pizza.new 

dsl(obj) do |pizza| 
    pizza.cheese = true 
    pizza.pepperoni = true 
    pizza.sauce = :extra 
end 

p obj 
# => #<struct Pizza cheese=true, pepperoni=true, bacon=nil, sauce=:extra> 

+1

もちろん、裸の 'instance_eval'を使うこともできますが、インスタンス変数やローカル変数を使うことができなくなり、コンテキストを連鎖させることができなくなります(一般的なマルチレベルDSLを考える) 。それは理にかなっていますか? Docileが追加するものは、これらの問題に対する標準的な解決策であり、プロジェクトではこれを再発見し、再発明する必要はありません。 –

関連する問題