0

私の人生では、これに対する簡単な説明を見つけることはできません。

私は、独自のカスタム コードを持つプロジェクトに取り組んでいますが、gem が含まれているクラスの拡張機能やオーバーライドもいくつか持っています。

これを達成するための正しいフォルダ構造とモジュールの命名パターンは何ですか?

たとえば、サードパーティの「parallel_tests」gem の拡張用にコードを編成する方法を次に示します。私が取り組んでいるライブラリは「ChemistyKit」と呼ばれます。

lib/
  chemistrykit/
     parallel_tests/ # the gem name space i'm extending
       rspec/ 
         runner.rb

したがって、基本的には、そのparallel_testsフォルダーの下にある gem と同じ命名構造に従います。

次に、そのrunner.rbファイルには次のようなものがあります。

module ChemistryKit
  module ParallelTests
    module RSpec
      class Runner < ParallelTests::Test::Runner

ただし、これを使用するとエラーが発生します。RSpec HTML フォーマッタのこの拡張のChemistryKitようなものでは、フォーマッタは gem の最上位の名前空間の下で使用されるため、紛らわしいですが、これは紛らわしいです。この場合、名前は似ているが異なるクラスを作成しているためですか?意図はオーバーライドではなく、拡張することですか?

4

1 に答える 1

1

RSpec の Runner クラスを完全に置き換えるには、次のようにします。

module RSpec
  module Core
    remove_const(:Runner)
    class Runner < ParallelTests::Test::Runner
      ...
    end
  end
end

モジュール内のコードは、その名前に基づくパスを使用して定数を検索します。したがって、例で定義する Runner クラスは定数を参照しますChemistryKit::ParallelTests::RSpec::Runner

次の例のように、RSpec モジュールがグローバル名前空間にあることを指定することにより、モジュールの 1 つの内部から RSpec Runner を参照できます。

module ChemistryKit
  module ParallelTests
    module ::RSpec
      module Core
        class Runner < ParallelTests::Test::Runner

これを行ったとしても、この方法でクラスを変更することには別の問題があります。クラスを置き換えたいので、最初にそれを削除する必要があります。それ以外の場合は、既存のクラスを変更するだけです(別のスーパークラスを指定すると、クラスを再度開くことはできません。rspec ランナーは既にオブジェクトのサブクラスであり、できるそれを変更しないでください)。それがremove_const、最初の例の呼び出しの目的です。

ただし、余分なモジュールは、上記の例では実際には何もしませんが、物事を明確にしません。既存の gem のコードを変更するときは、すべてのコードを rspec サブフォルダーに (あなたのように) 入れるだけで問題ありませんが、元のものとまったく同じモジュール名を使用します。

この方法でクラスを変更すると、非常に簡単に失敗する可能性があることに注意してください。たとえば、クラスが必要なときに使用された場合、その後まで置換が行われず、予期しない問題が発生する可能性があります。これが、リンクしたフォーマッタの例が別のアプローチを取る理由です。コードは RSpec にモンキーパッチを適用するのではなく、実行時に新しいクラスをアタッチします。

于 2013-08-10T18:56:18.587 に答える