浏览 12764 次
锁定老帖子 主题:Ruby的根模块命名空间
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2006-10-23
class ApplicationController < ActionController::Base ... def rescue_action_in_public(exception) case exception when ::ActionController::UnknownAction render_with_layout .... when ActiveRecord::RecordNotFound ... end end end 这里唯一奇怪的地方就是::ActionController::UnknownAction, 为什么去掉开头的::就会报错说找不到UnknownAction?看看源码,UnknownAction类确实存在于ActionController模块中啊。 简单说,Ruby的namespace是从当前位置开始的找起的,而由::开头访问的是所谓根模块命名空间(root module namespace),好比绝对路径。为了便于理解,我们来看个例子: class Obj def self.p "Obj" end end module Test class Obj def self.p "Test::Obj" end end class See def self.p puts Obj.p puts ::Obj.p end end end 在irb中load这段代码,并执行 >> Test::See.p Test::Obj Obj 显然See看见Obj会首先在同一命名域下搜索。而外层的Obj是和Test同级别的所谓根命名,使用::才能直接引用以区别于Test内部的Obj。另外如果这时在See.p里面插一句pp Module.constants就能看见根模块空间的内容。 好了,我们已经看见“绝对”和“相对”的区别。回到主题,为什么不能直接用ActionController::UnknownAction呢?这里涉及到Rails导入模块的一些“巫术”,使得当在Controller里用ActionController的时候指向的是 ActionWebService::Container::ActionController。所以要加个::让Ruby知道用的是根级的ActionController的。 可见这是个命名冲突的Rails bug, 框架应该对用户隐藏掉这种晦涩的东西。然而这个hack也不失为解决一般的命名冲突情况的办法。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2006-10-23
我被这个问题困扰了一天,rails总是先到ActionWebService下面去找,所以总是找不到。
::ActionController::UnknownAction 有点 ../action_controller/base.rb 的感觉,呵呵。 |
|
返回顶楼 | |
发表时间:2006-10-23
嗯,好东西,攒一个,谢谢!!!
这一点与C++好像差不多.这该是namespace的问题,和路径没什么关系吧!? |
|
返回顶楼 | |
发表时间:2006-10-23
类似的问题在plugin里面也有。标准写法是写一个module,再调用某个要扩展或打补丁的类的class_eval方法,在里面include进去就行了,也可以直接写成:
class XXXModule::XXXClass # your code... end 但如果写成: module XXXModule class XXXClass # your code... end end 就不会有效果,经过调试,发现后面这种写法实际上成了Rails::Initializer::XXXModule::XXXClass。 |
|
返回顶楼 | |
发表时间:2006-10-23
奥,原来是这样呀,以后要多注意。
|
|
返回顶楼 | |
发表时间:2006-10-24
是啊rails的require方式太诡异了。难怪最近又出了个使用ActiveRecord但抛掉Rails别的部分的轻量级的ruby框架Merb,算上Camping现在一共有两个了。呼呼,看来Rails也快沦落成下一个J2EE了。
qiezi 写道 类似的问题在plugin里面也有。标准写法是写一个module,再调用某个要扩展或打补丁的类的class_eval方法,在里面include进去就行了,...
|
|
返回顶楼 | |
发表时间:2006-10-25
相对路径和绝对路径的问题.
class test class String attr_accessor :temp def initialize(temp) @temp= temp end end def initialize(temp) @temp= String.new("e") end end @temp= String.new("e")这里的String理解为test::String 如果要引用ruby内建的String,就要 ::String.new("e"); |
|
返回顶楼 | |