Skip to content

Commit 05934f7

Browse files
committed
Handle keyword arguments in a Ruby 3.0 world.
Now that keyword arguments are no longer implicitly translated into hashes, we need to explicitly handle them as a separate argument type. This commit may not cover all cases (either from a code or spec perspective), but hopefully it’s at least a useful start.
1 parent df19988 commit 05934f7

File tree

3 files changed

+30
-8
lines changed

3 files changed

+30
-8
lines changed

lib/dry/transformer/function.rb

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ class Function
2525
# @api private
2626
attr_reader :args
2727

28+
# Additional keyword arguments that will be passed to the wrapped proc
29+
#
30+
# @return [Hash]
31+
#
32+
# @api private
33+
attr_reader :kwargs
34+
2835
# @!attribute [r] name
2936
#
3037
# @return [<type] The name of the function
@@ -36,6 +43,7 @@ class Function
3643
def initialize(fn, options = {})
3744
@fn = fn
3845
@args = options.fetch(:args, [])
46+
@kwargs = options.fetch(:kwargs, {})
3947
@name = options.fetch(:name, fn)
4048
end
4149

@@ -46,8 +54,8 @@ def initialize(fn, options = {})
4654
# @alias []
4755
#
4856
# @api public
49-
def call(*value)
50-
fn.call(*value, *args)
57+
def call(*value, **additional_kwargs)
58+
fn.call(*value, *args, **(kwargs).merge(additional_kwargs))
5159
end
5260
alias_method :[], :call
5361

@@ -71,15 +79,15 @@ def compose(other)
7179
# @return [Function]
7280
#
7381
# @api private
74-
def with(*args)
75-
self.class.new(fn, name: name, args: args)
82+
def with(*args, **additional_kwargs)
83+
self.class.new(fn, name: name, args: args, kwargs: kwargs.merge(additional_kwargs))
7684
end
7785

7886
# @api public
7987
def ==(other)
8088
return false unless other.instance_of?(self.class)
8189

82-
[fn, name, args] == [other.fn, other.name, other.args]
90+
[fn, name, args, kwargs] == [other.fn, other.name, other.args, other.kwargs]
8391
end
8492
alias_method :eql?, :==
8593

@@ -99,7 +107,7 @@ def to_ast
99107
#
100108
def to_proc
101109
if !args.empty?
102-
proc { |*value| fn.call(*value, *args) }
110+
proc { |*value| fn.call(*value, *args, **kwargs) }
103111
else
104112
fn.to_proc
105113
end

lib/dry/transformer/registry.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ module Registry
4545
#
4646
# @alias :t
4747
#
48-
def [](fn, *args)
48+
def [](fn, *args, **kwargs)
4949
fetched = fetch(fn)
5050

51-
return Function.new(fetched, args: args, name: fn) unless already_wrapped?(fetched)
51+
return Function.new(fetched, args: args, kwargs: kwargs, name: fn) unless already_wrapped?(fetched)
5252

5353
args.empty? ? fetched : fetched.with(*args)
5454
end

spec/unit/registry_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
def self.prefix(value, prefix)
99
"#{prefix}_#{value}"
1010
end
11+
12+
def self.trim(value, limit:)
13+
value[0..(limit - 1)]
14+
end
1115
end
1216
end
1317

@@ -32,6 +36,16 @@ def self.prefix(value, prefix)
3236
expect(transproc["qux"]).to eql "baz_qux"
3337
end
3438
end
39+
40+
context "with keyword arguments" do
41+
it "passes keywords through" do
42+
expect(foo[:trim]["string", limit: 3]).to eql("str")
43+
end
44+
45+
it "works with a transproc approach" do
46+
expect(foo[:trim, limit: 2]["string"]).to eql("st")
47+
end
48+
end
3549
end
3650

3751
describe ".t" do

0 commit comments

Comments
 (0)