Skip to content

Commit

Permalink
Recognize more pass-through constructor signatures (fix #91)
Browse files Browse the repository at this point in the history
  • Loading branch information
flash-gordon committed Nov 12, 2023
1 parent 4c703d5 commit c03294e
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 4 deletions.
8 changes: 6 additions & 2 deletions lib/dry/auto_inject/method_parameters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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|
Expand Down
1 change: 1 addition & 0 deletions lib/dry/auto_inject/strategies/kwargs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
44 changes: 44 additions & 0 deletions spec/unit/method_parameters_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

0 comments on commit c03294e

Please sign in to comment.