datacaster 2.0.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|