2010-04-24 19 views

risposta

6

Come opzione, è disponibile un binding_of_caller gem che consente di eseguire il codice nel contesto di qualsiasi chiamante nello stack di chiamate (chiamante, chiamante del chiamante e così via). È utile per l'ispezione (leggi fare qualcosa in qualsiasi posizione sullo stack di chiamate) stack di chiamate in fase di sviluppo, come utilizzato in better_errors.

Gli oggetti della classe Binding incapsulano il contesto di esecuzione in un punto particolare del codice e mantengono questo contesto per uso futuro.

http://www.ruby-doc.org/core-2.1.4/Binding.html

Dovrei citare, questa tecnica dovrebbe essere utilizzato solo per il debug, divertimento o scopi educativi, perché viola i principi della programmazione orientata agli oggetti davvero male.
Principalmente a causa di eval.

Prepariamo roba:

require 'binding_of_caller' # I assume, you installed this gem already? 

Prendi il immediato (più vicino sulla pila, quindi 0) istanza chiamante :

binding.of_caller(0).eval('self') 

...o anche un metodo chiamante immediato:

binding.of_caller(0).eval('__method__') 

Se avete bisogno di ottenere più in alto lo stack di chiamate, utilizzare numeri diversi da 0 per ottenere vincolante di un chiamante.

Terribilmente hacky. Ma se hai davvero bisogno di questo — vai.

1

Intendi come self?

irb> class Object 
    .. def test 
    ..  self 
    .. end 
    .. end 
    => nil 
irb> o = Object.new 
    => #<Object:0xb76c5b6c> 
irb> o.test 
    => #<Object:0xb76c5b6c> 
+17

++ Amico, questo è semplicemente meraviglioso come che sembra come una Z – Pierreten

+0

stilizzata ho letto la domanda che all'interno del tuo 'test()' OP vuole ottenere l'oggetto che si ottiene se si digita 'self' in irb. – lulalala

12

Si può facilmente osservare la riga di codice che ha chiamato la funzione di interesse attraverso

caller.first 

che vi dirà il numero nome del file e la linea che ha chiesto la relativa funzione. Potresti quindi calcolare di nuovo quale oggetto era.

Tuttavia, sembra che tu stia di più dopo un oggetto che ha chiamato una determinata funzione, magari all'interno di un metodo di istanza. Non sono a conoscenza di un metodo per capirlo - ma non lo userei comunque, dal momento che sembra violare l'incapsulamento male.

+1

Questo è davvero un buon punto, passerò semplicemente l'oggetto chiamante L'idea era di semplificare alcuni degli argomenti a un metodo, riflettendo automaticamente alcune informazioni sull'oggetto chiamante. –

+1

beh, idealmente, se è più di una volta, dovrebbe essere un metodo in una superclasse, e puoi usare 'self '. – Peter

2

Tecnologia al suo meglio:

1 # phone.rb 
2 class Phone 
3 def caller_id 
4  caller 
5 end 
6 end 
7 
8 class RecklessDriver 
9 def initialize 
10  @phone = Phone.new 
11 end 
12 def dial 
13  @phone.caller_id 
14 end 
15 end 
16 
17 p = Phone.new 
18 p.caller_id.inspect # => ["phone.rb:18:in `<main>'"] 
19 
20 macek = RecklessDriver.new 
22 macek.dial.inspect # => ["phone.rb:13:in `dial'", "phone.rb:22:in `<main>'"] 

Nota: numero linea a scopo dimostrativo.phone.rb:X fa riferimento alla riga X dello script.

Vedere phone.rb:13! Questo metodo dial è ciò che ha inviato la chiamata! E phone.rb:22 si riferisce al driver spericolato che ha utilizzato il metodo dial!

1

Pietro answer utilizzato nel codice di esempio la produzione

Nella mia azienda ci sono stati deprecando deleted bandiera nel sapore di Paranoia gemdeleted_at colonna. Il soffietto codice è come siamo stati assicurando tutto andrà bene prima togliamo colonna (distribuzione di questo codice e poi dopo 2 o 3 giorni di essere in diretta schieriamo migrazione remoove_column :lessons, :deleted

class Lesson < ActiveRecord::Base 

    def deleted 
    if caller.select { |c| c.match /serialization\.rb/ }.any? 
     # this is Rails object mapping 
     !!deleted_at 
    else 
     raise 'deplicated - deleted was replaced by deleted_at' 
    end 
    end 
end 
Problemi correlati