Apakah ada alias_method untuk metode kelas?

10

Pertimbangkan kelas berikut:

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

Ini bukan masalah dan Anda dapat menelepon Foo.new.a_new_inst_methodtanpa masalah.

Saya ingin kemampuan untuk memiliki metode kelas seperti Foo.add_widget(*items)dan alias sehingga saya dapat melakukan sesuatu seperti:

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

Jadi pada dasarnya ia memiliki "gaya ruby" seperti 1.minutedan 2.minutesjadi saya ingin alias Foo.add_widgetpanggilan begitu Foo.add_widgetsmetode yang sama persis. Saya tahu saya bisa membungkusnya tetapi saya merasa saya harus bisa melakukan ini dengan cara yang lebih bersih.

Pertimbangkan upaya saya untuk mencoba sesuatu seperti ini:

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

Namun, saya mendapatkan kesalahan berikut:

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

Dan sepertinya ini tidak bekerja untuk metode kelas. Bagaimana cara saya melakukan ini?

aarona
sumber

Jawaban:

9

alias_methodalias metode instance penerima. Metode kelas sebenarnya adalah metode instan yang didefinisikan pada kelas tunggal dari suatu kelas.

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

Untuk alias metode instance yang didefinisikan pada kelas singleton Anda dapat membukanya menggunakan class << objectsintaks.

class << MyClass
  alias_method :b, :a
end

MyClass.b
#=> "Hello World!"

Atau Anda bisa merujuk langsung menggunakan singleton_classmetode ini.

MyClass.singleton_class.alias_method :c, :a

MyClass.c
#=> "Hello World!"

Jika Anda masih dalam konteks kelas selfakan merujuk ke kelas. Jadi di atas juga bisa ditulis sebagai:

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

Atau

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

Atau kombinasi keduanya.

3limin4t0r
sumber
5

Anda bisa membungkus metode kelas dan alias_methodpanggilan mereka ke modul terpisah dan memasukkan modul itu ke dalam kelas Anda melalui 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
sumber
Hei! Saya lupa extend ClassMethodssolusinya. +1
aarona
4

Yang penting untuk dipahami adalah bahwa tidak ada yang namanya metode kelas di Ruby.

Metode kelas sebenarnya hanya metode tunggal. Tidak ada yang istimewa tentang metode kelas. Setiap objek dapat memiliki metode tunggal. Kita menyebutnya "metode kelas" ketika objeknya adalah Classkarena "metode singleton dari instance Class" terlalu panjang dan sulit digunakan.

Tunggu! Apakah saya mengatakan "metode tunggal"?

Hal lain yang penting untuk dipahami adalah bahwa tidak ada yang namanya metode singleton di Ruby.

Metode singleton sebenarnya hanya metode instance lama yang membosankan dari kelas singleton. Tidak ada yang istimewa tentang metode singleton. Mereka hanya metode contoh seperti metode contoh lainnya.

Faktanya, Ruby hanya memiliki metode instance. Tidak ada fungsi, tidak ada konstruktor, tidak ada metode statis, tidak ada metode kelas, tidak ada fungsi modul, tidak ada metode tunggal.

Pertanyaannya bukan "apakah ini metode kelas, apakah ini metode tunggal", melainkan " modul apa yang dimaksud dengan metode ini?"

"Metode Singleton" adalah metode instan yang didefinisikan dalam kelas singleton. Sintaks untuk mengakses kelas singleton fooadalah

class << foo
end

Ada juga metode Object#singleton_classyang mengembalikan kelas singleton objek.

Mengapa saya begitu agresif memalu tentang fakta bahwa setiap metode adalah metode contoh dan metode kelas tidak ada? Karena itu berarti model objek Ruby jauh lebih sederhana daripada yang dipikirkan orang! Setelah semua, dalam pertanyaan Anda, Anda sudah menunjukkan bahwa Anda tahu cara alias metode contoh, tetapi Anda mengatakan bahwa Anda tidak tahu cara alias metode kelas. Tapi itu salah! Anda lakukan tahu bagaimana metode kelas alias, karena mereka metode instan hanya . Jika Anda telah diajarkan fakta ini dengan benar, Anda tidak akan pernah perlu mengajukan pertanyaan ini!

Setelah Anda memahami bahwa setiap metode adalah metode instan, dan apa yang kami sebut "metode singleton" hanyalah metode instan dari kelas singleton, solusinya menjadi jelas:

singleton_class.alias_method :a_new_class_method, :a_class_method

Catatan: ketika saya menulis di atas bahwa "tidak ada yang namanya X", yang saya maksudkan adalah "tidak ada yang namanya X dalam bahasa Ruby ". Itu tidak berarti bahwa konsep-konsep itu tidak ada di komunitas Ruby .

Kita secara teratur berbicara tentang "metode singleton" dan "metode kelas", hanya karena lebih mudah daripada berbicara tentang "metode instan dari kelas singleton" atau "metode instan dari kelas singleton suatu objek yang kebetulan merupakan instance dari Classkelas tersebut ". Ada metode bahkan seperti Object#define_singleton_method, Object#singleton_method, Object#singleton_methods, Module#private_class_method, Module#public_class_method, dan Module#module_functiondi perpustakaan inti Ruby. Tetapi selalu penting untuk diingat bahwa itu bukan konsep bahasa. Itu adalah konsep komunitas yang hanya ada di kepala kita dan atas nama beberapa metode perpustakaan.

Jörg W Mittag
sumber
2

OK, sepertinya saya bisa melakukan sesuatu seperti ini dan itu akan berhasil:

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"

Jika ada yang punya informasi berguna tentang bahasa Ruby di sini dan ingin mengirim jawaban yang komprehensif, saya akan memberi Anda +1.

aarona
sumber
1
Ketika Anda class << selfdiikuti oleh alias_method :a_new_class_method, :a_class_methodAnda benar-benar memanggil alias_methodkelas singleton Foo. Cara lain untuk menulis ini adalah: singleton_class.alias_method :a_new_class_method, :a_class_methoddalam konteks kelas.
3limin4t0r
Apa lagi yang Anda inginkan dari sebuah jawaban? Maksud saya, ini mungkin solusi terbersih.
Dave Newton
@ 3limin4t0r jika Anda menjawabnya, saya akan memberi +1. Terima kasih atas info tambahan ini.
aarona
@DaveNewton Anda benar tetapi karena saya juga memiliki filosofi bahwa jika seseorang dapat memberikan informasi yang lebih berarti untuk suatu masalah bahkan jika itu secara tidak langsung menyelesaikan masalah, saya pikir itu juga harus dihargai.
aarona
2

alias_methodberoperasi pada instance, jadi Anda harus naik satu tingkat lebih dalam dan beroperasi pada Classinstance, atau metaclass kelas . Ruby memiliki model objek liar yang bisa merusak otak, tetapi juga memberi Anda banyak kekuatan:

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
sumber
Saya telah bekerja dengan ruby ​​dalam konteks rel selama sekitar satu dekade tetapi hanya baru-baru ini mulai melakukan penyelaman mendalam ke model objek. Ada begitu banyak hal keren yang tersedia!
aarona