如何使用META PROGRAMMING记忆类方法?

时间:2012-11-27 15:51:25

标签: ruby metaprogramming

编辑:要清楚。这是关于如何使用元编程做一些事情的问题。这不是关于回忆。很明显,有更好的方法来记忆。相关方法在其中“记忆”只是为了说明它们的目的。


我只是在玩元编程,所以请不要回答使用a @foo实例变量。

我有以下尝试记住实例和类方法 通过从正在运行的方法覆盖方法定义..

class Obj
  class << self

    def meta_me; self; end

    def class_memoize
      puts "hard core calculating ..."
      abc = "huge calculation result"

      raise "broken here with infinite loop"

      define_class_method "class_memoize" do
        puts abc
        abc
      end
      class_memoize
    end

    def define_class_method name, &blk
      meta_me.instance_eval do
        define_method name, &blk
      end
    end
  end

  def instance_memoize
    puts "hard core calculating ..."
    abc = "huge calculation result"

    self.class.meta_me.send :define_method, :instance_memoize do
      puts abc
      abc
    end

    instance_memoize
  end
end

o = Obj.new
o.instance_memoize
# hard core calculating ...
# huge calculation result

o.instance_memoize
# huge calculation result

实例版本有效,但类版本没有。

我已经尝试过课程版本以供参考。

1 个答案:

答案 0 :(得分:1)

除了道德之外,它比你想象的要容易得多。你的主要问题是你的meta_me方法使用了错误的东西。试试这个:

class Object
  def metaclass
    class<<self;self;end
  end
end

在Ruby中进行元编程时,这是一个相当常见的monkeypatch。现在,动态重新实现方法很容易:

class Obj
  def self.class_memoize
    puts "calculating..."
    abc = "result"
    metaclass.send(:define_method, :class_memoize) do
      puts abc
      abc
    end
    class_memoize
  end

  def instance_memoize
    puts "calculating..."
    abc = "result"
    metaclass.send(:define_method, :instance_memoize) do
      puts abc
      abc
    end
    instance_memoize
  end
end

正如您所看到的,一旦您拥有了元类对象,无论是类方法还是实例方法,重新定义方法都是以相同的方式完成的。请注意,如果您不想使用元类方法来玷污整个命名空间,那么只要您想引用它就可以更好地使用class<<self;self;end惯用法。您可以直接在其上调用方法,如下所示:

(class<<self;self;end).send(:define_method, :foo){|bar| bar*23}

请注意,parens并不是真正需要的,它只是有助于控制裸元类引用的混乱:)希望这会有所帮助。