Frage

Ich möchte einem bestimmten Objekt eine Singleton -Methode hinzufügen. Ich wünschte, wenn eine Instanzmethode auf einem Objekt zum ersten Mal aufgerufen wird, funktioniert sie und erstellt dann eine Singleton -Methode für das gleichnamige Objekt (das die Arbeit enthält). Bei allen nachfolgenden Aufrufen des Objekts würde die Singleton -Methode die Instanzmethode beschatten und aufgerufen werden.

Ich weiß, wie man eine Singleton -Methode erstellt. Mein Problem ist, dass ich möchte, dass die Singleton -Methode eine Lambda aufruft (l in diesem Fall). DEF erstellt keinen Verschluss, daher kann ich keine Variable L (Code unten) referenzieren, wenn die Methode anschließend aufgerufen wird (((l.call() wird in diesem Beispiel kommentiert) Ich möchte wissen, wie ich beim Erstellen einer Singleton -Methode für ein bestimmtes Objekt einen Verschluss schaffen kann. Jede Hilfe wäre geschätzt. 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()

Gibt die folgenden Ergebnisse beim Ausführen: (Ich habe '<' zu '#' geändert, damit sie in HTML auftauchen)

Ich spreche für alle Dinge, ich bin eine Klassenmethode

Dies ist die Instanzmethode, auf die Objekt #Thing: 0x1d204> verwiesen wird

Dies ist die Instanzmethode, auf die Objekt #Thing: 0x1d1dc> verwiesen wird

Dies ist die Singleton -Methode in dem Ding -Objekt #Thing: 0x1d204>

Dies ist die Singleton -Methode in dem Ding -Objekt #Thing: 0x1d1dc>

War es hilfreich?

Lösung

Sie können eine Methode mit einem Block verwenden define_method.

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 von a 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

Andere Tipps

Jetzt, da 1.9 ausgefallen ist, können Sie define_singleton_method verwenden:

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

Eine Möglichkeit, es zu tun, wäre, es in eine Instanzvariable zu packen:

(FYI können Sie einfach tun class Thing aufgerissen Thing (Es ist etwas kürzer als verwendet #class_eval, und du brauchst nicht #instance_eval Methoden aus einer Methode 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 neu definieren #speak, aber nur für diesen Fall von Thing. Andere Fälle von Thing wird noch die ursprüngliche Definition haben.

Die Alternative ist, wie Chuck betonte, die mit der Instanz verbundene Singleton -Klasse (auch bekannt als Metaclass, auch bekannt als Eigenklass) zu verwenden. Die Singleton -Klasse ist das Objekt, das alle mit einem Objekt verknüpften Singleton -Methoden speichert. Sie können den Kontext für die Singleton -Klasse -Bewertung erhalten, indem Sie die lustigen verwenden class <<object ; ... ; end Syntax (ähnlich dem Kontext von gegeben durch #class_eval durch normale Klassen).

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top