实际上问题是关于我对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; 谢谢!
答案 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_eval
(self
)将上下文(Mappable
的值)从A
更改为class << self
。 class << A
(A
)然后将上下文更改为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}}