【问题标题】:How to create this little DSL in Ruby?如何在 Ruby 中创建这个小 DSL?
【发布时间】:2013-03-22 04:43:23
【问题描述】:

我的职能是:

def hello(str)
  puts "hello #{str}"
end

def hello_scope(scope, &block)
  # ???
end

我想在我的方法块中临时增加一个函数。

hello_scope 中,我只想将scope 字符串添加到str,然后再将其传递给原始hello 方法。这是一个例子:

hello 'world'               #=> hello world

hello_scope "welcome!" do
  hello 'bob'               #=> welcome!hello bob
  hello 'alice'             #=> welcome!hello alice
end

当谈到 Ruby 中的这种事情时,我是个菜鸟。有人可以帮我以优雅的方式解决这个问题吗?


编辑:

如果它使事情变得更容易,如果我们将方法作为参数传递给块就可以了,例如:

hello_scope "welcome!" do |h|
  h "bob"                     #=> welcome!hello bob
  h "alice"                   #=> welcome!hello alice
end

【问题讨论】:

  • 如果不重写 hello 方法,您可能无法很好地做到这一点。
  • @AndrewMarshall 我进行了编辑;这会让事情变得更可行吗?

标签: ruby lambda dsl proc


【解决方案1】:

一种方法是创建一个“评估上下文对象”,块将在该对象上进行实例评估。该对象必须提供特定于块的所有方法。在下面的示例中,我没有使用相同的名称,因为我不记得如何显式引用全局方法“hello”(以避免无限递归)。在适当的库中,“hello”将在某处定义为类方法,因此这不是问题。

例如

def hello(str)
  puts "hello #{str}"
end
class HelloScope
  def h(str)
    print scope
    hello(str)
  end
end
def hello_scope(scope, &block)
  HelloScope.new(scope).instance_eval(&block)
end

【讨论】:

    【解决方案2】:

    只需修改您的“hello”方法以考虑当前范围:

    class Greeter
      def initialize
        @scope = nil
      end
    
      def hello(str)
        puts "#{@scope}hello #{str}"
      end
    
      def with_scope(scope)
        @scope = scope
        yield
        @scope = nil
      end
    end
    
    Greeter.new.instance_eval do
      hello 'world'               #=> hello world
    
      with_scope "welcome!" do
        hello 'bob'               #=> welcome!hello bob
        hello 'alice'             #=> welcome!hello alice
      end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-25
      • 2018-02-17
      • 1970-01-01
      • 2010-12-19
      相关资源
      最近更新 更多