动态执行类级函数

时间:2014-11-26 04:56:10

标签: ruby class module eval metaprogramming

实际上问题是关于我对ruby元编程的误解:只想在这里清楚我的问题: 我在我的一个模块中有一个工作代码,如:

module Mappable
  def self.included(klass)
    klass.class_eval do
      class << self
        attr_accessor :source
      end
    end
  end
end

我对这里发生的事情的理解是:在包含Mappable模块的任何类中,我们想要评估代码&#34; attr_accessor:source&#34;。

然后&#34;类&lt;&lt;自&#34;在这里?如果我们已经评估了&#34; attr_accessor:source&#34;用&#34; klass.class_eval&#34; 谢谢!

1 个答案:

答案 0 :(得分:1)

这里有一些代码可以帮助解释这里发生了什么。我将在短期内添加一些解释性说明。

module Mappable
  def self.included(klass)
    puts "klass = #{klass}"
    puts "self before class_eval = #{self}"
    klass.class_eval do
      puts "self after class_eval and before class << self = #{self}"
      class << self
        puts "self after class << self = #{self}"
        attr_accessor :source
      end
    end
  end
end

class A
  include Mappable
  attr_accessor :source
  @source = 'cat'
  def initialize
    @source = 'dog'
  end
end

以下Mappable include A#-> klass = A #-> self before class_eval = Mappable #-> self after class_eval and before class << self = A #-> self after class << self = #<Class:A> 的结果:

klass.class_eval

可以看出A.class_evalself)将上下文(Mappable的值)从A更改为class << selfclass << AA)然后将上下文更改为attr_accessor的单例类,我们执行方法@source以创建类实例的读写访问器变量A.methods(false) #=> [:source, :source=] A.instance_variables #=> [:@source] A.source #=> "cat" A.source = 'pig' A.source #=> "pig"

@a

这表明我们为类实例变量A.instance_methods(false) #=> [:source, :source=] a = A.new #=> #<A:0x000001018fdc78 @source="dog"> a.instance_variables #=> [:@source] a.source #=> "dog" a.source = 'cow' #=> "cow" a.source #=> "cow" 创建的访问器似乎正常工作。现在让我们看一下实例方法和实例变量。

A

这似乎也没问题。重要的是要了解虽然a@source每个都有一个实例变量A.source #=> "pig" ,但这两个变量是不相关的。最后,让我们确认在更改实例变量的值时,我们不会影响类实例变量的值:

A

还有其他方法可以将上下文更改为attr_accessor的单例类,以便执行方法def self.included(klass) klass.singleton_class.class_eval do attr_accessor :source end end 。我更喜欢使用Object#singleton_class,自Ruby 1.9.2以来一直在我们身边:

{{1}}