Ruby on rails Ruby:使用class_eval定义常量只能通过const_get找到,而不能直接通过::lookup找到
给定一个用户类:Ruby on rails Ruby:使用class_eval定义常量只能通过const_get找到,而不能直接通过::lookup找到,ruby-on-rails,ruby,Ruby On Rails,Ruby,给定一个用户类: 类用户 结束 我想使用.class\u eval定义一个新常量。因此: User.class_eval{AVOCADO='fruit'} 如果我试图通过User::AVOCADO访问它,我会得到未初始化的常量User::AVOCADO,但是User.const\u get(:AVOCADO)有效。为什么? 如果我在included方法中在Rails关注点中定义了一个常量,并将该关注点包含在User类中,我可以通过常规的:查找来访问它。例如: module关注点 扩展Ac
类用户
结束
我想使用.class\u eval
定义一个新常量。因此:
User.class_eval{AVOCADO='fruit'}
User::AVOCADO
访问它,我会得到未初始化的常量User::AVOCADO
,但是User.const\u get(:AVOCADO)
有效。为什么?
included
方法中在Rails关注点中定义了一个常量,并将该关注点包含在User
类中,我可以通过常规的:
查找来访问它。例如:
module关注点
扩展ActiveSupport::关注点
包括做
鳄梨=‘水果’
结束
结束
类用户
包括水果关切
结束
用户:鳄梨
=>“水果”
但是,在查找ActiveSupport::Concern时,included
只将该块存储在一个实例变量(@\u included\u block
)中,然后它对append\u功能的覆盖将调用base.class\u eval(&@\u included\u block)
那么,如果它只是用同一个块调用User.class_eval
,为什么User::AVOCADO
在included
块中定义常量时有效,而在我直接调用User.class_eval{AVOCADO='fruit'}
时无效
奇怪的是(请参阅),在执行User.class_eval{AVOCADO='teste'}
时,Ruby似乎也将常量泄漏到了顶层。因此:
User.const\u get(:鳄梨)
=>“水果”
鳄梨
=>“水果”
我知道块的作用域是平坦的,但常数事先没有定义,我希望class_eval
将self
和默认定义对象更改为接收方。这是怎么回事?如何在顶层和用户范围内两次定义此常量?定义常量时,您没有将常量分配给self。您正在当前模块嵌套中定义一个常量
当您显式打开一个类或模块时,您也在设置模块嵌套:
module Foo
BAR = 1
puts Module.nesting.inspect # [Foo]
end
执行User.class_eval{AVOCADO='fruit'}
时,模块嵌套为“Main”,即全局对象:
User.class_eval do
ADVOCADO = 'Fruit'
puts Module.nesting.inspect # []
end
块实际上不会更改模块嵌套<另一方面,code>const_set
在另一个模块嵌套中定义了一个常量
Ruby实际上也没有两次定义常量。相反,当您使用const_get或引用一个常量而不显式使用scope resolution操作符时,Ruby将查看模块嵌套并将树遍历到全局作用域:
class A
end
B = 'eureka'
A.const_get(:B) # 'eureka'
这就是如何引用顶级常量,而不必在它们前面加上:
。但是当您使用User::ADVOCADO
时,您显式地引用了User
中的常量
当涉及到这个例子时,你已经误解了正在发生的事情。完全不是关于类的评估
。您正在定义常量水果关注::鳄梨
然后,当您将水果关注点
包含到用户
中时,您正在将水果关注点
添加到包含在持续查找中的祖先链中:
module FruitConcern
ADVOCADO = 'fruit'
end
class User
include FruitConcern
end
User::ADVOCADO # fruit
见:
有:
self
,“当前对象”:隐式接收器和实例变量的作用域
- 默认定义对象:其中使用
def bar
定义的方法最终没有明确的目标(即非def foo.bar
)
- 恒定范围
前两个在链接的文章中解释得很好。链接文章中承诺为第三篇撰写一篇文章,但从未出现过。许多人已经写了很多关于常量的文字,但不幸的是,没有人编写过权威的规范,类似于yugui为默认定义者所做的
因此,不幸的是,我也只能猜测,因此毫无帮助地增加了关于这个话题的大量非权威性文字
块在Ruby中是词汇范围的,它们捕获它们的词汇环境。通常,这意味着块内的引用与块外的引用的含义完全相同,就好像块不在那里一样。(当然,块局部变量除外。)
所以
foo{AVOCADO='fruit'}
意思和
鳄梨=‘水果’
当然,除非,foo
以某种方式更改了计算块的上下文。我们知道,instance\u eval
改变了self
。我们知道class\u eval
更改了self
和默认的定义者。但是,重要的是:class_eval
不会更改隐式常量范围
因此,分配AVOCADO='fruit'
inside
User.class_eval{AVOCADO='fruit'}
与位于区块外时的含义完全相同:
鳄梨=‘水果’
换言之,它的含义与顶层的常量赋值相同,正如我们所知,在顶层:
self
是未命名的单例对象,通常称为main
- 默认的定义对象是
对象
,增加了方法在默认情况下变为私有
,以及
- 隐式常量范围也是
对象
因此,AVOCADO
在Object
中定义
这意味着以下工作:
类用户
鳄梨
结束
#=>“水果”
因为常量查找首先在词汇上“向外”(在本例中它失败),然后在继承层次结构中“向上”,在继承层次结构中它成功,因为User
隐式地是Object
的子类
User.const\u get(:鳄梨)
#=>“水果”
肌萎缩侧索硬化