使用块、绑定和评估填充项目的层次结构
Populating a hierarchy of items using blocks, bindings and eval
我正在尝试创建一个 'foo' 项目,其中包含一个名为 'bar' 的子项目。预期输出为:
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
如何获得上面的预期输出?
instance_eval解决方案
这是实现您想要的目标的一种方法。
instance_eval
with block is usually a better idea than eval
.
item
方法并不太复杂:
- 它首先创建一个带有
item_name
的项目
- 如果有块,它会在
item
的上下文中执行它。这意味着在此块中执行的代码将知道 @name
和 @children
.
- 如果定义了
children
,则表示当前item
方法已在另一个item
的块内调用。当前 item
应该添加到父 item
的 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 []]]
我正在尝试创建一个 'foo' 项目,其中包含一个名为 'bar' 的子项目。预期输出为:
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
如何获得上面的预期输出?
instance_eval解决方案
这是实现您想要的目标的一种方法。
instance_eval
with block is usually a better idea than eval
.
item
方法并不太复杂:
- 它首先创建一个带有
item_name
的项目
- 如果有块,它会在
item
的上下文中执行它。这意味着在此块中执行的代码将知道@name
和@children
. - 如果定义了
children
,则表示当前item
方法已在另一个item
的块内调用。当前item
应该添加到父item
的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 []]]