1

Ruby で DSL メタプログラミングをいじっています。

次のプログラムは、ネストされたブロックの評価を使用して、期待どおりに動作します。その意味は、ここで公開する問題にとって重要ではありません。私が抱えている「バグ」または問題は、最後の 4 行に関するものです。

# works (using a variable 'mm' to store the result of Gen.define method)
mm=Gen.define("abc") do
  node(:func){}
end
pp mm
# returns {"abc"=>#<Definition:0x000000021f6c90 @nodes={:func=>#<Node:0x000000021f6a60 @name=:func>}>}

ただし、以下は機能せず、エラーが返されます。これも以下に示します。違いは、define の結果 (ハッシュ) が引数として 'pp' pretty printer に直接渡されるのに対し、作業プログラムは変数 (mm) を使用することです。

# does NOT work (no variable)
pp Gen.define("abc") do
  node(:func){}
end

なぜこのような行動の違いが生じるのでしょうか?

エラーは次のとおりです。

`instance_eval': ブロックが提供されていません (ArgumentError)

これが完全な(動作する)プログラムです(これも何も役に立ちません)。

require 'pp'

class Gen
  def self.define name,&block
    @nodes=Definition.new(&block)
    return name => @nodes
  end
end

class Definition
  def initialize(&block)
    @nodes={}
    instance_eval(&block)
  end

  def node name,&block
    @nodes.merge!(name =>  Node.new(name,&block))
  end
end

class Node
  def initialize name,&block
    @name=name
    instance_eval(&block)
  end
end

mm=Gen.define("abc") do
  node(:func){}
end

pp mm
4

1 に答える 1

1

ここでの問題は単に優先順位です: あなたが言うとき

pp Gen.define("abc") do
  node(:func){}
end

それppはブロックを取得することです。それは次と同じです:

pp(Gen.define("abc")) do
  node(:func){}
end

これはあなたが望むことをします:

pp(Gen.define("abc") do
  node(:func){}
end)

do一部の人々 (私を含む)は、メソッドが値を返すときにブロックに …<code>end の代わりに中括弧を使用することを推奨しています。おそらく、これにより驚くべき結果が少なくなることがわかります。

pp Gen.define("abc") {
  node(:func){}
}
于 2013-10-04T13:02:56.387 に答える