ruby-on-rails - Ruby:使用 class_eval 定义常量只能通过 const_get 找到,但不能直接通过 :: 查找
问题描述
给定一个用户类:
class User
end
我想使用.class_eval
. 所以:
User.class_eval { AVOCADO = 'fruit' }
如果我尝试通过 访问它
User::AVOCADO
,我会得到uninitialized constant User::AVOCADO
,但User.const_get(:AVOCADO)
可以。为什么?如果我在
included
方法的 Rails Concern 中定义了一个常量并将该关注点包含在User
类中,我可以通过常规::
查找来访问它。例如:
module FruitConcern
extend ActiveSupport::Concern
included do
AVOCADO = 'fruit'
end
end
class User
include FruitConcern
end
User::AVOCADO
=> 'fruit'
但是,查找 ActiveSupport::Concern 的源代码,included
只需将该块存储在实例变量 ( @_included_block
) 中,然后将其覆盖append_features
will call base.class_eval(&@_included_block)
。
所以,如果它只是User.class_eval
用同一个块调用,为什么User::AVOCADO
在该块内定义常量时起作用included
,但当我User.class_eval { AVOCADO = 'fruit' }
直接调用时不起作用?
- 奇怪的是(见这篇博文),当做 时
User.class_eval { AVOCADO = 'teste' }
,似乎 Ruby 也将常量泄漏到顶层。所以:
User.const_get(:AVOCADO)
=> "fruit"
AVOCADO
=> 'fruit'
我知道块有平面范围,但没有事先定义常量,我希望class_eval
同时改变接收器self
和default definee
接收器。这里发生了什么?这个常量是如何在顶层和用户范围内定义两次的?
解决方案
当您定义常量时,您不会将常量分配给self。您正在当前模块嵌套中定义一个常量。
当您显式打开一个类或模块时,您还设置了模块嵌套:
module Foo
BAR = 1
puts Module.nesting.inspect # [Foo]
end
当你做User.class_eval { AVOCADO = 'fruit' }
模块嵌套是“主要”又名全局对象:
User.class_eval do
ADVOCADO = 'Fruit'
puts Module.nesting.inspect # []
end
块实际上并不改变模块嵌套。const_set
另一方面,在另一个模块嵌套中定义了一个常量。
Ruby 实际上也没有两次定义常量。相反,当您使用 const_get 或引用常量而不明确使用范围解析运算符时,Ruby 将查看模块嵌套并将树向上移动到全局范围:
class A
end
B = 'eureka'
A.const_get(:B) # 'eureka'
这就是您可以引用顶级常量而不用::
. 但是,当您使用时,User::ADVOCADO
您会明确引用User
.
当谈到这个例子时,你误解了正在发生的事情。一点也不约class_eval
。您正在定义常量FruitConcern::AVOCADO
。
然后,当您包含在内时,您将添加FruitConcern
到包含在常量查找中的祖先链中:User
FruitConcern
module FruitConcern
ADVOCADO = 'fruit'
end
class User
include FruitConcern
end
User::ADVOCADO # fruit
看:
推荐阅读
- web-component - 扩展的 HTML 元素:“是”,包裹一个 HTML 元素,或其他任何东西 - 当前状态是什么?
- google-bigquery - 使用 OVER PARTITION BigQuery 在给定时间之前获取最新记录
- onedrive - 将文件从本地共享复制到共享一个驱动器文件夹
- javascript - 在命名空间存储中调度操作 (Vuex/Nuxt)
- c - C:scanf() 挂起,getchar() 无法清除输入
- json - 如何在 Swift 中映射这个 JSON?
- java - Spring Data JPA 将存储过程结果从多个数据源映射到非实体 POJO
- r - 在本地采购 Rcpp 可以工作,但不能并行化
- r - 为什么我不能在 RStudio 中安装 Plotly 包?错误说明了什么?
- javascript - 2个错误:(未捕获的ReferenceError:未定义要求)&(npm ERR!缺少脚本:开始)