Как использовать define_method для создания методов класса? - PullRequest
100 голосов
/ 15 апреля 2009

Это полезно, если вы пытаетесь создать методы класса метапрограмматически:

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

Мой ответ следовать ...

Ответы [ 6 ]

184 голосов
/ 08 ноября 2010

Я думаю, что в Ruby 1.9 вы можете сделать это:

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

A.loudly "my message"

# >> MY MESSAGE
25 голосов
/ 15 апреля 2009

Я предпочитаю использовать send для вызова define_method, и мне также нравится создавать метод метакласса для доступа к метаклассу:

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
10 голосов
/ 08 октября 2012

Это самый простой способ в Ruby 1.8 +:

class A
  class << self
    def method_name
      ...
    end
  end
end
8 голосов
/ 15 апреля 2009

Получено от: Jay и Почему , которые также предоставляют способы сделать это красивее.

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

Обновление : из вклада VR ниже; более краткий метод (если вы только так определяете один метод), который все еще автономен:

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

но обратите внимание, что использование send () для доступа к закрытым методам, таким как define_method (), не обязательно является хорошей идеей (насколько я понимаю, это прекращается в Ruby 1.9).

5 голосов
/ 19 ноября 2015

Используется в Rails, если вы хотите динамически определять методы класса из задачи:

module Concerns::Testable
  extend ActiveSupport::Concern

  included do 
    singleton_class.instance_eval do
      define_method(:test) do
        puts 'test'
      end
    end
  end
end
0 голосов
/ 14 декабря 2016

Вы также можете сделать что-то подобное, не полагаясь на 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
...