如何使用 define_method 创建类方法?

Posted

技术标签:

【中文标题】如何使用 define_method 创建类方法?【英文标题】:How do I use define_method to create class methods? 【发布时间】:2010-10-19 15:47:45 【问题描述】:

如果您尝试以元编程方式创建类方法,这很有用:

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

我的回答……

【问题讨论】:

【参考方案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

【讨论】:

【参考方案2】:

如果你想从关注点动态定义类方法,可以在 Rails 中使用:

module Concerns::Testable
  extend ActiveSupport::Concern

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

【讨论】:

【参考方案3】:

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

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

【讨论】:

我真的很喜欢这个。小巧,整洁,读起来很好,而且很便携。当然,你可以问我在 2013 年使用 ruby​​ 1.8 在做什么......【参考方案4】:

我认为在 Ruby 1.9 中你可以这样做:

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

A.loudly "my message"

# >> MY MESSAGE

【讨论】:

还有singleton_class.define_method @Pyro 澄清一下,你会去singleton_class.define_method :loudly do |message| 等吗?【参考方案5】:

源自:Jay 和 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【参考方案6】:

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

【讨论】:

谢谢!绝对有办法让自己变得更好。但是,例如,如果您正在开发一个开源插件,我认为最好不要用 metaclass 阻塞命名空间,所以很高兴知道简单、独立的速记。 我决定采用我原来的答案。我的理解是,如果在 Ruby 1.9 中消失,使用 send() 访问私有方法,所以这似乎不是一件好事。另外,如果您定义了多个方法,那么 instance_evaling 块会更干净。 @Vincent Robert 有什么链接可以解释元类方法的魔力吗?

以上是关于如何使用 define_method 创建类方法?的主要内容,如果未能解决你的问题,请参考以下文章

你如何将参数传递给define_method?

Ruby:define_method 与 def

在 Ruby 中动态定义命名类

类方法中的定义方法

ruby 使用define_method和method_missing

ruby define_methodメソッドでコードをシンプルに书く