datacaster 2.0.2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +518 -268
- data/config/locales/en.yml +24 -0
- data/datacaster.gemspec +2 -0
- data/lib/datacaster/absent.rb +4 -0
- data/lib/datacaster/and_node.rb +3 -5
- data/lib/datacaster/and_with_error_aggregation_node.rb +5 -6
- data/lib/datacaster/array_schema.rb +18 -16
- data/lib/datacaster/base.rb +33 -44
- data/lib/datacaster/caster.rb +4 -8
- data/lib/datacaster/checker.rb +8 -10
- data/lib/datacaster/comparator.rb +9 -9
- data/lib/datacaster/config.rb +28 -0
- data/lib/datacaster/context_node.rb +43 -0
- data/lib/datacaster/context_nodes/errors_caster.rb +21 -0
- data/lib/datacaster/context_nodes/i18n.rb +20 -0
- data/lib/datacaster/context_nodes/i18n_keys_mapper.rb +27 -0
- data/lib/datacaster/context_nodes/structure_cleaner.rb +103 -0
- data/lib/datacaster/context_nodes/user_context.rb +20 -0
- data/lib/datacaster/definition_dsl.rb +37 -0
- data/lib/datacaster/hash_mapper.rb +13 -16
- data/lib/datacaster/hash_schema.rb +14 -15
- data/lib/datacaster/i18n_values/base.rb +87 -0
- data/lib/datacaster/i18n_values/key.rb +34 -0
- data/lib/datacaster/i18n_values/scope.rb +28 -0
- data/lib/datacaster/message_keys_merger.rb +8 -15
- data/lib/datacaster/or_node.rb +3 -4
- data/lib/datacaster/predefined.rb +119 -64
- data/lib/datacaster/result.rb +35 -14
- data/lib/datacaster/runtimes/base.rb +47 -0
- data/lib/datacaster/runtimes/i18n.rb +20 -0
- data/lib/datacaster/runtimes/structure_cleaner.rb +47 -0
- data/lib/datacaster/runtimes/user_context.rb +39 -0
- data/lib/datacaster/substitute_i18n.rb +48 -0
- data/lib/datacaster/then_node.rb +7 -8
- data/lib/datacaster/transformer.rb +4 -8
- data/lib/datacaster/trier.rb +9 -11
- data/lib/datacaster/validator.rb +8 -9
- data/lib/datacaster/version.rb +1 -1
- data/lib/datacaster.rb +15 -35
- metadata +57 -9
- data/lib/datacaster/definition_context.rb +0 -20
- data/lib/datacaster/terminator.rb +0 -98
@@ -13,21 +13,18 @@ module Datacaster
|
|
13
13
|
@fields = fields
|
14
14
|
end
|
15
15
|
|
16
|
-
def cast(object)
|
17
|
-
object = super(object)
|
18
|
-
# return Datacaster.ErrorResult(["must be hash"]) unless object.value.is_a?(Hash)
|
19
|
-
|
20
|
-
checked_schema = object.meta[:checked_schema].dup || {}
|
21
|
-
|
16
|
+
def cast(object, runtime:)
|
22
17
|
errors = {}
|
23
18
|
result = {}
|
24
19
|
|
20
|
+
runtime.will_check!
|
21
|
+
|
25
22
|
@fields.each do |key, validator|
|
26
|
-
new_value = validator.(object)
|
23
|
+
new_value = runtime.ignore_checks! { validator.with_runtime(runtime).(object) }
|
27
24
|
|
28
25
|
# transform_to_hash([:a, :b, :c] => pick(:a, :b, :c) & ...)
|
29
26
|
if key.is_a?(Array)
|
30
|
-
unwrapped = new_value.valid? ? new_value.value : new_value.
|
27
|
+
unwrapped = new_value.valid? ? new_value.value : new_value.raw_errors
|
31
28
|
|
32
29
|
if key.length != unwrapped.length
|
33
30
|
raise TypeError.new("When using transform_to_hash([:a, :b, :c] => validator), validator should return Array "\
|
@@ -40,17 +37,17 @@ module Datacaster
|
|
40
37
|
if key.is_a?(Array)
|
41
38
|
key.zip(new_value.value) do |new_key, new_key_value|
|
42
39
|
result[new_key] = new_key_value
|
43
|
-
|
40
|
+
runtime.checked_key!(new_key)
|
44
41
|
end
|
45
42
|
else
|
46
43
|
result[key] = new_value.value
|
47
|
-
|
44
|
+
runtime.checked_key!(key)
|
48
45
|
end
|
49
46
|
else
|
50
47
|
if key.is_a?(Array)
|
51
|
-
errors = self.class.merge_errors(errors, key.zip(new_value.
|
48
|
+
errors = self.class.merge_errors(errors, key.zip(new_value.raw_errors).to_h)
|
52
49
|
else
|
53
|
-
errors = self.class.merge_errors(errors, {key => new_value.
|
50
|
+
errors = self.class.merge_errors(errors, {key => new_value.raw_errors})
|
54
51
|
end
|
55
52
|
end
|
56
53
|
end
|
@@ -58,17 +55,17 @@ module Datacaster
|
|
58
55
|
errors.delete_if { |_, v| v.empty? }
|
59
56
|
|
60
57
|
if errors.empty?
|
61
|
-
# All unchecked key-value pairs of initial hash are passed through, and eliminated by
|
58
|
+
# All unchecked key-value pairs of initial hash are passed through, and eliminated by ContextNode
|
62
59
|
# at the end of the chain. If we weren't dealing with the hash, then ignore that.
|
63
60
|
result_hash =
|
64
|
-
if object.
|
65
|
-
object.
|
61
|
+
if object.is_a?(Hash)
|
62
|
+
object.merge(result)
|
66
63
|
else
|
67
64
|
result
|
68
65
|
end
|
69
66
|
|
70
67
|
result_hash.keys.each { |k| result_hash.delete(k) if result_hash[k] == Datacaster.absent }
|
71
|
-
Datacaster.ValidResult(result_hash
|
68
|
+
Datacaster.ValidResult(result_hash)
|
72
69
|
else
|
73
70
|
Datacaster.ErrorResult(errors)
|
74
71
|
end
|
@@ -1,43 +1,42 @@
|
|
1
1
|
module Datacaster
|
2
2
|
class HashSchema < Base
|
3
|
-
def initialize(fields)
|
3
|
+
def initialize(fields, error_key = nil)
|
4
4
|
@fields = fields
|
5
|
-
|
6
|
-
@
|
5
|
+
|
6
|
+
@error_keys = ['.hash_value', 'datacaster.errors.hash_value']
|
7
|
+
@error_keys.unshift(error_key) if error_key
|
7
8
|
end
|
8
9
|
|
9
|
-
def cast(object)
|
10
|
-
object
|
11
|
-
return Datacaster.ErrorResult(["must be hash"]) unless object.value.is_a?(Hash)
|
10
|
+
def cast(object, runtime:)
|
11
|
+
return Datacaster.ErrorResult(I18nValues::Key.new(@error_keys, value: object)) unless object.is_a?(Hash)
|
12
12
|
|
13
|
-
|
13
|
+
runtime.will_check!
|
14
14
|
|
15
15
|
errors = {}
|
16
16
|
result = {}
|
17
17
|
|
18
18
|
@fields.each do |key, validator|
|
19
19
|
value =
|
20
|
-
if object.
|
21
|
-
object
|
20
|
+
if object.key?(key)
|
21
|
+
object[key]
|
22
22
|
else
|
23
23
|
Datacaster.absent
|
24
24
|
end
|
25
25
|
|
26
|
-
new_value = validator.(value)
|
26
|
+
new_value = runtime.checked_key!(key) { validator.with_runtime(runtime).(value) }
|
27
27
|
if new_value.valid?
|
28
28
|
result[key] = new_value.value
|
29
|
-
checked_schema[key] = new_value.meta[:checked_schema].dup || true
|
30
29
|
else
|
31
|
-
errors[key] = new_value.
|
30
|
+
errors[key] = new_value.raw_errors
|
32
31
|
end
|
33
32
|
end
|
34
33
|
|
35
34
|
if errors.empty?
|
36
|
-
# All unchecked key-value pairs are passed through, and eliminated by
|
35
|
+
# All unchecked key-value pairs are passed through, and eliminated by ContextNode
|
37
36
|
# at the end of the chain
|
38
|
-
result_hash = object.
|
37
|
+
result_hash = object.merge(result)
|
39
38
|
result_hash.keys.each { |k| result_hash.delete(k) if result_hash[k] == Datacaster.absent }
|
40
|
-
Datacaster.ValidResult(result_hash
|
39
|
+
Datacaster.ValidResult(result_hash)
|
41
40
|
else
|
42
41
|
Datacaster.ErrorResult(errors)
|
43
42
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Datacaster
|
2
|
+
module I18nValues
|
3
|
+
class Base
|
4
|
+
attr_reader :args
|
5
|
+
|
6
|
+
def *(other, additional_scope = [])
|
7
|
+
# To allow redefine array/hash errors with #i18n_key
|
8
|
+
other = other.first if other.is_a?(Array) && other.length == 1
|
9
|
+
result = apply(other, additional_scope)
|
10
|
+
|
11
|
+
result = [result] unless result.is_a?(Array) || result.is_a?(Hash)
|
12
|
+
result
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
self.class == other.class && @args == other.args
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def apply(other, additional_scope = [])
|
22
|
+
if !other.is_a?(Base)
|
23
|
+
return apply_to_literal(other, additional_scope)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Key(...) * Scope(...) -> error
|
27
|
+
if is_a?(Key) && !other.is_a?(Key)
|
28
|
+
raise RuntimeError.new("Can not apply #{inspect} to #{other.inspect}")
|
29
|
+
end
|
30
|
+
|
31
|
+
merged_args = other.args.merge(@args)
|
32
|
+
|
33
|
+
# Key(...) * Key(...) -> left
|
34
|
+
if is_a?(Key) && other.is_a?(Key)
|
35
|
+
return Key.new(@keys, merged_args)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Scope('x') * Key(['.relative', 'full_path']) = Key(['x.relative', 'full_path'])
|
39
|
+
if is_a?(Scope) && other.is_a?(Key)
|
40
|
+
scoped_keys =
|
41
|
+
other.keys.flat_map do |x|
|
42
|
+
next x if x[0] != '.'
|
43
|
+
|
44
|
+
keys = ["#{@scope}#{x}"]
|
45
|
+
next keys if x.count('.') > 1
|
46
|
+
|
47
|
+
accumulator = ""
|
48
|
+
additional_scope.each do |k|
|
49
|
+
accumulator << ".#{k}"
|
50
|
+
keys.unshift "#{@scope}#{accumulator}#{x}"
|
51
|
+
end
|
52
|
+
|
53
|
+
keys
|
54
|
+
end
|
55
|
+
return Key.new(scoped_keys, merged_args)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Scope(...) * Scope(...) -> error
|
59
|
+
raise RuntimeError.new("Can not apply #{inspect} to #{other.inspect}")
|
60
|
+
end
|
61
|
+
|
62
|
+
def apply_to_literal(other, additional_scope = [])
|
63
|
+
# Base * Other -> Other
|
64
|
+
return other if !other.is_a?(Hash) && !other.is_a?(Array)
|
65
|
+
|
66
|
+
# Key(...) * Array -> Array
|
67
|
+
# Key(...) * Hash -> Hash
|
68
|
+
return other if is_a?(Key)
|
69
|
+
|
70
|
+
# Scope(...) * Array -> map
|
71
|
+
return other.map { |x| self.*(x, additional_scope) } if other.is_a?(Array)
|
72
|
+
|
73
|
+
# Scope(...) * Hash -> map values
|
74
|
+
other.map do |(k, v)|
|
75
|
+
new_value =
|
76
|
+
case k
|
77
|
+
when String, Symbol
|
78
|
+
self.*(v, [*additional_scope, k])
|
79
|
+
else
|
80
|
+
self.*(v, [*additional_scope])
|
81
|
+
end
|
82
|
+
[k, new_value]
|
83
|
+
end.to_h
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Datacaster
|
2
|
+
module I18nValues
|
3
|
+
class Key < Base
|
4
|
+
attr_reader :keys
|
5
|
+
|
6
|
+
def initialize(keys_or_key, args = {})
|
7
|
+
keys = Array(keys_or_key)
|
8
|
+
@keys = keys
|
9
|
+
@args = args
|
10
|
+
end
|
11
|
+
|
12
|
+
def ==(other)
|
13
|
+
super && @keys == other.keys
|
14
|
+
end
|
15
|
+
|
16
|
+
def resolve
|
17
|
+
keys = @keys.select { |x| x[0] != '.' }
|
18
|
+
if keys.empty?
|
19
|
+
raise RuntimeError.new("No absolute keys among #{@keys.inspect}. Use #i18n_key in addition to #i18n_scope.")
|
20
|
+
end
|
21
|
+
key = keys.find(&Config.i18n_exists?) || keys.first
|
22
|
+
Config.i18n_t.(key, **@args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def with_args(args)
|
26
|
+
self.class.new(@keys, @args.merge(args))
|
27
|
+
end
|
28
|
+
|
29
|
+
def inspect
|
30
|
+
"#<#{self.class.name}(#{@keys.inspect}) #{@args.inspect}>"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Datacaster
|
2
|
+
module I18nValues
|
3
|
+
class Scope < Base
|
4
|
+
attr_reader :scope
|
5
|
+
|
6
|
+
def initialize(scope, args = {})
|
7
|
+
@scope = scope
|
8
|
+
@args = args
|
9
|
+
end
|
10
|
+
|
11
|
+
def ==(other)
|
12
|
+
super && @scope == other.scope
|
13
|
+
end
|
14
|
+
|
15
|
+
def resolve
|
16
|
+
raise RuntimeError.new("Tried to resolve i18n scope #{@scope.inspect}. Use #i18n_key in addition to #i18n_scope.")
|
17
|
+
end
|
18
|
+
|
19
|
+
def with_args(args)
|
20
|
+
self.class.new(@scope, @args.merge(args))
|
21
|
+
end
|
22
|
+
|
23
|
+
def inspect
|
24
|
+
"#<#{self.class.name}(#{@scope.inspect}) #{@args.inspect}>"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -4,11 +4,8 @@ module Datacaster
|
|
4
4
|
@keys = keys
|
5
5
|
end
|
6
6
|
|
7
|
-
def cast(object)
|
8
|
-
|
9
|
-
object = intermediary_result.value
|
10
|
-
|
11
|
-
return Datacaster.ErrorResult(["must be Hash"]) unless object.is_a?(Hash)
|
7
|
+
def cast(object, runtime:)
|
8
|
+
return Datacaster.ErrorResult(I18nValues::Key.new(['.hash_value', 'datacaster.errors.hash_value'], value: object)) unless object.is_a?(Hash)
|
12
9
|
|
13
10
|
result = set_initial_value(object)
|
14
11
|
|
@@ -35,7 +32,7 @@ module Datacaster
|
|
35
32
|
end
|
36
33
|
|
37
34
|
def need_hash_merger?(object)
|
38
|
-
@need_hash_merger =
|
35
|
+
@need_hash_merger =
|
39
36
|
@need_hash_merger.nil? ? @keys.any? { |k| object[k].is_a?(Hash) } : @need_hash_merger
|
40
37
|
end
|
41
38
|
|
@@ -44,7 +41,7 @@ module Datacaster
|
|
44
41
|
unit = [unit] unless unit.is_a?(Array)
|
45
42
|
|
46
43
|
result = clean(unit | merge_with)
|
47
|
-
result
|
44
|
+
result == [] ? Datacaster.absent : result
|
48
45
|
end
|
49
46
|
|
50
47
|
def value_or(value, default)
|
@@ -54,12 +51,8 @@ module Datacaster
|
|
54
51
|
def merge_hash_with_hash(result, merge_with)
|
55
52
|
if merge_with.is_a?(Hash)
|
56
53
|
merge_with.each do |k, v|
|
57
|
-
|
58
|
-
|
59
|
-
result[k] = merge_hash_with_hash(result[k], v)
|
60
|
-
else
|
61
|
-
result[k] = merge_array_or_scalar(value_or(result[k], []), v)
|
62
|
-
end
|
54
|
+
result = value_or(result, {})
|
55
|
+
result[k] = merge_hash_with_hash(result[k], v)
|
63
56
|
end
|
64
57
|
|
65
58
|
result
|
@@ -85,12 +78,12 @@ module Datacaster
|
|
85
78
|
when Array
|
86
79
|
value.delete_if do |v|
|
87
80
|
clean(v) if v.is_a?(Hash) || v.is_a?(Array)
|
88
|
-
v == Datacaster.absent
|
81
|
+
v == Datacaster.absent || v == nil
|
89
82
|
end
|
90
83
|
when Hash
|
91
84
|
value.delete_if do |_k, v|
|
92
85
|
clean(v) if v.is_a?(Hash) || v.is_a?(Array)
|
93
|
-
v == Datacaster.absent
|
86
|
+
v == Datacaster.absent || v == nil
|
94
87
|
end
|
95
88
|
end
|
96
89
|
end
|
data/lib/datacaster/or_node.rb
CHANGED
@@ -5,13 +5,12 @@ module Datacaster
|
|
5
5
|
@right = right
|
6
6
|
end
|
7
7
|
|
8
|
-
def cast(object)
|
9
|
-
|
10
|
-
left_result = @left.(object)
|
8
|
+
def cast(object, runtime:)
|
9
|
+
left_result = @left.with_runtime(runtime).(object)
|
11
10
|
|
12
11
|
return left_result if left_result.valid?
|
13
12
|
|
14
|
-
@right.(object)
|
13
|
+
@right.with_runtime(runtime).(object)
|
15
14
|
end
|
16
15
|
|
17
16
|
def inspect
|
@@ -4,73 +4,94 @@ module Datacaster
|
|
4
4
|
|
5
5
|
# Base types
|
6
6
|
|
7
|
-
def cast(
|
8
|
-
Caster.new(
|
7
|
+
def cast(&block)
|
8
|
+
Caster.new(&block)
|
9
9
|
end
|
10
10
|
|
11
|
-
def check(
|
12
|
-
Checker.new(
|
11
|
+
def check(error_key = nil, &block)
|
12
|
+
Checker.new(error_key, &block)
|
13
13
|
end
|
14
14
|
|
15
|
-
def compare(value,
|
16
|
-
Comparator.new(value,
|
15
|
+
def compare(value, error_key = nil)
|
16
|
+
Comparator.new(value, error_key)
|
17
17
|
end
|
18
18
|
|
19
|
-
def transform(
|
20
|
-
Transformer.new(
|
19
|
+
def transform(&block)
|
20
|
+
Transformer.new(&block)
|
21
21
|
end
|
22
22
|
|
23
|
-
def transform_if_present(
|
23
|
+
def transform_if_present(&block)
|
24
24
|
raise 'Expected block' unless block_given?
|
25
25
|
|
26
|
-
Transformer.new
|
26
|
+
Transformer.new { |v| v == Datacaster.absent ? v : block.(v) }
|
27
27
|
end
|
28
28
|
|
29
|
-
def try(
|
30
|
-
Trier.new(
|
29
|
+
def try(error_key = nil, catched_exception:, &block)
|
30
|
+
Trier.new(catched_exception, error_key, &block)
|
31
31
|
end
|
32
32
|
|
33
|
-
def array_schema(element_caster)
|
34
|
-
ArraySchema.new(element_caster)
|
33
|
+
def array_schema(element_caster, error_keys = {})
|
34
|
+
ArraySchema.new(DefinitionDSL.expand(element_caster), error_keys)
|
35
35
|
end
|
36
36
|
alias_method :array_of, :array_schema
|
37
37
|
|
38
|
-
def hash_schema(fields)
|
39
|
-
|
38
|
+
def hash_schema(fields, error_key = nil)
|
39
|
+
unless fields.is_a?(Hash)
|
40
|
+
raise "Expected field definitions in a form of Hash for hash_schema, got #{fields.inspect} instead"
|
41
|
+
end
|
42
|
+
HashSchema.new(
|
43
|
+
fields.transform_values { |f| DefinitionDSL.expand(f) },
|
44
|
+
error_key
|
45
|
+
)
|
40
46
|
end
|
41
47
|
|
42
48
|
def transform_to_hash(fields)
|
43
|
-
HashMapper.new(fields)
|
49
|
+
HashMapper.new(fields.transform_values { |x| DefinitionDSL.expand(x) })
|
44
50
|
end
|
45
51
|
|
46
|
-
def validate(active_model_validations
|
47
|
-
Validator.new(active_model_validations
|
52
|
+
def validate(active_model_validations)
|
53
|
+
Validator.new(active_model_validations)
|
48
54
|
end
|
49
55
|
|
50
56
|
# 'Meta' types
|
51
57
|
|
52
|
-
def absent
|
53
|
-
|
58
|
+
def absent(error_key = nil)
|
59
|
+
error_keys = ['.absent', 'datacaster.errors.absent']
|
60
|
+
error_keys.unshift(error_key) if error_key
|
61
|
+
check { |x| x == Datacaster.absent }.i18n_key(*error_keys)
|
54
62
|
end
|
55
63
|
|
56
|
-
def any
|
57
|
-
|
64
|
+
def any(error_key = nil)
|
65
|
+
error_keys = ['.any', 'datacaster.errors.any']
|
66
|
+
error_keys.unshift(error_key) if error_key
|
67
|
+
check { |x| x != Datacaster.absent }.i18n_key(*error_keys)
|
68
|
+
end
|
69
|
+
|
70
|
+
def default(value, on: nil)
|
71
|
+
transform do |x|
|
72
|
+
if x == Datacaster.absent ||
|
73
|
+
(on && x.respond_to?(on) && x.public_send(on))
|
74
|
+
value
|
75
|
+
else
|
76
|
+
x
|
77
|
+
end
|
78
|
+
end
|
58
79
|
end
|
59
80
|
|
60
81
|
def transform_to_value(value)
|
61
|
-
transform
|
82
|
+
transform { value }
|
62
83
|
end
|
63
84
|
|
64
85
|
def remove
|
65
|
-
transform
|
86
|
+
transform { Datacaster.absent }
|
66
87
|
end
|
67
88
|
|
68
89
|
def pass
|
69
|
-
transform(
|
90
|
+
transform(&:itself)
|
70
91
|
end
|
71
92
|
|
72
93
|
def pick(*keys)
|
73
|
-
must_be(Enumerable) & transform
|
94
|
+
must_be(Enumerable) & transform { |value|
|
74
95
|
result =
|
75
96
|
keys.map do |key|
|
76
97
|
if value.respond_to?(:key?) && !value.key?(key)
|
@@ -90,12 +111,16 @@ module Datacaster
|
|
90
111
|
MessageKeysMerger.new(keys)
|
91
112
|
end
|
92
113
|
|
93
|
-
def responds_to(method)
|
94
|
-
|
114
|
+
def responds_to(method, error_key = nil)
|
115
|
+
error_keys = ['.responds_to', 'datacaster.errors.responds_to']
|
116
|
+
error_keys.unshift(error_key) if error_key
|
117
|
+
check { |x| x.respond_to?(method) }.i18n_key(*error_keys, reference: method.to_s)
|
95
118
|
end
|
96
119
|
|
97
|
-
def must_be(klass)
|
98
|
-
|
120
|
+
def must_be(klass, error_key = nil)
|
121
|
+
error_keys = ['.must_be', 'datacaster.errors.must_be']
|
122
|
+
error_keys.unshift(error_key) if error_key
|
123
|
+
check { |x| x.is_a?(klass) }.i18n_key(*error_keys, reference: klass.name)
|
99
124
|
end
|
100
125
|
|
101
126
|
def optional(base)
|
@@ -104,81 +129,111 @@ module Datacaster
|
|
104
129
|
|
105
130
|
# Strict types
|
106
131
|
|
107
|
-
def decimal(digits = 8)
|
108
|
-
|
132
|
+
def decimal(digits = 8, error_key = nil)
|
133
|
+
error_keys = ['.decimal', 'datacaster.errors.decimal']
|
134
|
+
error_keys.unshift(error_key) if error_key
|
135
|
+
|
136
|
+
Trier.new([ArgumentError, TypeError]) do |x|
|
109
137
|
# strictly validate format of string, BigDecimal() doesn't do that
|
110
138
|
Float(x)
|
111
139
|
|
112
140
|
BigDecimal(x, digits)
|
113
|
-
end
|
141
|
+
end.i18n_key(*error_keys)
|
114
142
|
end
|
115
143
|
|
116
|
-
def array
|
117
|
-
|
144
|
+
def array(error_key = nil)
|
145
|
+
error_keys = ['.array', 'datacaster.errors.array']
|
146
|
+
error_keys.unshift(error_key) if error_key
|
147
|
+
check { |x| x.is_a?(Array) }.i18n_key(*error_keys)
|
118
148
|
end
|
119
149
|
|
120
|
-
def float
|
121
|
-
|
150
|
+
def float(error_key = nil)
|
151
|
+
error_keys = ['.float', 'datacaster.errors.float']
|
152
|
+
error_keys.unshift(error_key) if error_key
|
153
|
+
check { |x| x.is_a?(Float) }.i18n_key(*error_keys)
|
122
154
|
end
|
123
155
|
|
124
|
-
# 'hash'
|
125
|
-
def hash_value
|
126
|
-
|
156
|
+
# 'hash' would be a bad method name, because it would override built in Object#hash
|
157
|
+
def hash_value(error_key = nil)
|
158
|
+
error_keys = ['.hash_value', 'datacaster.errors.hash_value']
|
159
|
+
error_keys.unshift(error_key) if error_key
|
160
|
+
check(error_key) { |x| x.is_a?(Hash) }
|
127
161
|
end
|
128
162
|
|
129
|
-
def hash_with_symbolized_keys
|
130
|
-
hash_value & transform
|
163
|
+
def hash_with_symbolized_keys(error_key = nil)
|
164
|
+
hash_value(error_key) & transform { |x| x.symbolize_keys }
|
131
165
|
end
|
132
166
|
|
133
|
-
def integer
|
134
|
-
|
167
|
+
def integer(error_key = nil)
|
168
|
+
error_keys = ['.integer', 'datacaster.errors.integer']
|
169
|
+
error_keys.unshift(error_key) if error_key
|
170
|
+
check { |x| x.is_a?(Integer) }.i18n_key(*error_keys)
|
135
171
|
end
|
136
172
|
|
137
|
-
def integer32
|
138
|
-
|
173
|
+
def integer32(error_key = nil)
|
174
|
+
error_keys = ['.integer32', 'datacaster.errors.integer32']
|
175
|
+
error_keys.unshift(error_key) if error_key
|
176
|
+
integer(error_key) & check { |x| x.abs <= 2_147_483_647 }.i18n_key(*error_keys)
|
139
177
|
end
|
140
178
|
|
141
|
-
def string
|
142
|
-
|
179
|
+
def string(error_key = nil)
|
180
|
+
error_keys = ['.string', 'datacaster.errors.string']
|
181
|
+
error_keys.unshift(error_key) if error_key
|
182
|
+
check { |x| x.is_a?(String) }.i18n_key(*error_keys)
|
143
183
|
end
|
144
184
|
|
145
|
-
def non_empty_string
|
146
|
-
|
185
|
+
def non_empty_string(error_key = nil)
|
186
|
+
error_keys = ['.non_empty_string', 'datacaster.errors.non_empty_string']
|
187
|
+
error_keys.unshift(error_key) if error_key
|
188
|
+
string(error_key) & check { |x| !x.empty? }.i18n_key(*error_keys)
|
147
189
|
end
|
148
190
|
|
149
191
|
# Form request types
|
150
192
|
|
151
|
-
def iso8601
|
152
|
-
|
153
|
-
|
193
|
+
def iso8601(error_key = nil)
|
194
|
+
error_keys = ['.iso8601', 'datacaster.errors.iso8601']
|
195
|
+
error_keys.unshift(error_key) if error_key
|
196
|
+
|
197
|
+
string(error_key) &
|
198
|
+
try(catched_exception: [ArgumentError, TypeError]) { |x| DateTime.iso8601(x) }.
|
199
|
+
i18n_key(*error_keys)
|
154
200
|
end
|
155
201
|
|
156
|
-
def to_boolean
|
157
|
-
|
202
|
+
def to_boolean(error_key = nil)
|
203
|
+
error_keys = ['.to_boolean', 'datacaster.errors.to_boolean']
|
204
|
+
error_keys.unshift(error_key) if error_key
|
205
|
+
|
206
|
+
cast do |x|
|
158
207
|
if ['true', '1', true].include?(x)
|
159
208
|
Datacaster.ValidResult(true)
|
160
209
|
elsif ['false', '0', false].include?(x)
|
161
210
|
Datacaster.ValidResult(false)
|
162
211
|
else
|
163
|
-
Datacaster.ErrorResult(
|
212
|
+
Datacaster.ErrorResult(Datacaster::I18nValues::Key.new(error_keys, value: x))
|
164
213
|
end
|
165
214
|
end
|
166
215
|
end
|
167
216
|
|
168
|
-
def to_float
|
169
|
-
|
217
|
+
def to_float(error_key = nil)
|
218
|
+
error_keys = ['.to_float', 'datacaster.errors.to_float']
|
219
|
+
error_keys.unshift(error_key) if error_key
|
220
|
+
|
221
|
+
Trier.new([ArgumentError, TypeError]) do |x|
|
170
222
|
Float(x)
|
171
|
-
end
|
223
|
+
end.i18n_key(*error_keys)
|
172
224
|
end
|
173
225
|
|
174
|
-
def to_integer
|
175
|
-
|
226
|
+
def to_integer(error_key = nil)
|
227
|
+
error_keys = ['.to_integer', 'datacaster.errors.to_integer']
|
228
|
+
error_keys.unshift(error_key) if error_key
|
229
|
+
|
230
|
+
Trier.new([ArgumentError, TypeError]) do |x|
|
176
231
|
Integer(x)
|
177
|
-
end
|
232
|
+
end.i18n_key(*error_keys)
|
178
233
|
end
|
179
234
|
|
180
235
|
def optional_param(base)
|
181
|
-
transform_if_present
|
236
|
+
transform_if_present { |x| x == '' ? Datacaster::Absent.instance : x } & (absent | base)
|
182
237
|
end
|
183
238
|
end
|
184
239
|
end
|