2017-01-31 4 views
0

'bar'という子アイテムを持つ 'foo'アイテムを作成しようとしています。期待される出力は次のとおりです。ブロック、バインディング、および評価を使用してアイテムの階層を設定する

foo_item = Item @name="foo", @children=[<...>] 
foo_item children = [Item @name="bar", @children=[]] 

私はブロック、バインディング、および評価を使用しています。これは私のコードです:

foo_item = Item @name="bar", @children=[<...>] 
foo_item children = [Item @name="bar", @children=[<...>]] 

同じ入力を考える:

foo_item = item('foo') do 
    item('bar') 
end 
以下の実際の出力で

class Item 
    attr_accessor :name, :children 
    def initialize name 
    @name = name 
    @children = [] 
    end 
end 

def item(item_name) 
    @item = Item.new(item_name) 
    if @context 
    @context.eval('@item.children') << @item 
    end 

    if block_given? 
    old_context = @context if @context 
    @context = binding 
    yield 
    if old_context 
     @context = old_context 
    else 
     @context = nil 
    end 
    end 
    @item 
end 

foo_item = item('foo') do 
    item('bar') 
end 

puts "foo_item = #{foo_item.inspect}" 
puts "foo_item children = #{foo_item.children.inspect}" 

foo_itemは、その子もbarアイテムであるbar項目が含まれてい

上記の出力はどのようにして得られますか?

答えて

2

instance_evalソリューション

これは、あなたが望むものを達成するための方法の1つです。

instance_evalブロックは通常、evalより良いアイデアです。

item方法はあまりにも複雑ではありません。

  • それは最初のブロックがある場合、それはitemのコンテキストwithingそれを実行item_name
  • で項目を作成します。このブロックで実行されるコードは、@name@childrenを知ることになります。
  • childrenが定義されている場合、現在のメソッドが別のitemのブロック内で呼び出されたことを意味します。現在のitemは、itemchildrenに追加する必要があります。

class Item 
    attr_accessor :name, :children 
    def initialize(name) 
    @name = name 
    @children = [] 
    end 

    def inspect 
    "#{name} #{children}" 
    end 
end 

def item(item_name, &block) 
    item = Item.new(item_name) 
    item.instance_eval(&block) if block 
    children << item if defined?(children) 
    item 
end 

foo_item = item('foo') do 
    item('bar') do 
    item('biz') 
    item('boz') 
    end 
    item('baz') 
end 

p foo_item 
#=> foo [bar [biz [], boz []], baz [] 

デバッグモード

は、ここでデバッグ情報と同じコードです:

class Item 
    attr_accessor :name, :children 
    def initialize(name, indent = "") 
    @name = name 
    @children = [] 
    @indent = indent 
    end 

    def inspect 
    "#{name} #{children}" 
    end 
end 

@indent = "" 
def item(name, &block) 
    puts "#{@indent}Creating item #{name}" 
    item = Item.new(name, @indent + " ") 
    item.instance_eval do 
    puts "#{@indent}Inside item #{@name}" 
    end 
    if block 
    puts "#{@indent} Block is here. Executing it in item #{item.name}" 
    item.instance_eval(&block) 
    end 
    if defined?(children) 
    puts "#{@indent}Inside item #{@name}! Adding item #{item.name} to #{@children}" 
    children << item 
    end 
    item 
end 

それは出力:

Creating item foo 
    Inside item foo 
    Block is here. Executing it in item foo 
    Creating item bar 
    Inside item bar 
    Block is here. Executing it in item bar 
    Creating item biz 
     Inside item biz 
    Inside item bar! Adding item biz to [] 
    Creating item boz 
     Inside item boz 
    Inside item bar! Adding item boz to [biz []] 
    Inside item foo! Adding item bar to [] 
    Creating item baz 
    Inside item baz 
    Inside item foo! Adding item baz to [bar [biz [], boz []]] 
+0

私はこれが動作することを見たが、やります方法を理解していない。何が起こっているのか説明できますか? – Anand

+0

私はそれがはっきりしていることを願っています、今 –

+0

はい、説明に感謝します。 – Anand

関連する問題