【问题标题】:How do I use define_method to create class methods?如何使用 define_method 创建类方法?
【发布时间】: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

我的回答……

【问题讨论】:

    标签: ruby metaprogramming class-method


    【解决方案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】:

        源自:JayWhy,他们还提供了使这个更漂亮的方法。

        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 中将消失)。

        【讨论】:

        【解决方案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 有什么链接可以解释元类方法的魔力吗?
        猜你喜欢
        • 2016-11-09
        • 1970-01-01
        • 1970-01-01
        • 2017-10-02
        • 2019-04-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多