class Metaractor::Errors

Public Class Methods

new() click to toggle source
# File lib/metaractor/errors.rb, line 66
def initialize
  @tree = Sycamore::Tree.new
end

Public Instance Methods

[](*path)
Alias for: dig
add(error: {}, errors: {}, object: nil) click to toggle source
# File lib/metaractor/errors.rb, line 72
def add(error: {}, errors: {}, object: nil)
  trees = []
  [error, errors].each do |h|
    tree = nil
    tree = if h.is_a? Metaractor::Errors
      Sycamore::Tree.from(h.instance_variable_get(:@tree))
    else
      Sycamore::Tree.from(normalize_error_hash(h))
    end

    unless tree.empty?
      if tree.nodes.any? { |node| tree.strict_leaf?(node) }
        raise ArgumentError, "Invalid hash!"
      end

      trees << tree
    end
  end

  trees.each do |tree|
    tree.each_path do |path|
      node = path.node
      unless node.is_a?(Error)
        node = Error.new(
          value: path.node,
          object: object
        )
      end

      @tree[path.parent] << node
    end
  end
  @tree.compact
end
dig(*path) click to toggle source
# File lib/metaractor/errors.rb, line 127
def dig(*path)
  result = @tree.dig(*path)

  if result.strict_leaves?
    unwrapped_enum(result.nodes)
  else
    unwrapped_tree(result).to_h
  end
end
Also aliased as: []
full_messages(tree = @tree) click to toggle source
# File lib/metaractor/errors.rb, line 107
def full_messages(tree = @tree)
  messages = []
  tree.each_path do |path|
    messages << message_from_path(path)
  end

  messages
end
Also aliased as: to_a
full_messages_for(*path) click to toggle source
# File lib/metaractor/errors.rb, line 117
def full_messages_for(*path)
  child_tree = @tree.fetch_path(path)

  if child_tree.strict_leaves?
    child_tree = @tree.fetch_path(path[0..-2])
  end

  full_messages(child_tree)
end
include?(*elements) click to toggle source
# File lib/metaractor/errors.rb, line 138
def include?(*elements)
  if elements.size == 1 &&
      elements.first.is_a?(Hash)
    unwrapped_tree.include?(*elements)
  elsif elements.all? { |e| e.is_a? String }
    full_messages.include?(*elements)
  else
    elements.all? do |element|
      @tree.include_path?(element)
    end
  end
end
inspect() click to toggle source
# File lib/metaractor/errors.rb, line 172
def inspect
  str = "<##{self.class.name}: "

  if !empty?
    str << "Errors:\n"
    str << Metaractor.format_hash(to_h(unwrap: false))
    str << "\n"
  end

  str << ">"
  str
end
slice(*paths) click to toggle source
# File lib/metaractor/errors.rb, line 151
def slice(*paths)
  new_tree = Sycamore::Tree.new

  paths.each do |path|
    if @tree.include_path?(path)
      new_tree[path] = @tree[path].dup
    end
  end

  unwrapped_tree(new_tree).to_h
end
to_a(tree = @tree)
Alias for: full_messages
to_h(unwrap: true) click to toggle source
# File lib/metaractor/errors.rb, line 163
def to_h(unwrap: true)
  if unwrap
    unwrapped_tree.to_h
  else
    @tree.to_h
  end
end
Also aliased as: to_hash
to_hash(unwrap: true)
Alias for: to_h

Private Instance Methods

deep_transform_values_in_object(object) { |object| ... } click to toggle source

Lifted from Rails

# File lib/metaractor/errors.rb, line 241
def deep_transform_values_in_object(object, &block)
  case object
  when Hash
    object.transform_values { |value| deep_transform_values_in_object(value, &block) }
  when Array
    object.map { |e| deep_transform_values_in_object(e, &block) }
  else
    yield(object)
  end
end
message_from_path(path) click to toggle source
# File lib/metaractor/errors.rb, line 187
def message_from_path(path)
  path_elements = []
  path.parent&.each_node do |node|
    unless node == :base
      path_elements << node.to_s
    end
  end

  path.node.generate_message(path_elements: path_elements)
end
normalize_error_hash(hash) click to toggle source
# File lib/metaractor/errors.rb, line 222
def normalize_error_hash(hash)
  deep_transform_values_in_object(hash, &method(:transform_delegator))
end
transform_delegator(value) click to toggle source
# File lib/metaractor/errors.rb, line 226
def transform_delegator(value)
  if value.is_a?(Delegator)
    if value.respond_to?(:to_hash)
      deep_transform_values_in_object(value.to_hash, &method(:transform_delegator))
    elsif value.respond_to?(:to_a)
      deep_transform_values_in_object(value.to_a, &method(:transform_delegator))
    else
      value
    end
  else
    value
  end
end
unwrapped_enum(orig) click to toggle source
# File lib/metaractor/errors.rb, line 212
def unwrapped_enum(orig)
  orig.map do |element|
    if element.is_a? Error
      element.value
    else
      element
    end
  end
end
unwrapped_tree(orig_tree = @tree) click to toggle source
# File lib/metaractor/errors.rb, line 198
def unwrapped_tree(orig_tree = @tree)
  tree = Sycamore::Tree.new
  orig_tree.each_path do |path|
    node = path.node
    if node.is_a? Error
      node = node.value
    end

    tree[path.parent] << node
  end

  tree
end