我最近遇到了一个问题,load
在 Ruby 类上调用两次会导致错误(这是一个真实的示例)。这是因为在类主体中发生了有状态的方法调用,并load
导致这些方法被执行两次。一个简单的例子如下:
base.rb
:
class Base
def foo
puts "BASE"
end
end
derived.rb
:
require "./base"
class Derived < Base
alias_method :foo_aliased, :foo
def foo
puts "DERIVED!"
end
end
从 REPL 执行:
$ load './derived.rb'
> true
$ Derived.new.foo
> DERIVED!
> nil
$ Derived.new.foo_aliased
> BASE
> nil
$ load './derived.rb'
> true
$ Derived.new.foo
> DERIVED!
> nil
$ Derived.new.foo_aliased
> DERIVED!
> nil
在此示例中,第二个load
原因alias_method
破坏了原始别名。结果,我们破坏了任何依赖于原始方法具有完整别名的代码。
蛮力类重新加载很常见(例如,您在each_run
使用 Spork 的 RSpec 配置的条款中看到了很多),完全禁止使用并不总是那么容易load
。因此,似乎防止错误的唯一方法是确保类定义是“幂等的”。换句话说,您已经确保打算从类定义中调用的方法无论调用多少次都应该产生相同的结果。重新加载不会破坏更多代码的事实似乎暗示了一种不言而喻的约定。
是否有一些针对 Ruby 类设计的风格指南要求这样做?如果是这样,执行这些语义的常用技术是什么?对于某些方法,您可以只做一些记忆以防止使用相同的参数重新执行相同的方法,但其他一些事情alias_method
似乎更难解决。