ruby - 在 Ruby 中,是否可以在超类的子类中定义常量?
问题描述
假设我有一个由许多子类扩展的 Ruby 类。我希望这些子类中的每一个都有一个名为FRIENDLY_NAME
. 显然,我可以编辑每个类并添加常量。但是,如果它没有在子类中指定,有没有办法在超类的子类中定义一个常量?
例如,当尚未定义时,也许我可以将每个子类设置FRIENDLY_NAME
为子类的类名解调和下划线。FRIENDLY_NAME
解决方案
直到关于TracePoint
!
为了扩展我原来的问题,我有一个我想多次扩展的超类:
class BaseClass
end
我希望该类的所有扩展版本都有一个FRIENDLY_NAME
常量。当在子类中明确指定时,这将是常量的值。例如:
class Subclass1 < BaseClass
FRIENDLY_NAME = 'Bob seems like a friendly name!'
end
因此:
pry(main)> Subclass1::FRIENDLY_NAME
=> "Bob seems like a friendly name!"
但是,也许我有另一个没有定义常量的子类。例如:
class Subclass2 < BaseClass
end
这就是我在没有常数的情况下得到的(显然):
pry(main)> Subclass2::FRIENDLY_NAME
NameError: uninitialized constant Subclass2::FRIENDLY_NAME
from /bundle/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/active_support.rb:79:in `block in load_missing_constant'
Caused by NameError: uninitialized constant Subclass2::FRIENDLY_NAME
from /bundle/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/active_support.rb:60:in `block in load_missing_constant'
如何添加该常数?您可以添加self.inherited
到超类。每次扩展超类时都会调用此方法。Module
在named上还有一个方法const_set
,所以我可以像这样自动设置孩子的常量:
class BaseClass
def self.inherited(child)
child.const_set(:FRIENDLY_NAME, child.name)
end
end
这适用于Subclass2
:
pry(main)> Subclass2::FRIENDLY_NAME
=> "Subclass2"
但是,它会产生丑陋的警告Subclass1
(pry):10: warning: already initialized constant Subclass1::FRIENDLY_NAME
(pry):3: warning: previous definition of FRIENDLY_NAME was here
最初我尝试使用该const_defined?
方法来检查是否FRIENDLY_NAME
已经定义了常量。问题是,在子类中定义常量之前self.inherited
调用该方法。基本上,只要 Ruby 看到它运行.< BaseClass
self.inherited
最终我发现了这个关于如何在定义类后执行代码的问题。答案是使用TracePoint
.
TracePoint
是一个允许我们在代码中处理事件的类。这些可能是在执行一行代码时,当我们调用一个方法时,当引发错误时等等。我们关心的是:end
事件,它发生在类或模块定义完成时。
知道了这一点,我们可以self.inherited
像这样更新我们的方法:
class BaseClass
def self.inherited(child)
TracePoint.trace(:end) do |t|
if child == t.self
unless child.const_defined?(:FRIENDLY_NAME)
child.const_set(:FRIENDLY_NAME, child.code)
end
end
end
end
end
现在,两者Subclass1
都有Subclass2
一个FRIENDLY_NAME
常数,但都不会产生警告!
推荐阅读
- c - 用串口连接程序和 Arduino
- opencv - 如何在 OpenCV 中实现类似 Photoshop 的效果 OilPaint 效果?
- python - 脸书情绪分析
- ios - 如何转换数组数组的元组<(键:字符串,值:数组
)> 到数组字典字典 >? - cordova - 具有电容器和 Cordova 的 Ionic 应用程序
- python - Python 游戏总是崩溃或卡住 | 游戏
- ubuntu - 临时端口上大量阻塞的传入请求
- c# - 在 C# 中是否有一种更高效的方式来清除文本框?
- c++ - 如何从整个磁盘中排除要挂载的一个文件
- rust - 使用 Rust 语言编译问题:从“Hello World”开始