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 솔루션은

여기 당신이 원하는 것을 달성하기위한 하나의 방법입니다.

instance_eval 블록은 일반적으로 eval보다 좋습니다.

item 방법은 너무 복잡하지 : 블록이 있다면

  • item_name
  • 가진 항목을 만들고, 그것은 item 컨텍스트 withing에 행한다. 이 블록에서 실행 된 코드는 @name@children에 대해 알 수 있습니다.
  • children이 정의되면 현재 item 메서드가 다른 item 블록 내부에서 호출되었음을 의미합니다. 현재 itemitem 부모의 children에 추가해야합니다.
    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