web-dev-qa-db-ja.com

Rubyでクラスを未定義にする方法は?

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

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

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

問題は、モデルContactがあり、会社のAPIを使用しているときにContactと呼ばれるクラスがあり、モデル名を変更するのが大変なことです。

この状況で何ができますか?

49
Bhushan Lodha
>> 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

[〜#〜] edit [〜#〜]編集に気付いたばかりですが、定数を削除することはおそらく探しているものを達成するための最良の方法ではありません。なぜ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クラスがまだあるため、再度削除する必要があることです。代わりに、クラスの名前をスペースで区切ることをお勧めします。これは、読み込みの問題を回避するのにも役立ちます

84
Lee Jarvis

同様の状況-私がテストしようとしている別のクラスによって内部的に使用されるクラスをモックする-私はこれが実行可能なソリューションであることがわかりました:

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
1
ZimbiX