如何使用define_method创建类方法?


108

如果您试图通过元编程创建类方法,这将非常有用:

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

我的回答如下...

Answers:


196

我认为在Ruby 1.9中,您可以执行以下操作:

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

A.loudly "my message"

# >> MY MESSAGE

4
singleton_class.define_method
Pyro

@Pyro只是要澄清一下,你愿意去singleton_class.define_method :loudly do |message|等等吗?
约书亚·品特(

25

我更喜欢使用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

2
谢谢!肯定有一些方法可以使自己更好。但是,例如,如果您正在使用开放源代码插件,我认为最好不要使用来阻塞名称空间metaclass,因此知道简单易行的速记法也很好。
Chinasaur's

我决定接受我的原始答案。我的理解是,如果在Ruby 1.9中不使用send()来访问私有方法,那么使用它似乎不是一件好事。另外,如果要定义多个方法,instance_evaval块会更干净。
Chinasaur,2009年

@Vincent Robert有什么链接可以解释元类方法的神奇之处?
Amol Pujari 2012年

类<<自我; 自; 结束; 只需重新打开self的类(class << self),然后返回该类(self),以便实际上返回self的元类。
文森特·罗伯特

10

这是Ruby 1.8+中最简单的方法:

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

1
我真的很喜欢这一个。体积小,整洁,阅读效果好且便于携带。当然,您可以问一下我在2013年使用ruby 1.8所做的事情……
Fader Darkly

8

派生自:Jay and Why,他们还提供了使自己更漂亮的方法。

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中它已不复存在)。


更好的(?)替代方法可能是将东西放在模块中,然后让您的create_class_method将模块扩展到类上?参见:blog.jayfields.com/2008/07/ruby-underuse-of-modules.html
Chinasaur,

6

如果要根据关注动态定义类方法,可以在Rails中使用:

module Concerns::Testable
  extend ActiveSupport::Concern

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

-1

您也可以不依赖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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.