我正在尝试使用名为“bar”的子项创建“foo”项。预期的输出是:
foo_item = Item @name="foo", @children=[<...>]
foo_item children = [Item @name="bar", @children=[]]
我正在使用块,绑定和评估。这是我的代码:
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
项:
foo_item = Item @name="bar", @children=[<...>]
foo_item children = [Item @name="bar", @children=[<...>]]
给出相同的输入:
foo_item = item('foo') do
item('bar')
end
如何获得上面的预期输出?
答案 0 :(得分:2)
这是达到你想要的一种方式。
带有阻止的 instance_eval
通常比eval
更好。
item
方法并不复杂:
item_name
item
的上下文执行它。这意味着此块中执行的代码将了解@name
和@children
。children
,则表示已在另一个item
的块内调用了当前的item
方法。应将当前item
添加到父children
的{{1}}。item
这里有与调试信息相同的代码:
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