lib/datacaster/predefined.rb in datacaster-2.0.2 vs lib/datacaster/predefined.rb in datacaster-3.0.0

- old
+ new

@@ -2,77 +2,98 @@ module Predefined extend self # Base types - def cast(name = 'Anonymous', &block) - Caster.new(name, &block) + def cast(&block) + Caster.new(&block) end - def check(name = 'Anonymous', error = 'is invalid', &block) - Checker.new(name, error, &block) + def check(error_key = nil, &block) + Checker.new(error_key, &block) end - def compare(value, name = 'Anonymous', error = nil) - Comparator.new(value, name, error) + def compare(value, error_key = nil) + Comparator.new(value, error_key) end - def transform(name = 'Anonymous', &block) - Transformer.new(name, &block) + def transform(&block) + Transformer.new(&block) end - def transform_if_present(name = 'Anonymous', &block) + def transform_if_present(&block) raise 'Expected block' unless block_given? - Transformer.new(name) { |v| v == Datacaster.absent ? v : block.(v) } + Transformer.new { |v| v == Datacaster.absent ? v : block.(v) } end - def try(name = 'Anonymous', error = 'is invalid', catched_exception:, &block) - Trier.new(name, error, catched_exception, &block) + def try(error_key = nil, catched_exception:, &block) + Trier.new(catched_exception, error_key, &block) end - def array_schema(element_caster) - ArraySchema.new(element_caster) + def array_schema(element_caster, error_keys = {}) + ArraySchema.new(DefinitionDSL.expand(element_caster), error_keys) end alias_method :array_of, :array_schema - def hash_schema(fields) - HashSchema.new(fields) + def hash_schema(fields, error_key = nil) + unless fields.is_a?(Hash) + raise "Expected field definitions in a form of Hash for hash_schema, got #{fields.inspect} instead" + end + HashSchema.new( + fields.transform_values { |f| DefinitionDSL.expand(f) }, + error_key + ) end def transform_to_hash(fields) - HashMapper.new(fields) + HashMapper.new(fields.transform_values { |x| DefinitionDSL.expand(x) }) end - def validate(active_model_validations, name = 'Anonymous') - Validator.new(active_model_validations, name) + def validate(active_model_validations) + Validator.new(active_model_validations) end # 'Meta' types - def absent - check('Absent', 'must be absent') { |x| x == Datacaster.absent } + def absent(error_key = nil) + error_keys = ['.absent', 'datacaster.errors.absent'] + error_keys.unshift(error_key) if error_key + check { |x| x == Datacaster.absent }.i18n_key(*error_keys) end - def any - check('Any', 'must be set') { |x| x != Datacaster.absent } + def any(error_key = nil) + error_keys = ['.any', 'datacaster.errors.any'] + error_keys.unshift(error_key) if error_key + check { |x| x != Datacaster.absent }.i18n_key(*error_keys) end + def default(value, on: nil) + transform do |x| + if x == Datacaster.absent || + (on && x.respond_to?(on) && x.public_send(on)) + value + else + x + end + end + end + def transform_to_value(value) - transform('ToValue') { value } + transform { value } end def remove - transform('Remove') { Datacaster.absent } + transform { Datacaster.absent } end def pass - transform('Pass', &:itself) + transform(&:itself) end def pick(*keys) - must_be(Enumerable) & transform("Picker") { |value| + must_be(Enumerable) & transform { |value| result = keys.map do |key| if value.respond_to?(:key?) && !value.key?(key) Datacaster.absent elsif value.respond_to?(:length) && key.is_a?(Integer) && key > 0 && key >= value.length @@ -88,97 +109,131 @@ def merge_message_keys(*keys) MessageKeysMerger.new(keys) end - def responds_to(method) - check('RespondsTo', "must respond to #{method.inspect}") { |x| x.respond_to?(method) } + def responds_to(method, error_key = nil) + error_keys = ['.responds_to', 'datacaster.errors.responds_to'] + error_keys.unshift(error_key) if error_key + check { |x| x.respond_to?(method) }.i18n_key(*error_keys, reference: method.to_s) end - def must_be(klass) - check('MustBe', "must be #{klass.inspect}") { |x| x.is_a?(klass) } + def must_be(klass, error_key = nil) + error_keys = ['.must_be', 'datacaster.errors.must_be'] + error_keys.unshift(error_key) if error_key + check { |x| x.is_a?(klass) }.i18n_key(*error_keys, reference: klass.name) end def optional(base) absent | base end # Strict types - def decimal(digits = 8) - Trier.new('Decimal', 'must be decimal', [ArgumentError, TypeError]) do |x| + def decimal(digits = 8, error_key = nil) + error_keys = ['.decimal', 'datacaster.errors.decimal'] + error_keys.unshift(error_key) if error_key + + Trier.new([ArgumentError, TypeError]) do |x| # strictly validate format of string, BigDecimal() doesn't do that Float(x) BigDecimal(x, digits) - end + end.i18n_key(*error_keys) end - def array - check('Array', 'must be array') { |x| x.is_a?(Array) } + def array(error_key = nil) + error_keys = ['.array', 'datacaster.errors.array'] + error_keys.unshift(error_key) if error_key + check { |x| x.is_a?(Array) }.i18n_key(*error_keys) end - def float - check('Float', 'must be float') { |x| x.is_a?(Float) } + def float(error_key = nil) + error_keys = ['.float', 'datacaster.errors.float'] + error_keys.unshift(error_key) if error_key + check { |x| x.is_a?(Float) }.i18n_key(*error_keys) end - # 'hash' is a bad method name, because it will overwrite built in Object#hash - def hash_value - check('Hash', 'must be hash') { |x| x.is_a?(Hash) } + # 'hash' would be a bad method name, because it would override built in Object#hash + def hash_value(error_key = nil) + error_keys = ['.hash_value', 'datacaster.errors.hash_value'] + error_keys.unshift(error_key) if error_key + check(error_key) { |x| x.is_a?(Hash) } end - def hash_with_symbolized_keys - hash_value & transform("SymbolizeKeys") { |x| x.symbolize_keys } + def hash_with_symbolized_keys(error_key = nil) + hash_value(error_key) & transform { |x| x.symbolize_keys } end - def integer - check('Integer', 'must be integer') { |x| x.is_a?(Integer) } + def integer(error_key = nil) + error_keys = ['.integer', 'datacaster.errors.integer'] + error_keys.unshift(error_key) if error_key + check { |x| x.is_a?(Integer) }.i18n_key(*error_keys) end - def integer32 - integer & check('FourBytes', 'out of range') { |x| x.abs <= 2_147_483_647 } + def integer32(error_key = nil) + error_keys = ['.integer32', 'datacaster.errors.integer32'] + error_keys.unshift(error_key) if error_key + integer(error_key) & check { |x| x.abs <= 2_147_483_647 }.i18n_key(*error_keys) end - def string - check('String', 'must be string') { |x| x.is_a?(String) } + def string(error_key = nil) + error_keys = ['.string', 'datacaster.errors.string'] + error_keys.unshift(error_key) if error_key + check { |x| x.is_a?(String) }.i18n_key(*error_keys) end - def non_empty_string - string & check('NonEmptyString', 'must be present') { |x| !x.empty? } + def non_empty_string(error_key = nil) + error_keys = ['.non_empty_string', 'datacaster.errors.non_empty_string'] + error_keys.unshift(error_key) if error_key + string(error_key) & check { |x| !x.empty? }.i18n_key(*error_keys) end # Form request types - def iso8601 - string & - try('ISO8601', 'must be iso8601 string', catched_exception: [ArgumentError, TypeError]) { |x| DateTime.iso8601(x) } + def iso8601(error_key = nil) + error_keys = ['.iso8601', 'datacaster.errors.iso8601'] + error_keys.unshift(error_key) if error_key + + string(error_key) & + try(catched_exception: [ArgumentError, TypeError]) { |x| DateTime.iso8601(x) }. + i18n_key(*error_keys) end - def to_boolean - cast('ToBoolean') do |x| + def to_boolean(error_key = nil) + error_keys = ['.to_boolean', 'datacaster.errors.to_boolean'] + error_keys.unshift(error_key) if error_key + + cast do |x| if ['true', '1', true].include?(x) Datacaster.ValidResult(true) elsif ['false', '0', false].include?(x) Datacaster.ValidResult(false) else - Datacaster.ErrorResult(['must be boolean']) + Datacaster.ErrorResult(Datacaster::I18nValues::Key.new(error_keys, value: x)) end end end - def to_float - Trier.new('ToFloat', 'must be float', [ArgumentError, TypeError]) do |x| + def to_float(error_key = nil) + error_keys = ['.to_float', 'datacaster.errors.to_float'] + error_keys.unshift(error_key) if error_key + + Trier.new([ArgumentError, TypeError]) do |x| Float(x) - end + end.i18n_key(*error_keys) end - def to_integer - Trier.new('ToInteger', 'must be integer', [ArgumentError, TypeError]) do |x| + def to_integer(error_key = nil) + error_keys = ['.to_integer', 'datacaster.errors.to_integer'] + error_keys.unshift(error_key) if error_key + + Trier.new([ArgumentError, TypeError]) do |x| Integer(x) - end + end.i18n_key(*error_keys) end def optional_param(base) - transform_if_present("optional_param(#{base.inspect})") { |x| x == '' ? Datacaster::Absent.instance : x } & (absent | base) + transform_if_present { |x| x == '' ? Datacaster::Absent.instance : x } & (absent | base) end end end