Gibt es eine alias_method für eine Klassenmethode?

10

Betrachten Sie die folgende Klasse:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method
end

Dies ist kein Problem und Sie können Foo.new.a_new_inst_methodohne Probleme anrufen .

Ich hätte gerne die Möglichkeit, eine Klassenmethode wie Foo.add_widget(*items)und einen Alias ​​zu haben, damit ich so etwas tun kann:

Foo.add_widget 'item1'
Foo.add_widgets 'item2', 'item3'

Im Wesentlichen hat es also einen "Ruby-Stil" wie 1.minuteund 2.minutesso möchte ich einen Alias ​​eines Foo.add_widgetso aufrufenden Aufrufs Foo.add_widgetsgenau der gleichen Methode. Ich weiß, dass ich es einpacken könnte, aber ich denke, ich sollte dies sauberer tun können.

Betrachten Sie meinen Versuch, so etwas zu versuchen:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method
  alias_method :a_new_class_method, :a_class_method
end

Ich erhalte jedoch den folgenden Fehler:

NameError (undefined method `a_class_method' for class `Foo')

Es sieht also so aus, als würde dies für Klassenmethoden nicht funktionieren. Wie mache ich das?

aarona
quelle

Antworten:

9

alias_methodAliase eine Instanzmethode des Empfängers. Klassenmethoden sind tatsächlich Instanzmethoden, die für die Singleton-Klasse einer Klasse definiert sind.

class MyClass
  def self.a
    "Hello World!"
  end
end

method_1 = MyClass.method(:a).unbind
method_2 = MyClass.singleton_class.instance_method(:a)

method_1 == method_2
#=> true

Um eine in der Singleton-Klasse definierte Instanzmethode als Alias ​​zu verwenden, können Sie sie entweder mithilfe der class << objectSyntax öffnen .

class << MyClass
  alias_method :b, :a
end

MyClass.b
#=> "Hello World!"

Oder Sie können mit der singleton_classMethode direkt darauf verweisen .

MyClass.singleton_class.alias_method :c, :a

MyClass.c
#=> "Hello World!"

Wenn Sie sich noch im Klassenkontext befinden, selfwird auf die Klasse verwiesen. Das Obige könnte also auch geschrieben werden als:

class MyClass
  class << self
    def a
      "Hello World!"
    end
    alias_method :b, :a
  end
end

Oder

class MyClass
  def self.a
    "Hello World!"
  end
  singleton_class.alias_method :c, :a
end

Oder eine Kombination aus beiden.

3limin4t0r
quelle
5

Sie können Klassenmethoden und ihre alias_methodAufrufe in ein separates Modul einbinden und dieses Modul über Folgendes in Ihre Klasse integrieren extend:

class Foo
  def an_inst_method
    'instance method'
  end
  alias_method :a_new_inst_method, :an_inst_method

  module ClassMethods
    def a_class_method
      'class method'
    end
    alias_method :a_new_class_method, :a_class_method
  end

  extend ClassMethods
end
Stefan
quelle
Hallo! Ich habe die extend ClassMethodsLösung vergessen . +1
aarona
4

Es ist wichtig zu verstehen, dass es in Ruby keine Klassenmethode gibt .

Eine Klassenmethode ist eigentlich nur eine Singleton-Methode. Klassenmethoden haben nichts Besonderes. Jedes Objekt kann Singleton-Methoden haben. Wir nennen sie einfach "Klassenmethoden", wenn das Objekt eine ist, Classweil die "Singleton-Methode einer Instanz von Class" zu lang und unhandlich ist.

Warten! Habe ich "Singleton-Methode" gesagt?

Ein weiterer wichtiger Punkt ist, dass es in Ruby keine Singleton-Methode gibt .

Eine Singleton-Methode ist eigentlich nur eine normale, langweilige alte Instanzmethode der Singleton-Klasse. Singleton-Methoden haben nichts Besonderes. Sie sind nur Instanzmethoden wie jede andere Instanzmethode.

Tatsächlich verfügt Ruby nur über Instanzmethoden. Keine Funktionen, keine Konstruktoren, keine statischen Methoden, keine Klassenmethoden, keine Modulfunktionen, keine Singleton-Methoden.

Die Frage ist nicht "Ist dies eine Klassenmethode, ist dies eine Singleton-Methode ?" , Sondern "In welchem Modul ist diese Methode definiert?"

"Singleton-Methoden" sind wirklich Instanzmethoden, die in der Singleton-Klasse definiert sind. Die Syntax für den Zugriff auf die Singleton-Klasse von foolautet

class << foo
end

Es gibt auch eine Methode, Object#singleton_classdie die Singleton-Klasse eines Objekts zurückgibt.

Warum hämmere ich so aggressiv auf die Tatsache ein, dass jede Methode eine Instanzmethode ist und dass Klassenmethoden nicht existieren? Weil es bedeutet, dass Rubys Objektmodell viel einfacher ist, als die Leute denken! Schließlich zeigen Sie in Ihrer Frage bereits, dass Sie wissen, wie Instanzmethoden aliasisiert werden, aber Sie sagen, dass Sie nicht wissen, wie Klassenmethoden aliasisiert werden. Aber das ist falsch! Sie wissen , wie man Klassenmethoden aliasisiert, da es sich nur um Instanzmethoden handelt . Wenn Ihnen diese Tatsache richtig beigebracht worden wäre, hätten Sie diese Frage niemals stellen müssen!

Sobald Sie verstehen, dass jede Methode eine Instanzmethode ist und dass das, was wir "Singleton-Methoden" nennen, nur Instanzmethoden der Singleton-Klasse sind, wird die Lösung klar:

singleton_class.alias_method :a_new_class_method, :a_class_method

Hinweis: Als ich oben schrieb, dass "es kein X gibt", meinte ich, dass "es in der Ruby-Sprache kein X gibt ". Das bedeutet nicht , dass diese Konzepte in der Ruby-Community nicht existieren .

Wir sprechen regelmäßig über "Singleton-Methoden" und "Klassenmethoden", einfach weil es einfacher ist, als über "Instanzmethoden der Singleton-Klasse" oder "Instanzmethoden der Singleton-Klasse eines Objekts, das zufällig eine Instanz der ClassKlasse ist" ". Es gibt auch Methoden wie Object#define_singleton_method, Object#singleton_method, Object#singleton_methods, Module#private_class_method, Module#public_class_method, und Module#module_functionin der Ruby - Core - Bibliothek. Es ist jedoch immer wichtig, sich daran zu erinnern, dass dies keine Sprachkonzepte sind. Dies sind Community- Konzepte, die nur in unseren Köpfen und in den Namen einiger Bibliotheksmethoden existieren.

Jörg W Mittag
quelle
2

OK, es sieht so aus, als ob ich so etwas machen kann und es wird funktionieren:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method

  class << self
    alias_method :a_new_class_method, :a_class_method
  end
end

Foo.a_class_method # => "class method" 
Foo.a_new_class_method # => "class method"

Wenn jemand hier nützliche Informationen über die Ruby-Sprache hat und eine umfassende Antwort einreichen möchte, gebe ich Ihnen eine +1.

aarona
quelle
1
Wenn Sie das tun , class << selfindem gefolgt alias_method :a_new_class_method, :a_class_methodrufen Sie eigentlich alias_methodauf die Singleton - Klasse von Foo. Eine andere Art, dies zu schreiben, ist: singleton_class.alias_method :a_new_class_method, :a_class_methodim Klassenkontext.
3limin4t0r
Was willst du mehr von einer Antwort? Ich meine, das ist wahrscheinlich die sauberste Lösung.
Dave Newton
@ 3limin4t0r Wenn du das zu einer Antwort machst, werde ich es +1 geben. Danke für diese extra Info.
Aarona
@ DaveNewton Sie haben Recht, aber weil ich auch die Philosophie habe, dass, wenn jemand aussagekräftigere Informationen zu einem Problem liefern kann, auch wenn es das Problem indirekt löst, ich denke, dass dies auch belohnt werden sollte.
Aarona
2

alias_methodwird auf der Instanz ausgeführt, daher müssen Sie eine Ebene tiefer gehen und die ClassInstanz oder die Metaklasse der Klasse bearbeiten . Ruby hat ein Wildobjektmodell, das eine Art Gehirnbruch sein kann, aber es gibt Ihnen auch eine Menge Kraft:

class Foo
  def an_inst_method
    'instance method'
  end

  alias_method :a_new_inst_method, :an_inst_method

  class << self
    def a_class_method
      'class method'
    end

    alias_method :a_new_class_method, :a_class_method
  end
end
Lobati
quelle
Ich arbeite seit ungefähr einem Jahrzehnt mit Ruby in einem Rails-Kontext, habe aber erst vor kurzem begonnen, mich intensiv mit dem Objektmodell zu beschäftigen. Es gibt so viele coole Sachen!
Aarona