60

在 Ruby 中取消定义方法非常简单,我可以使用undef METHOD_NAME.

有没有类似的类?我在MRI 1.9.2

我必须取消定义 ActiveRecord 模型,运行两行代码,然后将模型恢复为原始形式。

问题是,我有一个模型Contact并且我正在使用公司的 API,并且碰巧他们有一些名为 的类Contact,更改我的模型名称对我来说是很多工作。

在这种情况下我能做什么?

4

2 回答 2

103
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课程,因此您必须再次删除它。我真的会建议为您的课程命名空间。这也将帮助您避免任何加载问题

于 2012-07-16T11:47:51.163 回答
2

在类似的情况下 - 模拟我正在尝试测试的另一个类在内部使用的类 - 我发现这是一个可行的解决方案:

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
于 2016-02-25T14:11:44.170 回答