From ef68d3e35cb58f9f491993eeec6e7de99442dd06 Mon Sep 17 00:00:00 2001 From: lulalala Date: Thu, 15 Mar 2018 16:13:18 +0800 Subject: Add ActiveModel::Error and NestedError Add initialize_dup to deep dup. Move proc eval and flexible message position out to Errors, because proc eval is needed for Errors#added? and Errors#delete --- activemodel/lib/active_model/error.rb | 60 ++++++++++++++++++++++++++++ activemodel/lib/active_model/errors.rb | 16 -------- activemodel/lib/active_model/nested_error.rb | 33 +++++++++++++++ 3 files changed, 93 insertions(+), 16 deletions(-) create mode 100644 activemodel/lib/active_model/error.rb create mode 100644 activemodel/lib/active_model/nested_error.rb (limited to 'activemodel/lib') diff --git a/activemodel/lib/active_model/error.rb b/activemodel/lib/active_model/error.rb new file mode 100644 index 0000000000..214a0b356d --- /dev/null +++ b/activemodel/lib/active_model/error.rb @@ -0,0 +1,60 @@ +# 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, **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 + end +end diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 3a692a3e64..7eff374ce3 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -59,9 +59,6 @@ module ActiveModel class Errors include Enumerable - CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict] - MESSAGE_OPTIONS = [:message] - class << self attr_accessor :i18n_customize_full_message # :nodoc: end @@ -532,19 +529,6 @@ module ActiveModel end private - def normalize_message(attribute, message, options) - case message - when Symbol - generate_message(attribute, message, options.except(*CALLBACKS_OPTIONS)) - else - message - end - end - - def normalize_detail(message, options) - { error: message }.merge(options.except(*CALLBACKS_OPTIONS + MESSAGE_OPTIONS)) - end - def without_default_proc(hash) hash.dup.tap do |new_h| new_h.default_proc = nil diff --git a/activemodel/lib/active_model/nested_error.rb b/activemodel/lib/active_model/nested_error.rb new file mode 100644 index 0000000000..b01447ac75 --- /dev/null +++ b/activemodel/lib/active_model/nested_error.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require "active_model/error" +require "forwardable" + +module ActiveModel + # Represents one single error + # @!attribute [r] base + # @return [ActiveModel::Base] the object which the error belongs to + # @!attribute [r] attribute + # @return [Symbol] attribute of the object which the error belongs to + # @!attribute [r] type + # @return [Symbol] error's type + # @!attribute [r] options + # @return [Hash] additional options + # @!attribute [r] inner_error + # @return [Error] inner error + class NestedError < Error + def initialize(base, inner_error, override_options = {}) + @base = base + @inner_error = inner_error + @attribute = override_options.fetch(:attribute) { inner_error.attribute } + @type = override_options.fetch(:type) { inner_error.type } + @raw_type = inner_error.raw_type + @options = inner_error.options + end + + attr_reader :inner_error + + extend Forwardable + def_delegators :@inner_error, :full_message, :message + end +end -- cgit v1.2.3