从Ruby中块内的一系列调用返回

从Ruby中块内的一系列调用返回,ruby,Ruby,我有一段类似DSL的Ruby代码,如下所示: Activity.new('20-06-2012') do Eat.log do |l| l.duration = 0.30 l.priority = 5 end Work.log do |l| l.duration = 2 l.priority = 3 end end 每次调用log()方法时,都会实例化一个日志对象(在幕后),并将块传递给该方法(该块传递给日志对象的构造函数)。我的问题是,有没有一

我有一段类似DSL的Ruby代码,如下所示:

Activity.new('20-06-2012') do
  Eat.log do |l|
    l.duration = 0.30
    l.priority = 5
  end
  Work.log do |l|
    l.duration = 2
    l.priority = 3
  end
end
每次调用log()方法时,都会实例化一个日志对象(在幕后),并将块传递给该方法(该块传递给日志对象的构造函数)。我的问题是,有没有一种方法可以收集log()方法的所有返回?在上面的示例中,最外层块的返回值是对log()的最后一次调用。但是我想在一个数组中得到所有调用的结果,而不仅仅是最后一个


谢谢

使用
return
,用逗号分隔每个块

Activity.new('20-06-2012') do
  return_value = Eat.log do |l|
    l.duration = 0.30
    l.priority = 5
  end, Work.log do |l|
    l.duration = 2
    l.priority = 3
  end
return return_value #redundant
end

当您返回多个用逗号分隔的值时,Ruby会将它们连接到一个数组中。

安德烈的方法会起作用,但可读性不强。如果你在一个月左右的时间里回顾它,很难发现隐藏在里面的逗号

就我个人而言,我会让数组集合更加明确:

Activity.new('20-06-2012') do
  logs = []
  logs << Eat.log do |l|
    l.duration = 0.30
    l.priority = 5
  end
  logs << Work.log do |l|
    l.duration = 2
    l.priority = 3
  end
  logs
end
Activity.new('20-06-2012')做什么
日志=[]

logs块的最后一条语句始终是返回值。如果不想强制用户将
l
作为块中的最后一条语句写入,则应使用对
l
实例(无论是什么)所做的修改,而不是块返回值。另一个选项是更改
l
对象的setter行为,以返回赋值时所有值的数组-但我将使用第一个选项,根据您的代码,它可能如下所示:

class Log
  attr_accessor :duration, :priority
  def initialize(block)
    block.call(self)
  end
end

Log.new proc{ |l| l.duration = 0.3; l.priority = 5 }
# => #<Log:0x000000029d8030 @duration=0.3, @priority=5>
Activity.new('20-06-2012') do
  logs = {
    Eat => {:duration => 0.30, :priority => 5},
    Work => {:duration => 2, :priority => 3}
  }

  logs.map do |log_type, log_data|
    log_type.log do |l|
      l.duration = log_data[:duration]
      l.priority = log_data[:priority]
    end
  end
end
activity '20-06-2012' do
  log :eat do
    duration 0.30
    priority 5
  end
  log :work do
    duration 2
    priority 3
  end
end
类日志
属性访问器:持续时间,优先级
def初始化(块)
阻塞呼叫(自我)
结束
结束
Log.newproc{| l | l.duration=0.3;l.priority=5}
# => #
如果(且仅当)您的日志结构简单且一致,您就可以这样做:

class Log
  attr_accessor :duration, :priority
  def initialize(block)
    block.call(self)
  end
end

Log.new proc{ |l| l.duration = 0.3; l.priority = 5 }
# => #<Log:0x000000029d8030 @duration=0.3, @priority=5>
Activity.new('20-06-2012') do
  logs = {
    Eat => {:duration => 0.30, :priority => 5},
    Work => {:duration => 2, :priority => 3}
  }

  logs.map do |log_type, log_data|
    log_type.log do |l|
      l.duration = log_data[:duration]
      l.priority = log_data[:priority]
    end
  end
end
activity '20-06-2012' do
  log :eat do
    duration 0.30
    priority 5
  end
  log :work do
    duration 2
    priority 3
  end
end

您需要自己决定这是否适合您的结构,以及它是否具有足够的可读性

您的内部DSL仍然太像Ruby,您可以对其进行重构,使其看起来像这样:

class Log
  attr_accessor :duration, :priority
  def initialize(block)
    block.call(self)
  end
end

Log.new proc{ |l| l.duration = 0.3; l.priority = 5 }
# => #<Log:0x000000029d8030 @duration=0.3, @priority=5>
Activity.new('20-06-2012') do
  logs = {
    Eat => {:duration => 0.30, :priority => 5},
    Work => {:duration => 2, :priority => 3}
  }

  logs.map do |log_type, log_data|
    log_type.log do |l|
      l.duration = log_data[:duration]
      l.priority = log_data[:priority]
    end
  end
end
activity '20-06-2012' do
  log :eat do
    duration 0.30
    priority 5
  end
  log :work do
    duration 2
    priority 3
  end
end

现在捕获
实例中的调用,并在内部数组中累积值,这是DSL常用的东西。

创建一个新对象,
ActivityLog
或其他任何东西,并将其从
Activity
初始值设定项传递到块

Activity.new('20-06-2012') do |log|
  log.eat do |l|
    l.duration = 0.30
    l.priority = 5
  end
  log.work do |l|
    l.duration = 2
    l.priority = 3
  end
end
如果您只有少数日志类型,只需将它们添加到
ActivityLog
ActivityLog#eat
ActivityLog#work
)中即可。初始化相应的对象(
Eat
Work
),并使用收到的块调用其log方法

下一步,您可以将它们添加到数组中,并在
ActivityLog#initialize
中对其进行迭代,然后动态创建每个方法

惰性方法是让
ActivityLog
拥有一个
方法\u missing
,该方法接受任何方法,将其转换为类常量,然后执行上述步骤。这是不好的,因为它通常会使调试变得更加困难。如果在对象上调用与记录器不对应的方法,并且不能对该对象调用
方法
,并查看列出的方法,则可能会出现误导性的异常


希望这能有所帮助。

这样,我就必须将类方法转换为实例方法,并使用
实例评估
——我本来打算在后面的步骤中这样做,但现在不妨这样做。谢谢@用户906230:没错。如果目标是Ruby程序员,那么可以使用带参数的块、
new
,等等,但是非程序员将很难理解它。+1对于我要建议的DSL修改:)即使是针对程序员,用这种方式在Ruby中也更惯用。甚至:
eat do。。。结束
工作完成。。。通过显式方法结束
,甚至在为活动调用的实例上结束