60

Rubyでメソッドの定義を解除するのは非常に簡単で、使用するだけundef METHOD_NAMEです。

クラスに似たものはありますか?私は上にいMRI 1.9.2ます。

ActiveRecordモデルの定義を解除し、2行のコードを実行して、モデルを元の形式に復元する必要があります。

問題は、私がモデルを持ってい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クラスの1つを別の名前空間に移動してみませんか。

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 に答える