代码之家  ›  专栏  ›  技术社区  ›  Anand

使用块、绑定和eval填充项的层次结构

  •  0
  • Anand  · 技术社区  · 8 年前

    我正在尝试创建一个“foo”项,其子项名为“bar”。预期输出为:

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

    我正在使用块、绑定和eval。这是我的代码:

    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 项,其子项也是 酒吧 项目:

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

    给定相同的输入:

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

    如何获得上述预期输出?

    1 回复  |  直到 8 年前
        1
  •  2
  •   Community Mohan Dere    8 年前

    instance_eval解决方案

    这里有一种方法可以实现你想要的。

    instance_eval 使用block通常比 eval .

    item 方法并不太复杂:

    • 它首先创建一个具有 item_name
    • 如果有一个块,它将在 项目 这意味着在该块中执行的代码将知道 @name @children .
    • 如果 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 []]]