class EcoRake module Base module MethodHelpers # Calls `method` with just the parameters it requires # @note missing arguments required arguments will be passed as `nil` value. # @return the result of the call. def safe_call(meth, *args, **kargs, &block) msg = "Expecting Method or Proc. Given: #{meth.class}" raise ArgumentError, msg unless [Method, Proc].any? {|c| meth.is_a?(c)} aux_curry(meth, :safe).call(*args, **kargs, &block) end # @param meth [Method, Proc, Lambda] # @param on_missing [Symbol] what should do when there are missing parameters # - `:curry` -> it does a curry with the parameters received (default) # - `:call` -> it calls anyway (will error). # - `:safe` -> it sets to `nil` the missing required arguments and does a call. # - `:return` -> it returns `nil` but doesn't call. # @return [Lambda, NilClass, Result] def aux_curry(meth, on_missing = :curry) lambda do |*args, **kargs, &block| params = meth.parameters kparams = params.select { |type, _| (type == :keyreq) || (type == :key) } aparams = params.select { |type, _| (type == :req) || (type == :opt) } kreq_miss = kparams.select { |type, _| type == :keyreq }.map(&:last) - kargs.keys req_miss = aparams.select { |type, _| type == :req }.count - args.count req_miss = req_miss >= 0 ? req_miss : 0 ready = kreq_miss.empty? && req_miss.zero? if on_missing == :safe argrest = params.find { |type, _| type == :rest } keyrest = params.find { |type, _| type == :keyrest } kextras = kargs.keys - kparams.map(&:last) kextras.each { |name| kargs.delete(name) } unless keyrest args = args[0..(aparams.count-1)] unless argrest || args.count <= aparams.count unless ready kreq_miss.each { |name| kargs[name] = nil } ary_nil = Array.new(req_miss, nil) args = args.dup.push(*ary_nil) ready = true end end return meth.call(*args, **kargs, &block) if ready || on_missing == :call return nil if on_missing == :return # (default) on_missing == :curry lambda do |*oth, **koth, &blk| curried = aux_curry(meth, on_missing) curried[*args, *oth, **kargs, **koth, &(blk || block)] end end end end end end