とりあえずコード書けよ

技術的なことの備忘録。

Dry::AutoInjectでinitializeをオーバーライドした時にArgumentError: wrong number of arguments (given 1, expected 0)になる

結論

  • Dry::AutoInjectでincludeしているクラスにネストしたクラスが別ファイルで存在しているとダメだった
  • とりあえずネストしたクラスの構成を変える or includeしているクラスの中にクラスを書く

状況

  • クラスFooServiceでDry::AutoInjectを使って、ContainerからDIをしている
  • クラスFooServiceのinitializeをオーバーライドして、DI以外の処理を挿入していた
  • クラスFooServiceにネストしたクラスを別で定義している(コードの良し悪しは置いといて下記のようなイメージ)
# foo_service.rb
class FooService
  Import = Dry::AutoInject(MyContainer)
  include Import[hoge_repository: 'repositories.hoge']

  def initialize(hoge:, **args)
     super(**args)

     @hoge = hoge
     ...
  end

  def call
     bar = Bar.new
     bar.fuga
     ...
  end
end

# foo_service/bar.rb
class FooService
  class Bar
     def fuga
       # FooServiceで使うなんかの処理とか
     end
  end
end

症状

この状態で次のようにinitializeが実行されるとでエラーが発生する

# foo_service_test.rb
class FooServiceTest < ActiveSupport::TestCase
  test 'なんかのテスト' do
    hoge = "hoge"
    hoge_repository_mock = Minitest::Mock.new
    service = FooService.new(hoge: hoge, hoge_repository: hoge_repository_mock)
  end
end
...
# 実行結果
ArgumentError: wrong number of arguments (given 1, expected 0)
    /Users/xxxxxx/.rbenv/versions/**/lib/ruby/gems/**/gems/dry-auto_inject-1.0.0/lib/dry/auto_inject/strategies/kwargs.rb:45:in `block (2 levels) in define_initialize_with_keywords'
    /Users/xxxxxx/**/foo_service.rb:*:in `initialize'
    /Users/xxxxxx/.rbenv/versions/**/lib/ruby/gems/**/gems/dry-auto_inject-1.0.0/lib/dry/auto_inject/strategies/kwargs.rb:19:in `new'
    /Users/xxxxxx/.rbenv/versions/**/lib/ruby/gems/**/gems/dry-auto_inject-1.0.0/lib/dry/auto_inject/strategies/kwargs.rb:19:in `block (2 levels) in define_new'
    /Users/xxxxxx/**/foo_service_test.rb:**:in `block in <class:FooServiceTest>'

オーバーライドしてもsuper()に、DIする引数を渡せばオーバーライドできるはずなのに、super()で引数を受け付けていないという状態になる

対策

  1. クラスの構成を変える
# foo_service/bar.rb
class Bar
   def fuga
     # FooServiceで使うなんかの処理とか
   end
end
  1. ネスト元のクラスに定義する
# foo_service.rb
class FooService
  Import = Dry::AutoInject(MyContainer)
  include Import[hoge_repository: 'repositories.hoge']  
  
  def initialize(hoge:, **args)
     super(**args)

     @hoge = hoge
     ...
  end

  class Bar
     def fuga
     end
  end
end

他のクラスでオーバーライドできていたのに、これに該当するクラスでなぜかinitializeのオーバーライドが効かず、めちゃくちゃ沼った。 ちゃんとコードを追った上でコントリビュートするべきなのだろうけど、時間の捻出がなかなかできず... 一旦書き置き。