在Ruby中传递的块中引用调用对象

有没有办法在被调用的块中获取被调用的对象。 例如,是否有任何方法可以让块访问方法batman或类SuperHeros

 class SuperHeros attr_accessor :news def initialize @news = [] end def batman task puts "Batman: #{task} - done" yield "feed cat" @news << task end end cat_woman = lambda do |task| puts "Cat Woman: #{task} - done" # invoker.news << task end robin = lambda do |task| puts "Robin: #{task} - done" # invoker.news << task end characters = SuperHeros.new characters.batman("kick Joker's ass", &cat_woman) characters.batman("break Bane's bones", &robin) 

您可以使用类似于Instance eval和委托模式的东西,例如,在Savon gem中使用 –

 def batman(task, &block) @original_self = eval('self', block.binding) puts "Batman: #{task} - done" instance_exec('feed cat', &block) @news << task end private def method_missing(method, *args, &block) if @original_self @original_self.send(method, *args, &block) else super end end 

在这种方法中,当你在传递给batman方法的块内调用方法(带隐式接收器)时,它会在SuperHeros实例的上下文中调用。 如果没有这样的方法可用,则调用(通过method_missing )到原始块self

在块中获取接收器对象的最简单方法是将对象分配给实例变量。

这个例子更清楚地说明了lambdas cat_woman和robin如何访问块的接收器对象的属性:

 class SuperHeros attr_accessor :news, :name, :current_task def initialize(a_name) @name = a_name @news = [] end def batman(task) puts "Inside the method batman of #{name}: #{task} in progress ..." @current_task = task yield @news << task end end cat_woman = lambda do |extra_task| puts "cat_woman even #{extra_task} before doing #{@caller_obj.current_task}" puts "Cat Woman: #{@caller_obj.current_task} - done by #{@caller_obj.name}" # invoker.news << task end robin = lambda do |extra_task| puts "robin even #{extra_task} before doing #{@caller_obj.current_task}" puts "Robin: #{@caller_obj.current_task} - done by #{@caller_obj.name}" end character_1 = SuperHeros.new('batman_1') (@caller_obj = character_1).batman("kick Joker's ass") { cat_woman['eats some burger'] } puts character_2 = SuperHeros.new('batman_2') (@caller_obj = character_2).batman("break Bane's bones") { robin['drinks some beer'] } 

输出将是:

 Inside the method batman of batman_1: kick Joker's ass in progress ... cat_woman even eats some burger before doing kick Joker's ass Cat Woman: kick Joker's ass - done by batman_1 Inside the method batman of batman_2: break Bane's bones in progress ... robin even drinks some beer before doing break Bane's bones Robin: break Bane's bones - done by batman_2