# frozen_string_literal: true module ActiveModel # == Active \Model \Error # # Represents one single error class Error CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict] MESSAGE_OPTIONS = [:message] def initialize(base, attribute, type = :invalid, **options) @base = base @attribute = attribute @raw_type = type @type = type || :invalid @options = options end def initialize_dup(other) @attribute = @attribute.dup @raw_type = @raw_type.dup @type = @type.dup @options = @options.deep_dup end attr_reader :base, :attribute, :type, :raw_type, :options def message case raw_type when Symbol base.errors.generate_message(attribute, raw_type, options.except(*CALLBACKS_OPTIONS)) else raw_type end end def detail { error: raw_type }.merge(options.except(*CALLBACKS_OPTIONS + MESSAGE_OPTIONS)) end def full_message base.errors.full_message(attribute, message) end # See if error matches provided +attribute+, +type+ and +options+. def match?(attribute, type = nil, **options) if @attribute != attribute || (type && @type != type) return false end options.each do |key, value| if @options[key] != value return false end end true end def strict_match?(attribute, type, **options) return false unless match?(attribute, type) options == @options.except(*CALLBACKS_OPTIONS + MESSAGE_OPTIONS) end def ==(other) other.is_a?(self.class) && attributes_for_hash == other.attributes_for_hash end alias eql? == def hash attributes_for_hash.hash end protected def attributes_for_hash [@base, @attribute, @raw_type, @options.except(*CALLBACKS_OPTIONS)] end end end