【问题标题】:Refactoring to no block parameters in a Ruby internal DSL在 Ruby 内部 DSL 中重构为无块参数
【发布时间】:2012-06-29 22:01:18
【问题描述】:

我有一个看起来像这样的小 DSL:

ActivityLogger.log do
  activity('27-06-2012') do
    eat do |act|
     act.duration = 15
     act.priority = 5
    end
  end
end

我想重构它,让它丢失最里面的块中的块参数,所以它看起来像这样:

ActivityLogger.log do
  activity('27-06-2012') do
    eat do
     duration = 15
     priority = 5
    end
  end
end

#eat 方法实例化一个 Log 对象:

def eat(&block)
  @logs << Log.new(Eat, &block)
end

Log 的构造函数在最后一行产生self

def initialize(activity, &block)
  @activity = activity
  yield self
end

在我看来,这就是问题所在。我已经尝试在#eat 方法中使用instance_eval(请参阅下面的链接#2)并从Log 的构造函数中完全删除yield 语句(链接#3),但是这些方法都不起作用(Log 对象已创建,但未设置其 #duration#priority 方法)。

以下是链接:

1) A working DSL with block parameters

2) Non-working DSL, first refactoring attempt

3)Non-working DSL, second refactoring attempt

谢谢!

【问题讨论】:

标签: ruby codeblocks dsl yield


【解决方案1】:

duration = 15 并没有像你期望的那样调用setter 方法,而是定义了一个局部变量duration。您必须通过self.duration = 15 显式调用设置器或实现您的设置器,如

def duration(value)
  @duration = value
end

并致电duration 15

【讨论】:

  • 当我将duration = 15 与块参数一起使用时,它确实按预期设置了值。这些方法在 Log 类中被声明为 attr_accessor,并且可以像在 ActivityLogger#report 方法中一样通过检查它们来查看值。
  • 你打电话给act.duration = 15,而不仅仅是duration = 15
  • 是的。当我打电话给duration = 15 时,什么都没有发生——这就是这个线程的重点。
  • 这是因为duration = 15定义了一个变量,就像i = 1一样
  • @user906230:Stefan 是对的,在编写 DSL 时,您可以使用 something.xyz = 1xyz 1xyz = 1总是创建一个局部变量,这就是 Ruby 中作用域的工作原理。
猜你喜欢
  • 1970-01-01
  • 2017-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-20
  • 1970-01-01
相关资源
最近更新 更多