在Ruby中取消定义方法非常简单,我可以使用undef METHOD_NAME
。
班级有类似的东西吗?我在MRI 1.9.2
。
我必须取消定义ActiveRecord模型,运行两行代码,然后将模型恢复为原始形式。
问题是,我有一个模型Contact
,我正在使用公司的API,而且他们有一个名为Contact
的类,并且更改我的模型名称对我来说将是很多工作。
在这种情况下我该怎么办?
答案 0 :(得分:83)
>> 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
课程,因此您必须再次删除它。我真的建议你的类名称间距。这也可以帮助您避免任何加载问题
答案 1 :(得分:1)
在类似的情况下 - 模拟我试图测试的另一个类在内部使用的类 - 我发现这是一个可行的解决方案:
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
我原本以为会有更好的方法来做到这一点 - 也就是说我无法找到一种方法来传递所需的返回值以供重用 - 但现在这似乎已经足够了。我是嘲笑/工厂的新手,我很乐意听到任何替代方法。
编辑:
好吧,毕竟不那么相似。
由于an excellent explanation in the 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