module DataModel # Provide Error building functionality as a mixin module Errors extend self ## Constructors # Type error applies when a value is not of the expected type # @param cls [String, Array(String)] the expected class # @param value [Object] the value that failed # @return [Array(Symbol, untyped)] the error def type_error(cls, value) [:type, [cls, value]] end # Coerce error applies when a value cannot be coerced to the expected type # @param cls [String] the expected class # @param value [Object] the value that failed # @return [Array(Symbol, untyped)] the error def coerce_error(cls, value) [:coerce, [cls, value]] end # Missing error applies when a value is missing # @param cls [String, Array] the expected class # @return [Array(Symbol, untyped)] the error def missing_error(cls) [:missing, cls] end # Inclusion error applies when a value is not in a set of allowed values # @param set [Array] the set of allowed values # @return [Array(Symbol, untyped)] the error def inclusion_error(set) [:inclusion, set] end # Exclusive error applies when a value is in a set of disallowed values # @param set [Array] the set of disallowed values # @return [Array(Symbol, untyped)] the error def exclusion_error(set) [:exclusion, set] end # Blank error applies when a value is blank # @return [Array(Symbol, untyped)] the error def blank_error [:blank, nil] end # Extra keys error applies when a hash has extra keys # @param keys [Array] the extra keys # @return [Array(Symbol, untyped)] the error def extra_keys_error(keys) [:extra_keys, keys] end # Min applies when value is less then the minimum # @param min [Numeric] the minimum value # @param val [Numeric] the value that failed # @return [Array(Symbol, untyped)] the error def min_error(min, val) [:min, [min, val]] end # Max applies when value is less then the minimum # @param min [Numeric] the minimum value # @param val [Numeric] the value that failed # @return [Array(Symbol, untyped)] the error def max_error(min, val) [:max, [min, val]] end # Earliest applies when value is earlier then earliest # @param earliest [Date, Time] the earliest value # @param val [Date, Time] the value that failed # @return [Array(Symbol, untyped)] the error def earliest_error(earliest, val) [:earliest, [earliest, val]] end # Latest applies when value is earlier then earliest # @param latest [Date, Time] the latest value # @param val [Date, Time] the value that failed # @return [Array(Symbol, untyped)] the error def latest_error(latest, val) [:latest, [latest, val]] end # Format applies when value does not match a format # @param format [Object] the format # @param val [String] the value that failed # @return [Array(Symbol, untyped)] the error def format_error(format, val) [:format, [format, val]] end ## Messages # Generate a message for a type error # @param cls [String] the expected class # @param value [Object] the value that failed # @return [String] the message def type_error_message(cls, value) names = Array(cls).join(" or ") "#{value.inspect} is not a #{names}, it is a #{value.class.name}" end # Generate a message for a coerce error # @param cls [String] the expected class # @param value [Object] the value that failed # @return [String] the message def coerce_error_message(cls, value) names = Array(cls).join(" or ") "cannot be coerced to #{names}, it is a #{value.class.name}" end # Generate a message for a missing error # @param cls [String, Array] the expected class # @return [String] the message def missing_error_message(cls) names = Array(cls).join(" or ") "missing value, expected a #{names}" end # Generate a message for an inclusion error # @param set [Array] the set of allowed values # @return [String] the message def inclusion_error_message(set) "must be one of #{set.join(', ')}" end # Generate a message for an exclusion error # @param set [Array] the set of disallowed values # @return [String] the message def exclusion_error_message(set) "must not be one of #{set.join(', ')}" end # Generate a message for a blank error # @return [String] the message def blank_error_message "cannot be blank" end # Generate a message for an extra keys error # @param keys [Array] the extra keys # @return [String] the message def extra_keys_error_message(keys) "more elements found in closed hash then specified children: #{keys.join(', ')}" end # Generate a message for a min error # @param min [Numeric] the minimum value # @param val [Numeric] the value that failed # @return [String] the message def min_error_message(min, val) "value is less than the minimum of #{min}, it is #{val}" end # Generate a message for a min error # @param max [Numeric] the maximum value # @param val [Numeric] the value that failed # @return [String] the message def max_error_message(max, val) "value is more than the maximum of #{max}, it is #{val}" end # Generate a message for a value that occurs earlier then the specified earliest point # @param earliest [Date, Time] the earliest value # @param val [Date, Time] the value that failed # @return [String] the message def early_error_message(earliest, val) "value #{val} is before #{earliest}" end # Generate a message for a value that occurs later then the specified latest point # @param latest [Date, Time] the latest value # @param val [Date, Time] the value that failed # @return [String] the message def late_error_message(latest, val) "value #{val} is after #{latest}" end # Generate a message for a value that does not match the format # @param format [Object] the format # @param val [String] the value that failed # @return [String] the message def format_error_message(format, val) "value #{val} does not match format #{format}" end # Builders # Get the error message builders # @return [Hash{Symbol => Proc}] the error message builders def error_messages return { type: lambda do |ctx| cls, val = ctx type_error_message(cls, val) end, coerce: lambda do |ctx| cls, val = ctx type_error_message(cls, val) end, missing: lambda do |ctx| cls = ctx missing_error_message(cls) end, inclusion: lambda do |ctx| set = ctx inclusion_error_message(set) end, exclusion: lambda do |ctx| set = ctx exclusion_error_message(set) end, extra_keys: lambda do |ctx| set = ctx extra_keys_error_message(set) end, min: lambda do |ctx| min, val = ctx min_error_message(min, val) end, max: lambda do |ctx| max, val = ctx max_error_message(max, val) end, earliest: lambda do |ctx| earliest, val = ctx early_error_message(earliest, val) end, latest: lambda do |ctx| latest, val = ctx late_error_message(latest, val) end, blank: lambda do blank_error_message end, format: lambda do |ctx| format, val = ctx format_error_message(format, val) end } end end end