module Metaractor::Parameters

Attributes

requirement_trees[W]

Public Class Methods

included(base) click to toggle source
# File lib/metaractor/parameters.rb, line 5
def self.included(base)
  base.extend ClassMethods
  base.class_eval do
    include Metaractor::HandleErrors

    class << self
      attr_writer :requirement_trees
    end

    before :remove_blank_values
    before :apply_defaults
    before :validate_required_parameters
    before :apply_types
  end
end

Public Instance Methods

_parameter_default(name) click to toggle source
# File lib/metaractor/parameters.rb, line 158
def _parameter_default(name)
  default = self.parameters[name][:default]

  case
  when default.respond_to?(:call) then instance_exec(&default)
  when default.respond_to?(:dup) then default.dup
  else default
  end
end
add_parameter_error(param: nil, message:) click to toggle source
# File lib/metaractor/parameters.rb, line 259
def add_parameter_error(param: nil, message:)
  add_error(
    message: "#{param} #{message}".lstrip
  )

  context.invalidate!
end
apply_defaults() click to toggle source
# File lib/metaractor/parameters.rb, line 148
def apply_defaults
  parameters.each do |name, parameter|
    next unless parameter.has_key?(:default)

    unless context.has_key?(name)
      context[name] = _parameter_default(name)
    end
  end
end
apply_types() click to toggle source
# File lib/metaractor/parameters.rb, line 168
def apply_types
  parameters.each do |name, parameter|
    next unless parameter[:type]

    if context.has_key?(name) && context[name] != nil
      callable = parameter[:type]

      if callable.is_a?(Symbol)
        callable = Metaractor.types[callable]
        raise ArgumentError, "No such type: #{parameter[:type]}" if callable.nil?
      end

      context[name] = callable.call(context[name])
    end
  end
end
parameter_valid?(param) click to toggle source
# File lib/metaractor/parameters.rb, line 217
def parameter_valid?(param)
  # implements a depth-first post-order traversal
  if param.respond_to?(:to_h)
    param = param.to_h
    raise "invalid required parameter #{param.inspect}" unless param.keys.size == 1
    raise "invalid required parameter #{param.inspect}" unless param.values.first.respond_to?(:to_a)

    operator = param.keys.first
    params = param.values.first.to_a

    valids = []
    messages = []
    params.each do |key|
      valid, message = parameter_valid?(key)
      valids << valid
      messages << message
    end

    case operator
    when :or
      return valids.any?, "(#{messages.join(' or ')})"
    when :xor
      return valids.one?, "(#{messages.join(' xor ')})"
    when :and
      return valids.all?, "(#{messages.join(' and ')})"
    else
      raise "invalid required parameter #{param.inspect}"
    end
  else
    return context[param] != nil, param.to_s
  end
end
parameters() click to toggle source
# File lib/metaractor/parameters.rb, line 122
def parameters
  self.class.parameter_hash
end
remove_blank_values() click to toggle source
# File lib/metaractor/parameters.rb, line 134
def remove_blank_values
  to_delete = []
  context.each_pair do |name, value|
    next if parameters.dig(name, :allow_blank)

    # The following regex is borrowed from Rails' String#blank?
    to_delete << name if (value.is_a?(String) && /\A[[:space:]]*\z/ === value) || value.nil?
  end

  to_delete.each do |name|
    context.delete_field name
  end
end
require_parameter(param, message: nil) click to toggle source
# File lib/metaractor/parameters.rb, line 204
def require_parameter(param, message: nil)
  message_override = message
  valid, message = parameter_valid? param

  if !valid
    if message_override != nil
      add_parameter_error(param: param, message: message_override)
    else
      add_parameter_error(message: "Required parameters: #{message}")
    end
  end
end
require_parameter!(param, message: nil) click to toggle source
# File lib/metaractor/parameters.rb, line 250
def require_parameter!(param, message: nil)
  require_parameter param, message: message
  context.fail! unless context.errors.empty?
end
requirement_trees() click to toggle source
# File lib/metaractor/parameters.rb, line 126
def requirement_trees
  self.class.requirement_trees
end
requirement_trees=(trees) click to toggle source
# File lib/metaractor/parameters.rb, line 130
def requirement_trees=(trees)
  self.class.requirement_trees=(trees)
end
run_validate_hooks() click to toggle source
# File lib/metaractor/parameters.rb, line 255
def run_validate_hooks
  run_hooks(self.class.validate_hooks)
end
validate_required_parameters() click to toggle source
# File lib/metaractor/parameters.rb, line 185
def validate_required_parameters
  context.errors ||= []

  parameters.each do |name, parameter|
    next if !parameter[:required] ||
      parameter[:required].is_a?(Hash)

    require_parameter name
  end

  requirement_trees.each do |tree|
    require_parameter tree
  end

  run_validate_hooks

  context.fail! unless context.errors.empty?
end