Ссылаться на вы вызывающий объект в пройденном блоке в Ruby

StackOverflow https://stackoverflow.com/questions/19834086

  •  25-07-2022
  •  | 
  •  

Вопрос

Есть ли способ завладеть вызванным объектом внутри блока, который называется. Например, есть ли способ для блоков получить доступ к объему метода 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)
Это было полезно?

Решение

Вы можете использовать что -то похожее на Экземпляр Eval с делегированием шаблон, используемый - например, в Савон драгоценный камень:

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top