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.