使用Ruby将嵌入式块转换为嵌入式数组

使用Ruby将嵌入式块转换为嵌入式数组,ruby,dsl,Ruby,Dsl,考虑到以下几点: 它正在返回: tree = #<Node:0x007fca1a103268 @name="Simpsons family tree", @children=[#<Node:0x007fca1a103128 @name="gramps", @children=[#<Node:0x007fca1a102fe8 @name="homer+marge", @children=[#<Node:0x007fca1a102ef8 @name="bart", @chil

考虑到以下几点:

它正在返回:

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
实例。因此,我想删除
@子项

编辑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返回的。

我的格式不完全是您想要的,但这并不是真正重要的部分

如果允许使用子节点集合初始化节点,则可以让
节点
方法在每次调用时返回一个新节点

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"]]]
通过更改初始化和
节点
方法的行为,可以在创建节点时累积节点

我还冒昧地删除了您的
方法,因为它只是初始化节点的包装器,但这可能是恢复格式的地方

我在这篇文章中找到了一些很好地使用
instance\u exec
的例子,但是您可以对块使用
instance\u exec
instance\u eval
,因为您没有向它传递任何参数

编辑:我更新了每次返回新值的方法。更改要求将不带块的节点链接在一起,因为每个
节点
调用都返回一个新对象。块的返回值是一个新节点


为了获得所需的格式,您需要执行
[t]。检查

否,如果您不知道
@children
中的数组,则不可能。是的,您是对的@Luiggi。实际上,我想删除这个数组。我的问题不够清楚,我更新了它。您需要将节点的子节点存储在某个位置。为什么不使用
@children
?这是实例变量的一个非常合适的用法,因为从语义上讲,这个嵌入数组是一个值,而不是一个对象。它应该是不可变的,由它自己定义。所以,如果我们能通过初始化过程创建这样的数组,它是原子的,对我来说是完美的。
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"
#          ]
#        ]
#      ]
#    ]
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"]]]