在 Ruby 中取消定义方法非常简单,我可以使用undef METHOD_NAME
.
有没有类似的类?我在MRI 1.9.2
。
我必须取消定义 ActiveRecord 模型,运行两行代码,然后将模型恢复为原始形式。
问题是,我有一个模型Contact
并且我正在使用公司的 API,并且碰巧他们有一些名为 的类Contact
,更改我的模型名称对我来说是很多工作。
在这种情况下我能做什么?
在 Ruby 中取消定义方法非常简单,我可以使用undef METHOD_NAME
.
有没有类似的类?我在MRI 1.9.2
。
我必须取消定义 ActiveRecord 模型,运行两行代码,然后将模型恢复为原始形式。
问题是,我有一个模型Contact
并且我正在使用公司的 API,并且碰巧他们有一些名为 的类Contact
,更改我的模型名称对我来说是很多工作。
在这种情况下我能做什么?
class Foo; end
# => nil
Object.constants.include?(:Foo)
# => true
Object.send(:remove_const, :Foo)
# => Foo
Object.constants.include?(:Foo)
# => false
Foo
# NameError: uninitialized constant Foo
编辑刚刚注意到您的编辑,删除常量可能不是实现您正在寻找的最佳方式。为什么不将其中一个Contact
类移到单独的命名空间中。
EDIT2你也可以像这样临时重命名你的类:
class Foo
def bar
'here'
end
end
TemporaryFoo = Foo
Object.send(:remove_const, :Foo)
# do some stuff
Foo = TemporaryFoo
Foo.new.bar #=> "here"
同样,这样做的问题是您仍然拥有较新的Contact
课程,因此您必须再次删除它。我真的会建议为您的课程命名空间。这也将帮助您避免任何加载问题
在类似的情况下 - 模拟我正在尝试测试的另一个类在内部使用的类 - 我发现这是一个可行的解决方案:
describe TilesAuth::Communicator do
class FakeTCPSocket
def initialize(*_); end
def puts(*_); end
end
context "when the response is SUCCESS" do
before do
class TilesAuth::Communicator::TCPSocket < FakeTCPSocket
def gets; 'SUCCESS'; end
end
end
after { TilesAuth::Communicator.send :remove_const, :TCPSocket }
it "returns success" do
communicator = TilesAuth::Communicator.new host: nil, port: nil, timeout: 0.2
response = communicator.call({})
expect(response["success"]).to eq(true)
expect(response).not_to have_key("error")
expect(response).not_to have_key("invalid_response")
end
end
end
我原以为会有更好的方法来做到这一点 - 即我看不到传递所需返回值以供重用的方法 - 但现在这似乎已经足够好了。我是模拟/工厂的新手,我很想听听任何替代方法。
编辑:
好吧,毕竟不是那么相似。
由于RSpec Google Group 中的出色解释,我找到了使用 RSpec 模拟的更好方法:
context "with socket response mocked" do
let(:response) do
tcp_socket_object = instance_double("TCPSocket", puts: nil, gets: socket_response)
class_double("TCPSocket", new: tcp_socket_object).as_stubbed_const
communicator = TilesAuth::Communicator.new host: nil, port: nil, timeout: 0.2
communicator.call({})
end
context "as invalid JSON" do
let(:socket_response) { 'test invalid json' }
it "returns an error response including the invalid socket response" do
expect(response["success"]).to eq(false)
expect(response).to have_key("error")
expect(response["invalid_response"]).to eq(socket_response)
end
end
context "as SUCCESS" do
let(:socket_response) { 'SUCCESS' }
it "returns success" do
expect(response["success"]).to eq(true)
expect(response).not_to have_key("error")
expect(response).not_to have_key("invalid_response")
end
end
end