Created
August 20, 2019 01:03
-
-
Save havenwood/db041566abeac894602c188c77374040 to your computer and use it in GitHub Desktop.
A little spike on implementing currying for keyword arguments after reading: https://bugs.ruby-lang.org/issues/16113
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module KeywordCurry | |
refine Method do | |
def curry(curry_arity = nil) | |
to_proc.curry(curry_arity) | |
end | |
end | |
refine Proc do | |
def curry(curry_arity = nil) | |
params = parameters | |
min_args = params.count { |type, _| type == :req } | |
if curry_arity && lambda? | |
unless arity.negative? && arity != curry_arity | |
raise ArgumentError, "Wrong number of arguments (#{curry_arity} for #{arity})" | |
end | |
max_args = params.count { |type, _| type != :block } | |
no_rest = params.none? { |type, _| type == :rest } | |
if curry_arity < min_args || no_rest && curry_arity > max_args | |
additional = no_rest ? "..#{max_args}" : '+' | |
raise ArgumentError, 'Wrong number of arguments ' \ | |
"(given #{curry_arity}, expected #{min_args}#{additional})" | |
end | |
end | |
req_kwargs = params.filter_map { |type, name| name if type == :keyreq } | |
-> *args, **kwargs do | |
currying_done = !curry_arity&.-(args.size)&.nonzero? | |
args_met = args.size >= min_args | |
kwargs_met = req_kwargs.all? { |req_kwarg| kwargs.key? req_kwarg } | |
if currying_done && args_met && kwargs_met | |
call(*args + kwargs.map { |key, value| {key => value} }) | |
else | |
-> *curry_args, **curry_kwargs do | |
curry(curry_arity).call(*args, *curry_args, **kwargs, **curry_kwargs) | |
end | |
end | |
end | |
end | |
end | |
end | |
require 'json' | |
require 'minitest/autorun' | |
require 'minitest/pride' | |
describe KeywordCurry do | |
using KeywordCurry | |
it 'curries keyword arguments' do | |
assert_equal JSON.:parse.curry.call(symbolize_names: true).call('{"aim":true}'), aim: true | |
end | |
it 'accepts a curried arity' do | |
h = {first: {second: {third: 42}}} | |
assert_equal h.:dig.curry(3).call(:first).call(:second).call(:third), 42 | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
👀