lib/data_model/errors.rb in data_model-0.4.0 vs lib/data_model/errors.rb in data_model-0.5.0

- old
+ new

@@ -1,234 +1,258 @@ -# typed: strict - module DataModel # Provide Error building functionality as a mixin module Errors - include Kernel - extend T::Sig extend self - TTemporal = T.type_alias { T.any(::Date, ::Time, ::DateTime) } - ## Constructors # Type error applies when a value is not of the expected type - sig { params(cls: T.class_of(Object), value: Object).returns(TError) } + # @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 - sig { params(cls: T.class_of(Object), value: Object).returns(TError) } + # @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 - sig { params(cls: T.class_of(Object)).returns(TError) } + # @param cls [String, Array<String>] 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 - sig { params(set: T::Array[T.any(Symbol, String)]).returns(TError) } + # @param set [Array<Symbol, String>] 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 - sig { params(set: T::Array[T.any(Symbol, String)]).returns(TError) } + # @param set [Array<Symbol, String>] 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 - sig { returns(TError) } + # @return [Array(Symbol, untyped)] the error def blank_error [:blank, nil] end # Extra keys error applies when a hash has extra keys - sig { params(keys: T::Array[Symbol]).returns(TError) } + # @param keys [Array<Symbol>] 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 - sig { params(min: Numeric, val: Numeric).returns(TError) } + # @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 - sig { params(min: Numeric, val: Numeric).returns(TError) } + # @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 - sig { params(earliest: TTemporal, val: TTemporal).returns(TError) } + # @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 - sig { params(latest: TTemporal, val: TTemporal).returns(TError) } + # @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 - sig { params(format: Object, val: String).returns(TError) } + # @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 - sig { params(cls: T.class_of(Object), value: Object).returns(String) } + # @param cls [String] the expected class + # @param value [Object] the value that failed + # @return [String] the message def type_error_message(cls, value) - "#{value.inspect} is not a #{cls.name}, it is a #{value.class.name}" + 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 - sig { params(cls: T.class_of(Object), value: Object).returns(String) } + # @param cls [String] the expected class + # @param value [Object] the value that failed + # @return [String] the message def coerce_error_message(cls, value) - "cannot be coerced to #{cls.name}, it is a #{value.class.name}" + names = Array(cls).join(" or ") + "cannot be coerced to #{names}, it is a #{value.class.name}" end # Generate a message for a missing error - sig { params(cls: T.class_of(Object)).returns(String) } + # @param cls [String, Array<String>] the expected class + # @return [String] the message def missing_error_message(cls) - "missing value, expected a #{cls.name}" + names = Array(cls).join(" or ") + "missing value, expected a #{names}" end # Generate a message for an inclusion error - sig { params(set: T::Array[Symbol]).returns(String) } + # @param set [Array<Symbol, String>] 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 - sig { params(set: T::Array[Symbol]).returns(String) } + # @param set [Array<Symbol, String>] 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 - sig { returns(String) } + # @return [String] the message def blank_error_message "cannot be blank" end # Generate a message for an extra keys error - sig { params(keys: T::Array[Symbol]).returns(String) } + # @param keys [Array<Symbol>] 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 - sig { params(min: Numeric, val: Numeric).returns(String) } + # @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 - sig { params(max: Numeric, val: Numeric).returns(String) } + # @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 - sig { params(earliest: TTemporal, val: TTemporal).returns(String) } + # @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 - sig { params(latest: TTemporal, val: TTemporal).returns(String) } + # @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 - sig { params(format: Object, val: String).returns(String) } + # @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 - TErrorMessageBuilder = T.type_alias { T.proc.params(ctx: T.untyped).returns(String) } - TErrorMessages = T.type_alias { T::Hash[Symbol, TErrorMessageBuilder] } - TClassValueCtx = T.type_alias { [T.class_of(Object), Object] } - TClassCtx = T.type_alias { T.class_of(Object) } - TSetCtx = T.type_alias { T::Array[Symbol] } - TWithinCtx = T.type_alias { [Numeric, Numeric] } - TWithinTemporalCtx = T.type_alias { [Errors::TTemporal, Errors::TTemporal] } - TFormatCtx = T.type_alias { [Object, String] } - # Get the error message builders - sig { returns(TErrorMessages) } - def self.error_messages + # @return [Hash{Symbol => Proc}] the error message builders + def error_messages return { type: lambda do |ctx| - cls, val = T.let(ctx, TClassValueCtx) + cls, val = ctx type_error_message(cls, val) end, coerce: lambda do |ctx| - cls, val = T.let(ctx, TClassValueCtx) + cls, val = ctx type_error_message(cls, val) end, missing: lambda do |ctx| - cls = T.let(ctx, TClassCtx) + cls = ctx missing_error_message(cls) end, inclusion: lambda do |ctx| - set = T.let(ctx, TSetCtx) + set = ctx inclusion_error_message(set) end, exclusion: lambda do |ctx| - set = T.let(ctx, TSetCtx) + set = ctx exclusion_error_message(set) end, extra_keys: lambda do |ctx| - set = T.let(ctx, TSetCtx) + set = ctx extra_keys_error_message(set) end, min: lambda do |ctx| - min, val = T.let(ctx, TWithinCtx) + min, val = ctx min_error_message(min, val) end, max: lambda do |ctx| - max, val = T.let(ctx, TWithinCtx) + max, val = ctx max_error_message(max, val) end, earliest: lambda do |ctx| - earliest, val = T.let(ctx, TWithinTemporalCtx) + earliest, val = ctx early_error_message(earliest, val) end, latest: lambda do |ctx| - latest, val = T.let(ctx, TWithinTemporalCtx) + latest, val = ctx late_error_message(latest, val) end, blank: lambda do blank_error_message end, format: lambda do |ctx| - format, val = T.let(ctx, TFormatCtx) + format, val = ctx format_error_message(format, val) end } end end