diff --git a/lib/dry/auto_inject/dependency_map.rb b/lib/dry/auto_inject/dependency_map.rb index ff8db61..52215bf 100644 --- a/lib/dry/auto_inject/dependency_map.rb +++ b/lib/dry/auto_inject/dependency_map.rb @@ -5,7 +5,7 @@ module AutoInject DuplicateDependencyError = Class.new(StandardError) DependencyNameInvalid = Class.new(StandardError) - VALID_NAME = /([a-z_][a-zA-Z_0-9]*)$/.freeze + VALID_NAME = /([a-z_][a-zA-Z_0-9]*)$/ class DependencyMap def initialize(*dependencies) diff --git a/lib/dry/auto_inject/method_parameters.rb b/lib/dry/auto_inject/method_parameters.rb index 56b4a1a..0b5d76b 100644 --- a/lib/dry/auto_inject/method_parameters.rb +++ b/lib/dry/auto_inject/method_parameters.rb @@ -9,9 +9,22 @@ class MethodParameters PASS_THROUGH = [ [%i[rest]], [%i[rest], %i[keyrest]], + [%i[keyrest]], + [%i[keyrest], %i[block &]], + [%i[block]], [%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 + + unless RUBY_VERSION < "3.1" + PASS_THROUGH << [%i[rest *], %i[block &]] + end + + PASS_THROUGH.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/super_initialize_spec.rb b/spec/integration/kwargs/super_initialize_spec.rb index b8d5c85..e636a96 100644 --- a/spec/integration/kwargs/super_initialize_spec.rb +++ b/spec/integration/kwargs/super_initialize_spec.rb @@ -112,8 +112,7 @@ def initialize(*args) Class.new do # rubocop:disable Lint/RedundantCopDisableDirective # rubocop:disable Style/RedundantInitialize - def initialize - end + def initialize; end # rubocop:enable Style/RedundantInitialize # rubocop:enable Lint/RedundantCopDisableDirective 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