diff --git a/lib/dry/auto_inject/method_parameters.rb b/lib/dry/auto_inject/method_parameters.rb index 56b4a1a..fbee704 100644 --- a/lib/dry/auto_inject/method_parameters.rb +++ b/lib/dry/auto_inject/method_parameters.rb @@ -10,8 +10,12 @@ class MethodParameters [%i[rest]], [%i[rest], %i[keyrest]], [%i[rest *]], - [%i[rest *], %i[keyrest **]] - ].freeze + [%i[rest *], %i[keyrest **]], + [%i[rest *], %i[block &]], + [%i[keyrest **]], + [%i[keyrest **], %i[block &]], + [%i[block &]] + ].to_set.freeze def self.of(obj, name) Enumerator.new do |y| diff --git a/lib/dry/auto_inject/strategies/kwargs.rb b/lib/dry/auto_inject/strategies/kwargs.rb index fcc9475..5581649 100644 --- a/lib/dry/auto_inject/strategies/kwargs.rb +++ b/lib/dry/auto_inject/strategies/kwargs.rb @@ -25,6 +25,7 @@ def define_initialize(klass) super_parameters = MethodParameters.of(klass, :initialize).each do |ps| # Look upwards past `def foo(*)` and `def foo(...)` methods # until we get an explicit list of parameters + break ps unless ps.pass_through? end diff --git a/spec/integration/kwargs/inheritance/parent_class_injections_spec.rb b/spec/integration/kwargs/inheritance/parent_class_injections_spec.rb index 9554af8..4adb297 100644 --- a/spec/integration/kwargs/inheritance/parent_class_injections_spec.rb +++ b/spec/integration/kwargs/inheritance/parent_class_injections_spec.rb @@ -84,10 +84,9 @@ def delegated(one:) Class.new(parent_class) do include Test::AutoInject[:one] - def initialize(*) + def initialize(**) super end - ruby2_keywords(:initialize) if respond_to?(:ruby2_keywords, true) end end diff --git a/spec/unit/method_parameters_spec.rb b/spec/unit/method_parameters_spec.rb index 2aac0ab..e04ad1a 100644 --- a/spec/unit/method_parameters_spec.rb +++ b/spec/unit/method_parameters_spec.rb @@ -45,6 +45,7 @@ def initialize(*) all_parameters = parameters.of(klass, :initialize).to_a expect(all_parameters.size).to eq 2 + if RUBY_VERSION >= "3.2" expect(all_parameters[0].parameters).to eql([[:rest, :*]]) else @@ -53,4 +54,47 @@ def initialize(*) expect(all_parameters[1]).to be_empty end end + + describe "#pass_through?" do + klass = Class.new { + def arg_kwarg(*, **) = super + + def arg(*) = super + + def kwarg(**) = super + + def ellipsis(...) = super + + if RUBY_VERSION >= "3.1" + class_eval(<<-RUBY, __FILE__, __LINE__ + 1) + def arg_kwarg_block(*, **, &) = super + + def arg_block(*, &) = super + + def kwarg_block(**, &) = super + + RUBY + else + alias_method :arg_kwarg_block, :arg + alias_method :arg_block, :arg + alias_method :kwarg_block, :kwarg + end + } + + it "returns true for pass-through methods" do + expect(parameters.of(klass, :arg_kwarg).first).to be_pass_through + expect(parameters.of(klass, :arg).first).to be_pass_through + expect(parameters.of(klass, :kwarg).first).to be_pass_through + expect(parameters.of(klass, :arg_block).first).to be_pass_through + expect(parameters.of(klass, :kwarg_block).first).to be_pass_through + end + + it "returns false for non-pass-through methods" do + # ellipsis are treated differently because + # it can be used for delegation to methods other than super + expect(parameters.of(klass, :ellipsis).first).not_to be_pass_through + # same signature + expect(parameters.of(klass, :arg_kwarg_block).first).not_to be_pass_through + end + end end