考虑以下code:
class Node
def initialize(name=nil)
@name = name
@children = []
end
def node(name, &block)
child = Node.new(name)
@children.push(child)
child.instance_exec(&block) if block
end
end
def tree(name, &block)
@tree = Node.new(name)
@tree.instance_exec(&block)
@tree
end
t = tree("Simpsons family tree") do
node("gramps") do
node("homer+marge") do
node("bart")
node("lisa")
node("maggie")
end
end
end
puts "tree = " + t.inspect
返回:
tree = #<Node:0x007fca1a103268 @name="Simpsons family tree", @children=[#<Node:0x007fca1a103128 @name="gramps", @children=[#<Node:0x007fca1a102fe8 @name="homer+marge", @children=[#<Node:0x007fca1a102ef8 @name="bart", @children=[]>, #<Node:0x007fca1a102e80 @name="lisa", @children=[]>, #<Node:0x007fca1a102e08 @name="maggie", @children=[]>]>]>]>
我想知道是否有可能进行更新,以便在不使用@children
共享阵列的情况下即时返回嵌入式数组阵列。我期待这个结果:
[
"Simpsons family tree",
[
"gramps",
[
"homer+marge",
[
"bart",
"lisa",
"maggie"
]
]
]
]
有可能吗?感谢您的任何建议。
修改
实际上,我想基本上使用相同的代码,但没有任何@children
实例。所以我想删除@children
。
编辑2:
经过一些测试后,这是我最好的结果:
class Node
def initialize(name=nil)
@name = name
end
def node(name, &block)
child = Node.new(name)
@sub = child.instance_exec(&block) if block
[
name,
@sub
].compact
end
end
def tree(name, &block)
@tree = Node.new(name)
[
name,
@tree.instance_exec(&block)
]
end
t = tree("Simpsons family tree") do
node("gramps") do
node("homer+marge") do
node("bart")
node("lisa")
node("maggie")
end
end
end
puts t.inspect
# => [
# "Simpsons family tree",
# [
# "gramps",
# [
# "homer+marge",
# [
# "maggie"
# ]
# ]
# ]
# ]
但是扁平节点仍然存在问题。因为Ruby只返回了最后一个。
答案 0 :(得分:0)
我的格式并不是你想要的,但这并不是真正重要的部分。
如果允许使用一组子节点初始化节点,则可以让node
方法在每次调用时返回一个新节点。
class Node
def self.new(*args, &block)
instance = super
if block
instance.instance_eval(&block)
else
instance
end
end
def initialize(name, children=[])
@name = name
@children = children
end
attr_reader :children, :name
def node(name, &block)
new_node = Node.new(name)
new_node = new_node.instance_eval(&block) if block
Node.new(self.name, next_children + [new_node])
end
def next_children
children.map{|child| Node.new(child.name, child.next_children) }
end
def inspect
return %{"#{name}"} if children.empty?
%{"#{name}", #{children}}
end
end
t = Node.new("Simpsons family tree") do
node("gramps") do
node("homer+marge") do
node("bart").
node("lisa").
node("maggie")
end
end
end
puts t.inspect
#=> "Simpsons family tree", ["gramps", ["homer+marge", ["bart", "lisa", "maggie"]]]
通过更改初始化和node
方法的行为,您可以在创建节点时累积它们。
我还冒昧地删除了你的tree
方法,因为它只是一个初始化节点的包装器,但这可能是一个带回格式化的地方。
我发现这篇文章正在寻找instance_exec
my Ruby DSL Handbook instance_exec
的好用例,但您可以使用instance_eval
或node
作为该块,因为您可以使用[t].inspect
不要传递任何论据。
编辑:我更新了每次返回新值的方法。更改要求将没有块的节点链接在一起,因为每个{{1}}调用都会返回一个新对象。块的返回值是一个新节点。
为了获得您想要的格式,您需要{{1}}