Bagaimana cara menggunakan define_method untuk membuat metode kelas?


108

Ini berguna jika Anda mencoba membuat metode kelas secara metaprogram:

def self.create_methods(method_name)
    # To create instance methods:
    define_method method_name do
      ...
    end

    # To create class methods that refer to the args on create_methods:
    ???
end

Jawaban saya untuk mengikuti ...

Jawaban:


196

Saya pikir di Ruby 1.9 Anda bisa melakukan ini:

class A
  define_singleton_method :loudly do |message|
    puts message.upcase
  end
end

A.loudly "my message"

# >> MY MESSAGE

4
jugasingleton_class.define_method
Pyro

@Pyro Hanya untuk mengklarifikasi, apakah Anda akan pergi, singleton_class.define_method :loudly do |message|dll.?
Joshua Pinter

25

Saya lebih suka menggunakan send to call define_method, dan saya juga suka membuat metode metaclass untuk mengakses metaclass:

class Object
  def metaclass
    class << self
      self
    end
  end
end

class MyClass
  # Defines MyClass.my_method
  self.metaclass.send(:define_method, :my_method) do
    ...
  end
end

2
Terima kasih! Pasti ada cara untuk membuatnya lebih bagus untuk diri Anda sendiri. Tetapi jika Anda bekerja pada sebuah plugin open source, misalnya, saya pikir akan lebih baik untuk tidak menyumbat namespace metaclass, jadi senang mengetahui singkatan yang mudah dan berdiri sendiri.
Chinasaur

Saya memutuskan untuk menggunakan jawaban asli saya. Pemahaman saya adalah bahwa menggunakan send () untuk mengakses metode privat jika pergi menggunakan Ruby 1.9, jadi itu sepertinya bukan hal yang baik untuk digunakan. Ditambah jika Anda mendefinisikan lebih dari satu metode, instance_evaling sebuah blok lebih bersih.
Chinasaur

@ Vincent Robert ada tautan yang akan menjelaskan keajaiban metode metaclass?
Amol Pujari

kelas << diri; diri; akhir; cukup membuka kembali kelas diri (kelas << diri) dan kemudian mengembalikan kelas itu (diri) jadi benar-benar mengembalikan metaclass dari diri.
Vincent Robert

10

Ini adalah cara termudah di Ruby 1.8+:

class A
  class << self
    def method_name
      ...
    end
  end
end

1
Saya sangat suka yang ini. Kecil, rapi, mudah dibaca dan portabel. Tentu saja, Anda bisa bertanya apa yang saya lakukan menggunakan ruby ​​1.8 pada 2013 ...
A Fader Darkly

8

Berasal dari: Jay and Why , yang juga memberikan cara untuk membuat ini lebih cantik.

self.create_class_method(method_name)
  (class << self; self; end).instance_eval do
    define_method method_name do
      ...
    end
  end
end

Pembaruan : dari kontribusi VR di bawah ini; metode yang lebih ringkas (selama Anda hanya mendefinisikan satu metode dengan cara ini) yang masih berdiri sendiri:

self.create_class_method(method_name)
  (class << self; self; end).send(:define_method, method_name) do
    ...
  end
end

tetapi perhatikan bahwa menggunakan send () untuk mengakses metode privat seperti define_method () belum tentu merupakan ide yang baik (pemahaman saya adalah bahwa ini akan hilang di Ruby 1.9).


Alternatif yang lebih baik (?) Mungkin dengan meletakkan sesuatu di modul dan kemudian membuat create_class_method Anda memperluas modul ke kelas ??? Lihat: blog.jayfields.com/2008/07/ruby-underuse-of-modules.html
Chinasaur

6

Untuk digunakan di Rails jika Anda ingin mendefinisikan metode kelas secara dinamis dari perhatian:

module Concerns::Testable
  extend ActiveSupport::Concern

  included do 
    singleton_class.instance_eval do
      define_method(:test) do
        puts 'test'
      end
    end
  end
end

-1

Anda juga dapat melakukan sesuatu seperti ini tanpa bergantung pada define_method:

A.class_eval do
  def self.class_method_name(param)
    puts param
  end
end

A.class_method_name("hello") # outputs "hello" and returns nil
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.