Sınıf yöntemi için bir alias_method var mı?


10

Aşağıdaki sınıfı düşünün:

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

Bu sorun değil ve sorun olmadan arayabilirsiniz Foo.new.a_new_inst_method.

Gibi bir sınıf yöntemi gibi Foo.add_widget(*items)ve diğer bir şekilde yapabilmek için yeteneği istiyorum:

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

Yani aslında bir "yakut tarzı" gibi 1.minuteve 2.minutesbu yüzden ben aynı Foo.add_widgetşekilde çağrı Foo.add_widgetsçağıran bir şekilde takma ad istiyorum . Ben satabileceğimi biliyorum ama bunu daha temiz bir şekilde yapabilmem gerektiğini hissediyorum.

Böyle bir şeyi denemeye çalıştığımı düşünün:

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

Ancak, aşağıdaki hatayı alıyorum:

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

Ve öyle görünüyor ki bu sınıf yöntemleri için işe yaramıyor. Bunu nasıl yapabilirim?

Yanıtlar:


9

alias_methodalıcının bir örnek yöntemini taklit eder. Sınıf yöntemleri aslında bir sınıfın singleton sınıfında tanımlanan örnek yöntemlerdir .

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

Singleton sınıfında tanımlanan bir örnek yöntemini takma adı için class << objectsözdizimini kullanarak açabilirsiniz .

class << MyClass
  alias_method :b, :a
end

MyClass.b
#=> "Hello World!"

Veya singleton_classyöntemi kullanarak doğrudan başvurabilirsiniz .

MyClass.singleton_class.alias_method :c, :a

MyClass.c
#=> "Hello World!"

Eğer hala sınıf bağlamındaysanız sınıfa selfatıfta bulunacaksınız. Yani yukarıdakiler de şöyle yazılabilir:

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

Veya

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

Veya ikisinin bir kombinasyonu.


5

Sınıf yöntemlerini ve alias_methodçağrılarını ayrı bir modüle sarabilir ve şu modülü sınıfınıza sınıfınıza dahil edebilirsiniz 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

Hey! extend ClassMethodsÇözümü unuttum . +1
aarona

4

Anlaşılması gereken önemli şey , Ruby'de sınıf yöntemi diye bir şey olmamasıdır .

Bir sınıf yöntemi gerçekten sadece tek bir yöntemdir. Sınıf yöntemleri hakkında özel bir şey yoktur. Her nesnenin singleton yöntemleri olabilir. Nesne bir Class"örneğinin singleton yöntemi Class" çok uzun ve hantal olduğu için onlara "sınıf yöntemleri" diyoruz .

Bekle! "Tekil yöntem" mi dedim?

Anlaşılması gereken bir diğer önemli şey de Ruby'de tekil yöntem diye bir şey olmadığıdır .

Singleton yöntemi, gerçekten de singleton sınıfının normal sıkıcı eski örnek yöntemidir. Singleton yöntemleri hakkında özel bir şey yoktur. Bunlar sadece diğer örnek yöntemleri gibi örnek yöntemleridir.

Aslında, Ruby'nin yalnızca örnek yöntemleri vardır. İşlev yok, kurucu yok, statik yöntem yok, sınıf yöntemi yok, modül işlevi yok, tekil yöntem yok.

Soru "bu bir sınıf yöntemi mi, bu tek bir yöntem mi" değil, " bu yöntem hangi modülde tanımlanıyor?"

"Singleton yöntemleri" gerçekten singleton sınıfında tanımlanan örnek yöntemlerdir. Singleton sınıfına erişim sözdizimi fooşöyledir:

class << foo
end

Object#singleton_classBir nesnenin singleton sınıfını döndüren bir yöntem de vardır .

Neden bu kadar agresif bir şekilde her yöntemin bir örnek yöntem olduğu ve sınıf yöntemlerinin olmadığı gerçeğine dikkat çekiyorum? Çünkü Ruby'nin nesne modelinin insanların düşündüğünden çok daha basit olduğu anlamına geliyor! Sonuçta, sorunuzda, örnek yöntemlerini nasıl takma yapacağınızı bildiğinizi, ancak sınıf yöntemlerini nasıl takma yapacağınızı bilmediğinizi söylüyorsunuz. Ama bu yanlış! Sen bunu çünkü nasıl takma sınıf yöntemleri bilmek onlar sadece örnek yöntemlerdir . Bu gerçeği düzgün bir şekilde öğrenmiş olsaydınız, bu soruyu asla sormanıza gerek kalmazdı!

Her yöntemin bir örnek yöntemi olduğunu ve "singleton yöntemleri" olarak adlandırdığımız şeyin yalnızca singleton sınıfının örnek yöntemleri olduğunu anladıktan sonra çözüm netleşir:

singleton_class.alias_method :a_new_class_method, :a_class_method

Not: Yukarıda "X diye bir şey yok" yazdığımda, demek istediğim " Ruby dilinde X diye bir şey yok " idi. Bu, bu kavramların Ruby topluluğunda mevcut olmadığı anlamına gelmez .

Biz düzenli olarak "tekil sınıfının örnek yöntemlerinden" veya bir örneği olur bir nesnenin tekil sınıfının "örneği yöntemleri hakkında konuşurken daha kolaydır çünkü, "tekil yöntemleri" ve "sınıf yöntemleri" hakkında konuşmak Classsınıfta ". Gibi yöntemler de vardır Object#define_singleton_method, Object#singleton_method, Object#singleton_methods, Module#private_class_method, Module#public_class_method, ve Module#module_functionRuby çekirdek kütüphane. Ancak bunların dil kavramları olmadığını hatırlamak her zaman önemlidir . Bunlar sadece kafamızda ve bazı kütüphane yöntemlerinin adlarında var olan topluluk kavramlarıdır .


2

Tamam, böyle bir şey yapabilirim ve işe yarayacak:

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"

Burada Ruby dili hakkında yararlı bilgiler varsa ve kapsamlı bir yanıt göndermek isterseniz, size bir +1 vereceğim.


1
Bunu class << selftakip alias_method :a_new_class_method, :a_class_methodettiğinizde aslında alias_methodsingleton sınıfını çağırırsınız Foo. Bunu yazmanın başka bir yolu da: singleton_class.alias_method :a_new_class_method, :a_class_methodsınıf bağlamında.
3limin4t0r

Bir cevaptan daha ne istersiniz? Demek istediğim, bu muhtemelen en temiz çözüm.
Dave Newton

@ 3limin4t0r Eğer bir cevap verirsen + 1'leyeceğim. Bu ekstra bilgi için teşekkürler.
aarona

@DaveNewton haklısınız, ancak aynı zamanda bir kişi sorunu dolaylı olarak çözse bile daha anlamlı bilgiler sağlayabiliyorsa, bunun da ödüllendirilmesi gerektiğini düşünüyorum.
aarona

2

alias_methodörnek üzerinde çalışır, bu nedenle bir seviye daha derine inmeniz ve Classörnek veya sınıfın metasınıfı üzerinde işlem yapmanız gerekir . Ruby, bir tür beyin kırılması olabilecek vahşi bir nesne modeline sahiptir, ancak aynı zamanda size bir ton güç verir:

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

Yaklaşık on yıldır raylar bağlamında ruby ​​ile çalışıyorum ama sadece son zamanlarda nesne modeline derin bir dalış yapmaya başladım. Çok güzel şeyler var!
aarona
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.