从Ruby中块内的一系列调用返回
我有一段类似DSL的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()方法时,都会实例化一个日志对象(在幕后),并将块传递给该方法(该块传递给日志对象的构造函数)。我的问题是,有没有一
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。。。结束
和工作完成。。。通过显式方法结束
,甚至在为活动调用的实例上结束
。