简体   繁体   中英

How to create this little DSL in Ruby?

My functions are:

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

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

I would like to temporarily augment a function within a block of my method.

In hello_scope , I simply want to prepend the scope string to the str before passing it to the original hello method. Here's an example:

hello 'world'               #=> hello world

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

I'm kind of a noob when it comes to this kind of thing in Ruby. Can someone help me solve this in an elegant way?


Edit:

If it makes things easier, it's OK if we pass the method in as an argument to the block, such as:

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

One way is to create a "evaluation context object" on which the block is going to be instance-eval'd. This object has to provide all the methods that are specific to the block. In the example below, I did not use the same name as I don't remember how to explicitly referring to the global method "hello" (to avoid infinite recursion). In a proper library, "hello" would be defined as a class method somewhere, so that would not be an issue.

For instance

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

Just modify your "hello" method to take into account current scope:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM