如何在Ruby中创建这个小DSL?

时间:2013-03-22 04:43:24

标签: ruby lambda dsl proc

我的职能是:

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

2 个答案:

答案 0 :(得分:4)

一种方法是创建一个“评估上下文对象”,块将在该对象上实例化。该对象必须提供特定于块的所有方法。在下面的示例中,我没有使用相同的名称,因为我不记得如何显式引用全局方法“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

答案 1 :(得分:0)

只需修改“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