2016-01-17 18 views
6

Qual è lo scopo di avere Method#unbind e UnboundMethod#bind?Quale è lo scopo dei metodi di binding/unbind in Ruby?

Da quanto ho capito, i metodi sono oggetti richiamabili come proc e lambda, tranne che i metodi sono legati alla portata del loro ricevitore:

class SomeClass 
    def a_method; puts "from SomeClass"; end 
end 

s = SomeClass.new 
s.a_method # => "from SomeClass" 

posso chiamare a_method se sono all'interno del contesto di SomeClass o se ho un oggetto di SomeClass. Posso fare un oggetto richiamabile estraendo il metodo come un oggetto Method, eppure è ancora legato ad un oggetto della classe SomeClass in questo esempio:

m = s.method :a_method 
m.class # => Method 
m.owner # => SomeClass 
m.call # => "from SomeClass" 

Perché dovrei voler unbind un metodo dal suo ricevitore? Forse posso passare questo o bind a un oggetto diverso dandogli un nuovo contesto, forse posso avere un oggetto completamente diverso chiamare questo metodo senza ereditarietà, ma non posso fare nulla con esso a meno che non lo leghi a un oggetto del suo classe originaria o io convertirlo in un oggetto Proc (in realtà un lambda, dal momento che i metodi e lambda sono in qualche modo simile):

# Module#instance_method gives me an UnboundMethod 
ub = SomeClass.instance_method :a_method 
ub.class # -> UnboundMethod 

# now I can't make any calls 
ub.call # -> NoMethod Error, undefined method 'call' 

class AnotherClass; end 
a = AnotherClass.new 
b = ub.bind(a) # -> TypeError: bind argument must be an instance of SomeClass 
b = ub.bind(SomeClass.new).call # -> "from SomeClass" 

ho potuto convertire l'oggetto metodo in un proc e forse fare qualcosa con esso:

AnotherClass.class_eval do 
    # I can access m becausec this block is evaluated in the same 
    # scope it's defined, so I can grab m ;) 
    define_method(:method_from_some_class, m.to_proc) 
end 

AnotherClass.instance_methods(false) # -> [:method_from_some_class] 
a.method_from_some_class # -> "from SomeClass" 

Qual è lo scopo di questo? Quali sono le applicazioni del mondo reale per qualcosa di simile?

+0

Welp ... http://stackoverflow.com/questions/33708250/what-is-the-point-of-rubys-method-unbinding-mechanism – ndn

+1

Capisco cosa fanno, ma dirò che in 8 anni di programmazione di rubini, inclusa un'intelligente capacità di metaprorgrammo riflessivo, non ho mai dovuto usare 'bind' su un metodo non associato, o fatto molto con un metodo non associato. Sono raramente necessari. Ma bene che siano lì per un completo controllo riflessivo nel rubino. Se non stai vedendo un uso per loro però, è perché gli usi sono rari per cose difficili che saprai quando ne hai uno. Se fa parte della tua cassetta degli attrezzi giorno per giorno, probabilmente sei troppo intelligente. – jrochkind

risposta

6

È davvero utile per metaprogramming. Supponiamo di voler conoscere la posizione del codice sorgente per SomeClass#method. Se è possibile generare un'istanza di SomeClass, è possibile creare un'istanza del metodo (vincolato) su quell'istanza SomeClass, in cui è possibile chiamare vari metodi per esaminare alcuni metadati del metodo. Ma cosa succede se non conoscete la firma del metodo di SomeClass#new o se il metodo di costruzione di SomeClass è stato denominato diverso da SomeClass#new? Creare in modo sicuro un'istanza di SomeClass può essere difficile. È qui che il metodo non associato è utile. Senza preoccuparsi di una particolare istanza della classe o di come creare un'istanza, è sufficiente eseguire SomeClass.instance_method(:a_method) (che è un metodo non associato), quindi chiamare source_location per esaminare la posizione della definizione.

E quando sarebbe necessario questo tipo di metaprogrammazione nelle applicazioni del mondo reale? Un esempio è quando si crea un IDE con funzioni per la ricerca del metodo.