【问题标题】:Ruby DSL - invoking user-provided methods within block contextRuby DSL - 在块上下文中调用用户提供的方法
【发布时间】:2017-08-09 22:11:53
【问题描述】:

我的 Ruby DSL 的用户希望能够添加其他方法并在任意块的上下文中调用它们,例如:

def do_something
  override 'flags', 'ABC'        
end

project('XXX') do
  configuration('debug') do
    do_something
  end
end

在此示例中,“覆盖”是使用 instance_eval 调用的配置对象的方法。

有没有办法强制在配置块的上下文中执行任何方法调用,以便例如可以解析和执行“覆盖”?

[编辑]

所以我构造了根 DSL 对象并评估如下:

root_dsl = DSL.new
root_dsl.instance_eval(File.read(filename))

这个 DSL 类有一个方法匹配上面示例中的“项目”:

def project(&block) do
    project_dsl = ProjectDSL.new
    project_dsl.instance_eval(&block)
end

并且 project_dsl 类有一个方法匹配上面示例中的“配置”:

def configuration(name, &block) do
   configuration_dsl = ProjectConfigDSL.new(name)
   configuration_dsl.instance_eval(&block)
end

等等。用户希望自己在 DSL 文件中定义的方法在 ProjectConfigDSL 对象的上下文中执行。

【问题讨论】:

  • 您愿意分享 DSL 实现本身吗?
  • @mudasobwa 我已按要求添加了进一步的实施细节

标签: ruby instance-eval


【解决方案1】:

所以我不知道 instance_eval 沙箱的作用域是那个实例,所以我必须做的是从根 DSL 对象委托直接执行块并将missing_method 中的调用转发到子 DSL 对象,然后重复这个模式一路下来。

通过这样做,它修复了范围问题,但它确实会导致冲突方法名称被转发到错误对象的新问题。幸运的是,我的 DSL 还没有遇到这个问题,所以现在已经足够了。

【讨论】:

    【解决方案2】:

    我在自己的代码中这样做的方式是让帮助函数返回一个传递给 instance_eval 的过程。例如:

    def do_something
      Proc.new do
        override 'flags', 'ABC'
      end        
    end
    
    project('XXX') do
      configuration 'debug', &do_something
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-12
      • 2010-11-16
      • 1970-01-01
      • 2019-11-17
      相关资源
      最近更新 更多