[英]Bug in rails autoload_paths?
I am encountering a strange bug in my code. 我在代码中遇到了一个奇怪的错误。 I have a rails application with the following two files in the lib:
我有一个rails应用程序,在lib中有以下两个文件:
lib/module_one/module_two/class_one.rb LIB / module_one / module_two / class_one.rb
module ModuleOne
module Moduletwo
class ClassOne
class << self
def test
puts 'Class one'
ClassTwo.test
end
end
end
end
end
and 和
lib/module_one/module_two/class_two.rb LIB / module_one / module_two / class_two.rb
module ModuleOne
module ModuleTwo
class ClassTwo
def self.test
puts 'Class two'
end
end
end
end
Now my problem is, that when I go into the console and write: 现在我的问题是,当我进入控制台并写道:
ModuleOne::ModuleTwo::ClassOne.test
it throws the following: NameError: uninitialized constant ClassTwo
它抛出以下内容:
NameError: uninitialized constant ClassTwo
The strange thing is, that the problem seems to be connected to the use of class << self
instead of self.method
. 奇怪的是,这个问题似乎与使用
class << self
而不是self.method
。 If I change the class_one.rb file like this it works!: 如果我像这样更改class_one.rb文件就可以了!
module ModuleOne
module ModuleTwo
class ClassOne
def self.test
puts 'Class one'
ClassTwo.test
end
end
end
end
Im loading the files in application.rb like this: 我在application.rb中加载文件,如下所示:
config.autoload_paths += %W(#{config.root}/lib)
Is this a bug in rails, or is it just me getting something all wrong? 这是rails中的一个错误,还是只是我弄错了?
Im using rails 3.1.3 btw 我使用rails 3.1.3 btw
So first off, the basic process for constant resolution is that ruby first searches the lexical scope of the receiver (the class or module enclosing the reference) for ClassTwo
and when it can't find it, it goes up a level ( Module.nesting
returns this search path) and so on. 首先,恒定解析的基本过程是ruby首先在
ClassTwo
搜索接收器的词法范围(包含引用的类或模块),当它找不到它时,它会上升一个级别( Module.nesting
返回此搜索路径)等等。 In your case that means looking for ModuleOne::ModuleTwo::ClassOne:ClassTwo
, then ModuleOne::ModuleTwo::ClassTwo
, then ModuleOne::ClassTwo
and so on. 在你的情况下,这意味着寻找
ModuleOne::ModuleTwo::ClassOne:ClassTwo
,然后是ModuleOne::ModuleTwo::ClassTwo
,然后是ModuleOne::ClassTwo
等等。
If that fails the ruby looks in the inheritance hierarchy of the enclosing class/module (eg has the superclass of ClassOne defined something. The ancestors
method on module returns this search path. Lastly, the top level constants are searched. 如果失败,ruby会查看封闭类/模块的继承层次结构(例如,ClassOne的超类定义了一些东西。模块上的
ancestors
方法返回此搜索路径。最后,搜索顶层常量。
Back to rails's magic loading. 回到rails的神奇装载。 Here a
const_missing
hook is added by rails that is called when ruby can't find the class, which basically tries to replicate this search logic, seeing at each step whether a file could have been loaded which would contain the missing constant. 这里有一个
const_missing
挂钩由rails添加,当ruby找不到类时调用它,它基本上试图复制这个搜索逻辑,在每一步看到是否可以加载一个包含缺失常量的文件。
Ideally ruby would pass the search path (ie the nesting) to search through, but unfortunately it doesn't: when you reference ClassTwo
, const_missing
gets called with just 'ClassTwo'. 理想情况下,ruby会通过搜索路径(即嵌套)来搜索,但不幸的是它没有:当你引用
ClassTwo
, const_missing
只用'ClassTwo'调用。
Rails guesses the nesting by prepending that with the name of the class on which const_missing
is being called (ie the class enclosing the access to the constant). Rails通过在其上调用
const_missing
的类的名称(即包含对常量的访问的类)前面来猜测嵌套。 For example, in your second example it ends up with ModuleOne::ModuleTwo::ClassOne::ClassTwo
. 例如,在你的第二个例子中,它以
ModuleOne::ModuleTwo::ClassOne::ClassTwo
。 You can see this easily enough by defining const_missing
to log what it's called with 通过定义
const_missing
来记录它的调用内容,你可以很容易地看到这一点
class Object
def self.const_missing missing_name
puts "qualified name is #{self.name}::#{missing_name}"
super
end
end
Rails then strips off 'ClassOne' and tries ModuleOne::ModuleTwo::ClassTwo
and so on up the chain. 然后Rails剥离'ClassOne'并尝试
ModuleOne::ModuleTwo::ClassTwo
,依此类推。
So why does class << self
make a difference? 那么为什么
class << self
有所作为呢? If you repeat your first case with the const_missing
logging you'd see that the logged qualified name is now just ::ClassTwo
. 如果您使用
const_missing
日志重复第一个案例,您会看到记录的限定名称现在只是::ClassTwo
。 const_missing
is now being called on ClassOne's metaclass, and because class << self
hasn't been assigned to a constant, it has no name and thus rails' attempt to fudge the nesting doesn't work. const_missing
现在在ClassOne的元类上被调用,并且因为class << self
尚未被赋值给常量,所以它没有名称,因此rails'试图捏造嵌套不起作用。
This opens the door to a horrible workaround: 这为一个可怕的解决方法打开了大门:
module ModuleOne
module ModuleTwo
class ClassOne
class << self
def test
puts 'Class one'
ClassTwo.test
end
end
FOO = class << self; self; end
end
end
end
Because the class that const_missing gets called on now has a name (ModuleOne::ModuleTwo::ClassOne::FOO) rails' workaround now works. 因为现在调用const_missing的类有一个名称(ModuleOne :: ModuleTwo :: ClassOne :: FOO)rails'的解决方法现在可以使用了。
Dave's workaround works I think because const_missing gets called on ModuleOne::ModuleTwo::ClassOne
rather than the anonymous eigenclass/metaclass. 我认为Dave的解决方法是有效的,因为const_missing在
ModuleOne::ModuleTwo::ClassOne
而不是匿名的eigenclass / metaclass。
The real fix would be for ruby to pass const_missing
a nesting. 真正的修复方法是让ruby传递
const_missing
一个嵌套。 There is a bug logged against ruby to this effect although it has been open for a long time. 虽然已经打开了很长时间,但是有一个针对ruby记录的错误 。 So yes, this could be considered a bug in the magic loading stuff (there are other edge cases) but the underlying reason is a weakness in the ruby api that forces the use of brittle workarounds.
所以是的,这可能被认为是魔法加载中的一个错误(还有其他边缘情况),但潜在的原因是ruby api的弱点迫使使用脆弱的变通方法。
(Only a partial answer, but need formatting.) (只是部分答案,但需要格式化。)
It's because of how class << self
works. 这是因为
class << self
运作”。
For example, if you change it to: 例如,如果您将其更改为:
class << self
def test
self::ClassTwo.test
end
end
it works fine. 它工作正常。
Edit; 编辑; too long for reasonable comment.
太长时间没有合理的评论。
I'm poking around a bit... On an intuitive level it makes sense to me, I'm just not sure why yet. 我正在喋喋不休......在直观的层面上,这对我来说很有意义,我只是不确定为什么。 Don't know if I knew a real reason once, or if I'm just making it up.
不知道我是否知道一次真正的理由,或者我是否只是在弥补它。
I'm not sure why self
seems to refer to the module, though; 我不确定为什么
self
似乎会参考模块; the "Programming Ruby 1.9" book doesn't go in to enough depth on the class <<
semantics. “Programming Ruby 1.9”一书并没有深入研究
class <<
语义学。 I'll tweet something and refer to this question and someone smarter will create a real answer. 我会发推特,并参考这个问题,聪明的人会创造一个真正的答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.