Czy istnieje metoda alias_metoda dla metody klasy?

10

Rozważ następującą klasę:

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

To nie jest problem i możesz dzwonić Foo.new.a_new_inst_methodbez problemu.

Chciałbym mieć możliwość posiadania metody klasowej Foo.add_widget(*items)i aliasu, aby móc zrobić coś takiego:

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

Więc w zasadzie nie ma „Ruby stylu” jak 1.minutei 2.minutestak chcę alias a Foo.add_widgetwięc wywołanie Foo.add_widgetswywołuje dokładnie te same metody. Wiem, że mógłbym to owinąć, ale wydaje mi się, że powinienem móc to zrobić w czystszy sposób.

Rozważ moją próbę wypróbowania czegoś takiego:

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

Jednak pojawia się następujący błąd:

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

I wygląda na to, że to nie działa w przypadku metod klasowych. Jak mam to zrobić?

aarona
źródło

Odpowiedzi:

9

alias_methodaliasuje metodę instancji odbiornika. Metody klasy są w rzeczywistości metodami instancji zdefiniowanymi w klasie singleton klasy.

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

Aby dokonać aliasu metody instancji zdefiniowanej w klasie singleton, możesz ją otworzyć, korzystając ze class << objectskładni.

class << MyClass
  alias_method :b, :a
end

MyClass.b
#=> "Hello World!"

Lub możesz odwołać się do tego bezpośrednio za pomocą singleton_classmetody.

MyClass.singleton_class.alias_method :c, :a

MyClass.c
#=> "Hello World!"

Jeśli nadal znajdujesz się w kontekście klasy, odniesiesz selfsię do klasy. Powyższe można również zapisać jako:

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

Lub

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

Lub kombinacja tych dwóch.

3limin4t0r
źródło
5

Możesz owinąć metody klas i ich alias_methodwywołania w osobny moduł i włączyć ten moduł do swojej klasy poprzez 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
źródło
Hej! Zapomniałem o extend ClassMethodsrozwiązaniu. +1
aarona
4

Ważną rzeczą do zrozumienia jest to, że w Ruby nie istnieje metoda klasowa .

Metoda klasowa jest tak naprawdę tylko metodą singleton. Nie ma nic specjalnego w metodach klasowych. Każdy obiekt może mieć metody singleton. Po prostu nazywamy je „metodami klasowymi”, gdy obiekt jest, Classponieważ „metoda singletonowa instancji Class” jest zbyt długa i niewygodna.

Czekać! Czy powiedziałem „singleton method”?

Inną ważną rzeczą do zrozumienia jest to, że nie ma czegoś takiego jak metoda singleton w Ruby.

Metoda singleton jest tak naprawdę zwykłą nudną, starą metodą instancji klasy singleton. Nie ma nic specjalnego w metodach singleton. Są to tylko metody instancji, jak każda inna metoda instancji.

W rzeczywistości Ruby ma tylko metody instancji. Bez funkcji, bez konstruktorów, bez metod statycznych, bez metod klasowych, bez funkcji modułowych, bez metod singletonowych.

Pytanie nie brzmi „czy jest to metoda klasowa, czy jest to metoda singletonowa”, ale raczej „w którym module jest zdefiniowana ta metoda?”

„Metody singletonowe” to tak naprawdę metody instancji zdefiniowane w klasie singleton. Składnia dostępu do klasy singleton footo

class << foo
end

Istnieje również metoda, Object#singleton_classktóra zwraca klasę singleton obiektu.

Dlaczego tak agresywnie zastanawiam się nad tym, że każda metoda jest metodą instancji, a metody klas nie istnieją? Ponieważ oznacza to, że model obiektowy Ruby jest o wiele prostszy, niż ludzie myślą! W końcu w swoim pytaniu pokazujesz już, że wiesz, jak aliasować metody instancji, ale mówisz, że nie wiesz, jak aliasować metody klas. Ale to źle! Ci zrobić wiedzieć jak alias metod klasy, ponieważ one są tylko metody instancji . Jeśli zostałeś właściwie nauczony tego faktu, nigdy nie musiałbyś zadawać tego pytania!

Gdy zrozumiesz, że każda metoda jest metodą instancji i że to, co nazywamy „metodami singleton”, jest tylko metodami instancji klasy singleton, rozwiązanie staje się jasne:

singleton_class.alias_method :a_new_class_method, :a_class_method

Uwaga: kiedy napisałem powyżej, że „nie ma czegoś takiego jak X”, miałem na myśli to, że „nie ma czegoś takiego jak X w języku Ruby ”. To nie znaczy, że te koncepcje nie istnieją w społeczności Ruby .

Regularnie mówimy o „metodach singletonowych” i „metodach klasowych”, po prostu dlatego, że jest to łatwiejsze niż mówienie o „metodach instancji klasy singletonów” lub „metodach instancji klasy singletonów obiektu, który przypadkiem jest instancją Classklasy „. Istnieją nawet metody, takie jak Object#define_singleton_method, Object#singleton_method, Object#singleton_methods, Module#private_class_method, Module#public_class_method, i Module#module_functionw podstawowej bibliotece Ruby. Zawsze jednak należy pamiętać, że nieto pojęcia językowe. Są to koncepcje społeczności , które istnieją tylko w naszych głowach i nazwach niektórych metod bibliotecznych.

Jörg W Mittag
źródło
2

OK, wygląda na to, że mogę zrobić coś takiego i zadziała:

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"

Jeśli ktoś ma tutaj jakieś przydatne informacje na temat języka Ruby i chce udzielić wyczerpującej odpowiedzi, dam +1.

aarona
źródło
1
Gdy to zrobisz class << self, a następnie alias_method :a_new_class_method, :a_class_methodrzeczywiście zadzwonić alias_methodna singleton klasy Foo. Innym sposobem pisania tego jest: singleton_class.alias_method :a_new_class_method, :a_class_methodw kontekście klasowym.
3limin4t0r
Czego więcej chcesz od odpowiedzi? To znaczy, to prawdopodobnie najczystsze rozwiązanie.
Dave Newton,
@ 3limin4t0r, jeśli udzielisz odpowiedzi, daję +1. Dzięki za te dodatkowe informacje.
aarona
@DaveNewton masz rację, ale ponieważ mam również filozofię, że jeśli ktoś może dostarczyć bardziej znaczących informacji na temat problemu, nawet jeśli pośrednio rozwiązuje problem, myślę, że należy to również wynagrodzić.
aarona
2

alias_methoddziała na instancji, więc musisz zejść o jeden poziom głębiej i operować na Classinstancji lub metaklasie klasy . Ruby ma model dzikiego obiektu, który może trochę łamać mózg, ale daje też mnóstwo mocy:

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
źródło
Pracuję z rubinem w kontekście szyn przez około dekadę, ale dopiero niedawno zacząłem głęboko zanurzać się w modelu obiektowym. Dostępnych jest tyle fajnych rzeczy!
aarona