Question

Existe-t-il un moyen de saisir l'objet invoqué à l'intérieur du bloc qui est appelé. Par exemple, y a-t-il un moyen pour les blocs d'accéder à la portée de la méthode batman ou la classe 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)
Était-ce utile?

La solution

Vous pouvez utiliser quelque chose de similaire à Instance Eval avec délégation motif, utilisé - par exemple - dans Savon gemme:

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

Dans cette approche, lorsque vous appelez la méthode (avec un récepteur implicite) à l'intérieur du bloc passé dans batman Méthode, cela s'appelle dans le contexte de SuperHeros exemple. S'il n'y a pas de méthode de ce type, l'appel passe (à travers method_missing) au bloc d'origine self.

Autres conseils

Le moyen le plus simple d'obtenir l'objet récepteur à l'intérieur d'un bloc consiste à attribuer l'objet à une variable d'instance.

Cet exemple illustre plus clairement comment la Lambdas Cat_woman et Robin peuvent accéder aux attributs des objets récepteurs des blocs:

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'] }

La sortie sera:

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top