ruby - 在Ruby中的每个对象上覆盖诸如“#==”之类的方法?
问题描述
免责声明:这只是为了满足我的好奇心——我没有将它用于任何用途的计划。我意识到这很少是一个好主意!
我很想听听有关如何实现这一目标的任何想法,无论它们是否明智。
我怎样才能覆盖一个方法,例如#==
在Ruby中的每个对象 ( ) 上?BasicObject
我可以覆盖它BasicObject
:
class BasicObject
def ==(other); puts "custom for #{self} and #{other}!"; end
end
但是当子类也覆盖它时,这将不起作用:
true == false # Runs my custom code!
"a" == "b" # Doesn't!
# Because of this:
true.method(:==) # => #<Method: TrueClass(BasicObject)#==(_)>
"hi".method(:==) # => #<Method: String#==(_)>
前置BasicObject
也无济于事 - 子类仍然获胜 - 前置模块在列表中太远了:
String.ancestors # => [String, Comparable, Object, Kernel, MyPrependedMod, BasicObject]
我也可以手动覆盖它String
——但是尝试在每个覆盖的类上手动执行它#==
很容易出错,特别是因为任何人都可以随时在某些用户定义的类上覆盖它。
有哪些方法可以实现这一目标?
解决方案
这是我想出的一个解决方案。需要明确的是,这很可能不应该添加到代码库中。这只是为了好玩。
ObjectSpace.each_object(Class) do |klass|
next if klass.frozen? # `Object` is frozen.
klass.define_method(:==) { |other| puts "custom for #{self} and #{other}!" }
end
# These all work.
true == false
"a" == "b"
1 == 2
:hi == :bye
如果你想prepend
(例如调用super
你的覆盖),有一个问题:
ObjectSpace.each_object(Class) do |klass|
next if klass.frozen? # `Object` is frozen.
# We can't use `prepend` here since e.g. `String` overrides it.
# `prepend_features` is essentially the same thing.
(Module.new do
def ==(other); puts "custom for #{self} and #{other}!"; super; end
end).send(:prepend_features, klass)
end
# These all work.
true == false
"a" == "b"
1 == 2
:hi == :bye
除了使用prepend_features
,我们还可以确保调用BasicObject
'sprepend
而不是子类中覆盖的那个:
# Some classes, like `String`, override "prepend".
prep = BasicObject.method(:prepend).unbind
ObjectSpace.each_object(Class) do |klass|
next if klass.frozen? # `Object` is frozen.
prep.bind(klass).call(Module.new do
def ==(other); puts "custom for #{self} and #{other}!"; super; end
end)
end
# These all work.
true == false
"a" == "b"
1 == 2
:hi == :bye
推荐阅读
- python - 使用 gRPC 联网
- javascript - 使用变量导入 JavaScript 模型
- python - 使用 python 抓取 url
- python - 使用 pymongo 更改流检索删除操作的完整删除文档
- azure - 是否有任何 REST API 可用于列出 azure 资源组的所有者?
- javascript - 如何在特定半径内显示 react-native-maps
- javascript - 在 React 中使用 Axios POST 时出现 400 BAD REQUEST
- c# - 如何根据C#中的另一个属性值获取XML节点的属性值
- angular - 使用日期时间选择器获取没有时区的日期和时间
- javascript - @rollup/plugin-node-resolve 抛出错误:无法读取未定义的属性“长度”