2009-07-17 2 views
2
hinzufügen

Ich möchte eine Singleton-Methode zu einem bestimmten Objekt hinzufügen. Ich wünsche mir, dass wenn eine Instanzmethode für ein Objekt zuerst aufgerufen wird, sie etwas Arbeit leistet und dann eine Singleton-Methode für das gleichnamige Objekt (das die Arbeit enthält) erstellt. Bei allen nachfolgenden Aufrufen des Objekts würde die Singleton-Methode die Instanzmethode überschatten und würde aufgerufen werden.Ich möchte eine Singleton-Methode mit einer Schließung zu einem Ruby-Objekt

Ich weiß, wie man eine Singleton-Methode erstellen, mein Problem ist, dass ich die Singleton-Methode erstellen möchte, um ein Lambda (l in diesem Fall) aufzurufen. def erzeugt keine Schließung, daher kann ich die Variable l (Code unten) nicht referenzieren, wenn die Methode anschließend aufgerufen wird (l.call() ist in diesem Beispiel auskommentiert). Ich möchte wissen, wie ich eine Schließung beim Erstellen einer Singleton-Methode für eine bestimmte erstellen kann Objekt. Jede Hilfe wäre willkommen. Vielen Dank.

class Thing 
end 

t = Thing.new 
t2 = Thing.new 

Thing.instance_eval() do 
    def speak 
    puts "I speak for all Things, I am a class method" 
    end 
end 

Thing.class_eval() do 
    def speak 
    puts "This is the instance method referenced by the Thing object #{self}" 
    r = "something I wish to hold on to, maybe expensive to calculate" 
    l = lambda {puts r} 
    instance_eval() do 
     def speak() 
     puts "This is the singleton method in the Thing object #{self}" 
     #l.call() # I want this to work! How? 
     end 
    end 
    end 
end 

Thing.speak() 
t.speak() 
t2.speak() 
t.speak() 
t2.speak() 

liefert folgende Ergebnisse bei der Ausführung: (I geändert '<' auf '#', so dass sie in HTML angezeigt)

ich für alle Dinge sprechen, ich bin eine Klasse Methode

Diese

ist die Instanz-Methode verwiesen vom Thing Objekt #Thing: 0x1d204>

Dies ist die Instanz-Methode verwiesen durch das Ding Objekt #Thing: 0x1d1dc>

Dies ist die Singleton-Methode im Sache Objekt #Thing: 0x1d204>

Dies ist die Singleton-Methode im Sache Objekt #Thing: 0x1d1dc>

Antwort

2

Sie können eine Methode mit einem Block unter Verwendung von define_method definieren.

Beispiel:

class Object 
    def eigenclass 
    class <<self; self end 
    end 
end 

a = "Hello" 
other_word = "World" 
a.eigenclass.class_eval do 
    define_method(:cliche) {"#{self} #{other_word}"} 
end 
a.cliche # => "Hello World" 
"Goodbye".cliche # => NoMethodError: undefined method `cliche' for "Goodbye":String 

Hier ist eine Implementierung einer define_singleton_method Methode:

class Object 
    def define_singleton_method(name, &block) 
    eigenclass = class<<self; self end 
    eigenclass.class_eval {define_method name, block} 
    end 
end 
+0

Ja, sehen das Problem scheint, dass define_method zu sein, ist ein Modul/Klasse Modul-Methode. Ich brauche ein define_method ähnliches Ding für irgendein Objekt. Die Methode, die Sie dort definiert haben, definiert eine Instanzmethode für alle Ojekte. Ich suche nach einer Möglichkeit, dynamisch (mit Closures) Methoden für einzelne Objekte zu definieren (Singular), nicht Instanzmethoden für alle Objekte einer bestimmten Klasse. Vielen Dank. –

+0

Nein, es definiert keine Methode für alle Objekte. Es definiert eine Singleton-Methode. Ich habe den Beispielcode aktualisiert, um dies zu veranschaulichen. – Chuck

+0

Ok, ich habe eine Permutation dieses Codes ausprobiert, und es scheint zu funktionieren. Ich muss sagen, ich hätte nie gedacht, dass ich den "class << self; self end" Trick machen würde, das war ziemlich cool. Anywho, das scheint eine funktionierende Lösung für das Problem zu sein, Singleton-Methoden für Ruby-Objekte zu erstellen. Vielen Dank. –

1

Nun, eine Möglichkeit, es zu tun wäre, es in eine Instanz Variable zu packen:

(FYI können Sie einfach class Thing wieder öffnen Thing (es ist ein wenig kürzer als mit #class_eval, und Sie brauchen nicht #instance_eval um Methoden innerhalb einer Methode zu definieren).

class Thing 
    def speak 
    puts "This is the instance method referenced by the Thing object #{self}" 
    r = "something I wish to hold on to, maybe expensive to calculate" 
    @l = lambda {puts r} 
    instance_eval do 
     def speak() 
     puts "This is the singleton method in the Thing object #{self}" 
     @l[] 
     end 
    end 
    end 
end 

Dies wird #speak, neu zu definieren, sondern nur für die Instanz von Thing. Andere Instanzen von Thing haben immer noch die ursprüngliche Definition.

Die Alternative ist, wie Chuck darauf hingewiesen hat, die der Instanz zugeordnete Singleton-Klasse (auch bekannt als Metaklasse, auch bekannt als Eigenklasse) zu verwenden. Die Singleton-Klasse ist das Objekt, das alle Singleton-Methoden speichert, die einem Objekt zugeordnet sind. Sie können den Kontext für die Singleton-Klassenauswertung abrufen, indem Sie die komische class <<object ; ... ; end-Syntax verwenden (ähnlich dem Kontext, der von #class_eval durch normale Klassen angegeben wird).

class Thing 
    def speak 
    puts "This is the instance method referenced by the Thing object #{self}" 
    r = "something I wish to hold on to, maybe expensive to calculate" 
    singleton_class = class <<self # open singleton class context for current instance 
     # in this context, self now refers to the singleton class itself 
     self 
    end 
    l = lambda {puts r} 
    singleton_class.class_eval do 
     # since we used #class_eval, local variables are still in scope 
     define_method(:speak) do 
     puts "This is the singleton method in the Thing object #{self}" 
     # since we used #define_method, local variables are still in scope 
     l[] 
     end 
    end 
    end 
end 
2

Jetzt, 1.9 out ist, können Sie define_singleton_method:

jruby --1.9 -S irb 
irb(main):019:0> fn = -> { length * 10 } 
=> #<Proc:[email protected](irb):19 (lambda)> 
irb(main):020:0> s.define_singleton_method :length_times_ten, fn 
=> #<Proc:[email protected](irb):19 (lambda)> 
irb(main):021:0> s 
=> "a string" 
irb(main):022:0> s.length_times_ten 
=> 80 
Verwandte Themen