class Arity::Function

Attributes

callable[R]

Public Class Methods

make(fn, silent: false) click to toggle source
# File lib/arity/function.rb, line 8
def self.make(fn, silent: false)
  return new(fn) if fn.respond_to?(:call)
  return if silent
  raise NotCallableError, "function is not callable: #{fn.inspect}"
end
new(fn) click to toggle source
# File lib/arity/function.rb, line 14
def initialize(fn)
  @callable = unwrap_function(fn)
end

Public Instance Methods

arity() click to toggle source
# File lib/arity/function.rb, line 18
def arity
  callable.arity
end
run(*args, **opts) click to toggle source
# File lib/arity/function.rb, line 50
def run(*args, **opts)
  args.push(opts) unless opts.empty?
  callable.call(*args)
end
runnable?(*args, **opts) click to toggle source
# File lib/arity/function.rb, line 46
def runnable?(*args, **opts)
  takes?(arg_count: args.size, keywords: opts.keys)
end
signature() click to toggle source
# File lib/arity/function.rb, line 22
def signature
  @signature ||= compute_signature
end
takes?(arg_count:, keywords:) click to toggle source
# File lib/arity/function.rb, line 26
def takes?(arg_count:, keywords:)
  bad_param('arg_count', 'an int', arg_count) if !arg_count.is_a?(Integer)
  bad_param('keywords', 'an array', keywords) if !keywords.is_a?(Array)

  return false if arg_count < signature[:min_args]

  if signature[:max_args] > -1
    return false if arg_count > signature[:max_args]
  end

  missing = signature[:required_keys] - keywords
  return false if !missing.empty?

  return true if signature[:any_key]

  extra_keys = keywords - signature[:required_keys] \
                        - signature[:optional_keys]
  extra_keys.empty?
end

Private Instance Methods

bad_param(name, type, value) click to toggle source
# File lib/arity/function.rb, line 68
def bad_param(name, type, value)
  raise ArgumentError, "#{name} must be #{type}, got: #{value.inspect}"
end
compute_signature() click to toggle source
# File lib/arity/function.rb, line 72
def compute_signature
  splat = false
  { min_args: 0,
    max_args: 0,
    required_keys: [],
    optional_keys: [],
    any_key: false
  }.tap do |signature|
    callable.parameters.each do |type,name|
      case type
      when :req
        signature[:min_args] += 1
        signature[:max_args] += 1
      when :opt
        signature[:max_args] += 1
      when :rest
        splat = true
      when :key
        signature[:optional_keys] << name
      when :keyreq
        signature[:required_keys] << name
      when :keyrest
        signature[:any_key] = true
      else
        unknown_parameter_type!(type, name)
      end
    end
    signature[:max_args] = -1 if splat
    signature[:required_keys].freeze
    signature[:optional_keys].freeze
  end.freeze
end
unknown_parameter_type!(type, name) click to toggle source
# File lib/arity/function.rb, line 61
def unknown_parameter_type!(type, name)
  msg  = "do not known how to parse the function signature"
  msg += " for type #{type.inspect} with parameter #{name.inspect}"
  msg += "; please file an issue at https://www.github.com/fledman/arity"
  raise UnknownParameterTypeError, msg
end
unwrap_function(fn) click to toggle source
# File lib/arity/function.rb, line 57
def unwrap_function(fn)
  fn.respond_to?(:arity) ? fn : fn.method(:call)
end