Làm cách nào để sử dụng định nghĩa_method để tạo các phương thức lớp?


108

Điều này hữu ích nếu bạn đang cố gắng tạo các phương thức lớp theo phương thức siêu chương trình:

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

Câu trả lời của tôi để làm theo ...

Câu trả lời:


196

Tôi nghĩ trong Ruby 1.9 bạn có thể làm điều này:

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

A.loudly "my message"

# >> MY MESSAGE

4
cũngsingleton_class.define_method
Pyro

@Pyro Chỉ để làm rõ, bạn có thể đi singleton_class.define_method :loudly do |message|v.v. không?
Joshua Pinter

25

Tôi thích sử dụng send để gọi định nghĩa_method và tôi cũng muốn tạo một phương thức metaclass để truy cập 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
Cảm ơn! Chắc chắn có nhiều cách để làm cho điều này đẹp hơn cho chính bạn. Nhưng nếu bạn đang làm việc trên một plugin mã nguồn mở, chẳng hạn, tôi nghĩ tốt hơn là không làm tắc nghẽn không gian tên metaclass, vì vậy thật tuyệt khi biết cách viết tắt đơn giản, dễ dàng.
Chinasaur

Tôi quyết định đi với câu trả lời ban đầu của tôi. Sự hiểu biết của tôi là sử dụng send () để truy cập các phương thức riêng tư nếu biến mất trong Ruby 1.9, vì vậy điều đó có vẻ không phải là một điều tốt để sử dụng. Ngoài ra, nếu bạn đang xác định nhiều phương thức, instance_evaling một khối sẽ rõ ràng hơn.
Chinasaur

@Vincent Robert bất kỳ liên kết nào giải thích sự kỳ diệu của phương pháp metaclass?
Amol Pujari

lớp << tự; bản thân; kết thúc; chỉ cần mở lại lớp self (class << self) và sau đó trả về lớp đó (self) để thực sự trả về siêu lớp của self.
Vincent Robert

10

Đây là cách đơn giản nhất trong Ruby 1.8+:

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

1
Tôi thật sự thich cai nay. Nhỏ, gọn gàng, đọc tốt và di động. Tất nhiên, bạn có thể hỏi tôi đang làm gì khi sử dụng ruby ​​1.8 vào năm 2013 ...
Một Fader mơ hồ

8

Xuất phát từ: JayWhy , người cũng cung cấp các cách để làm cho điều này đẹp hơn.

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

Cập nhật : từ đóng góp của VR bên dưới; một phương pháp ngắn gọn hơn (miễn là bạn chỉ xác định một phương pháp theo cách này) mà vẫn độc lập:

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

nhưng lưu ý rằng việc sử dụng send () để truy cập các phương thức riêng tư như define_method () không nhất thiết là một ý tưởng hay (theo hiểu biết của tôi là nó sẽ biến mất trong Ruby 1.9).


Cách thay thế tốt hơn (?) Có thể là đặt mọi thứ vào một mô-đun và sau đó để create_class_method của bạn mở rộng mô-đun đó vào lớp ??? Xem: blog.jayfields.com/2008/07/ruby-underuse-of-modules.html
Chinasaur 24/09/09

6

Để được sử dụng trong Rails nếu bạn muốn xác định động các phương thức lớp từ mối quan tâm:

module Concerns::Testable
  extend ActiveSupport::Concern

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

-1

Bạn cũng có thể làm điều gì đó tương tự như vậy mà không cần dựa vào 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.