【问题标题】:Add ruby class methods or instance methods dynamically动态添加 ruby​​ 类方法或实例方法
【发布时间】:2011-11-15 14:16:36
【问题描述】:

我对 Ruby 很陌生,所以还在学习。我研究了很多关于如何动态添加方法,创建实例方法成功,但创建类方法时没有成功。

这就是我生成实例方法的方式:

  class B
    def before_method
      puts "before method"
    end

    def self.run(method)
        send :define_method, method do
          before_method
          puts "method #{method}"
        end
    end
  end

  class A < B
    run :m
    run :n
  end

知道创建静态方法的最佳方法吗?

我的最终任务是寻找为类方法创建“之前”和“之后”任务的最佳方式。

【问题讨论】:

标签: ruby class metaprogramming instance


【解决方案1】:

要动态创建实例方法,试试

class Foo
  LIST = %w(a b c)

  LIST.each do |x|
    define_method(x) do |arg|
      return arg+5
    end
  end
end

现在 Foo 的任何实例都有方法“a”、“b”、“c”。试试

Foo.new.a(10)

要动态定义类方法,试试

class Foo
  LIST = %w(a b c)

  class << self
    LIST.each do |x|
      define_method(x) do |arg|
        return arg+5
      end
    end
  end
end

那就试试

Foo.a(10)

【讨论】:

    【解决方案2】:

    对象单例类的实例方法是对象本身的单例方法。所以如果你这样做了

    class B
      def self.run(method)
        singleton_class = class << self; self; end
        singleton_class.send(:define_method, method) do
            puts "Method #{method}"
        end
      end
    end
    

    你现在可以打电话了

    B.run :foo
    B.foo 
    => Method foo
    

    (编辑:根据 Lars Haugseth 的评论添加 B.run :foo)

    【讨论】:

    • 您需要先拨打B.run :foo,然后才能致电B.foo
    • 你也可以使用eigenclass.class_eval { define_method(method) { ... }}避免send
    • 编辑使用singleton_class的官方术语,在Ruby 1.9.2中引入
    • @Marc-André:啊,我不知道终于有了标准;我们仍然在 1.8.7。现在我必须忘掉我们公司的标准‘eigenclass’:)。
    【解决方案3】:

    以下是使用类方法重新设计的内容:

    class B
       def self.before_method
         puts "before method"
       end
    
      def self.run(method)
        define_singleton_method(method) do
          before_method
          puts "method #{method}"
        end
      end
    end
    

    更新:使用 Ruby 1.9 中的 define_singleton_method 正确分配给 eigenclass

    【讨论】:

    • 你能告诉我为什么它是一个边缘案例吗?我很新,很想学习,xD!
    • 人们很少创建动态的实例方法,动态的类方法更是少之又少。可悲的是,语义有点难看,因为它很少出现。这样做没有错,但大多数人永远不会,仅此而已。
    • 这可能不是您想要的:您现在已将方法添加到 Class,这意味着它在 every 类中可用(B.class== Class) .这是一个问题,尤其是因为并非每个类都有“before_method”。尝试调用 B.run 'foo',定义一个类 A 并调用 A.foo。它将失败,NameError: undefined local variable or method before_method' for A:Class`
    • 我认为人们在 Ruby 中相当频繁地创建动态方法。这就是很多“魔法”的来源。我是否混淆了术语?
    • 此处使用define_singleton_method 进行的编辑将方法置于正确的上下文中。
    猜你喜欢
    • 1970-01-01
    • 2013-01-09
    • 2016-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-01
    相关资源
    最近更新 更多