lib/abstractivator/proc_ext.rb in abstractivator-0.4.0 vs lib/abstractivator/proc_ext.rb in abstractivator-0.4.1

- old
+ new

@@ -1,12 +1,13 @@ require 'abstractivator/enumerable_ext' +require 'abstractivator/array_ext' module MethodAndProcExtensions # returns a version of the procedure that accepts any number of arguments def loosen_args - proc do |*args, &block| - Proc.loose_call(self, args, &block) + proc do |*args, **kws, &block| + Proc.loose_call(self, args, kws, &block) end end end class Proc @@ -52,14 +53,34 @@ end # tries to coerce x into a procedure, then calls it with # the given argument list. # If x cannot be coerced into a procedure, returns x. - def self.loose_call(x, args, &block) + def self.loose_call(x, args, kws={}, &block) x = x.to_proc if x.respond_to?(:to_proc) x.callable? or return x - args = args.take(x.arity).pad_right(x.arity) if x.arity >= 0 - x.call(*args, &block) + arg_types = x.parameters.map(&:first) + # customize args + req_arity = arg_types.select{|x| x == :req}.size + total_arity = req_arity + arg_types.select{|x| x == :opt}.size + accepts_arg_splat = arg_types.include?(:rest) + unless accepts_arg_splat + args = args.take(total_arity).pad_right(req_arity) + end + # customize keywords + accepts_kw_splat = arg_types.include?(:keyrest) + unless accepts_kw_splat + opt_key_names = x.parameters.select{|(type, name)| type == :key && !name.nil?}.map(&:value) + req_key_names = x.parameters.select{|(type, name)| type == :keyreq && !name.nil?}.map(&:value) + all_key_names = opt_key_names + req_key_names + padding = req_key_names.hash_map{nil} + kws = padding.merge(kws.select{|k| all_key_names.include?(k)}) + end + if kws.any? + x.call(*args, **kws, &block) + else + x.call(*args, &block) + end end end class Method include MethodAndProcExtensions