datacaster 6.0.3 → 6.1.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/lib/datacaster/context_node.rb +8 -12
- data/lib/datacaster/context_nodes/errors_caster.rb +2 -2
- data/lib/datacaster/context_nodes/i18n.rb +1 -1
- data/lib/datacaster/context_nodes/i18n_keys_mapper.rb +1 -1
- data/lib/datacaster/context_nodes/pass_if.rb +1 -2
- data/lib/datacaster/context_nodes/structure_cleaner.rb +8 -8
- data/lib/datacaster/message_keys_merger.rb +3 -11
- data/lib/datacaster/or_node.rb +1 -1
- data/lib/datacaster/predefined.rb +13 -8
- data/lib/datacaster/runtimes/base.rb +4 -0
- data/lib/datacaster/runtimes/structure_cleaner.rb +27 -3
- data/lib/datacaster/switch_node.rb +1 -1
- data/lib/datacaster/then_node.rb +1 -1
- data/lib/datacaster/utils.rb +6 -0
- data/lib/datacaster/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 01b7b515fe0b568974d1278356098f73459b80550132061b33cd87aec5d19551
|
|
4
|
+
data.tar.gz: e2d08e1e016df1221b40fcafe0fc6b47f430c0a899c8d1f1519e9e06157070fe
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ee0e18d9b8a2ac16de10dee56785bbcb53a014e0b6480a5f36c48cdff23694061de7d80ab6cc56090f9e435c65efb4b91086fd9e84f7fc6a3dd7d62c750a9a83
|
|
7
|
+
data.tar.gz: 64c6f333f085f4933e8b093e8feb66a964d4cf4a2797e65ae236c31e618f7aa86becb3be5b99791928161f6b9f7e0e19124ca8ef03bdcc501fb0b7320c5a68dd
|
|
@@ -5,9 +5,9 @@ module Datacaster
|
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
def cast(object, runtime:)
|
|
8
|
-
|
|
9
|
-
result = @base.with_runtime(
|
|
10
|
-
transform_result(result)
|
|
8
|
+
runtime = create_runtime(runtime)
|
|
9
|
+
result = @base.with_runtime(runtime).call(object)
|
|
10
|
+
transform_result(result, runtime)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def to_json_schema
|
|
@@ -28,23 +28,19 @@ module Datacaster
|
|
|
28
28
|
parent
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def runtime
|
|
32
|
-
@runtime
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def transform_result(result)
|
|
31
|
+
def transform_result(result, runtime)
|
|
36
32
|
if result.valid?
|
|
37
|
-
Datacaster.ValidResult(transform_success(result.value))
|
|
33
|
+
Datacaster.ValidResult(transform_success(result.value, runtime))
|
|
38
34
|
else
|
|
39
|
-
Datacaster.ErrorResult(transform_errors(result.raw_errors))
|
|
35
|
+
Datacaster.ErrorResult(transform_errors(result.raw_errors, runtime))
|
|
40
36
|
end
|
|
41
37
|
end
|
|
42
38
|
|
|
43
|
-
def transform_success(value)
|
|
39
|
+
def transform_success(value, _runtime)
|
|
44
40
|
value
|
|
45
41
|
end
|
|
46
42
|
|
|
47
|
-
def transform_errors(errors)
|
|
43
|
+
def transform_errors(errors, _runtime)
|
|
48
44
|
errors
|
|
49
45
|
end
|
|
50
46
|
end
|
|
@@ -2,8 +2,7 @@ module Datacaster
|
|
|
2
2
|
module ContextNodes
|
|
3
3
|
class PassIf < Datacaster::ContextNode
|
|
4
4
|
def cast(object, runtime:)
|
|
5
|
-
|
|
6
|
-
result = @base.with_runtime(@runtime).call(object)
|
|
5
|
+
result = @base.with_runtime(create_runtime(runtime)).call(object)
|
|
7
6
|
result.valid? ? Datacaster::ValidResult(object) : result
|
|
8
7
|
end
|
|
9
8
|
end
|
|
@@ -21,26 +21,26 @@ module Datacaster
|
|
|
21
21
|
Runtimes::StructureCleaner.new(parent)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def transform_result(result)
|
|
24
|
+
def transform_result(result, runtime)
|
|
25
25
|
return result unless result.valid?
|
|
26
|
-
result = cast_success(result)
|
|
26
|
+
result = cast_success(result, runtime)
|
|
27
27
|
|
|
28
28
|
# Notify parent runtime of current runtime's schema
|
|
29
|
-
unless
|
|
30
|
-
parent_runtime =
|
|
29
|
+
unless runtime.unchecked?
|
|
30
|
+
parent_runtime = runtime.instance_variable_get(:@parent)
|
|
31
31
|
if parent_runtime.respond_to?(:checked_schema!)
|
|
32
|
-
parent_runtime.checked_schema!(
|
|
32
|
+
parent_runtime.checked_schema!(runtime.checked_schema)
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
result
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
def cast_success(result)
|
|
39
|
+
def cast_success(result, runtime)
|
|
40
40
|
return result if @strategy == :pass
|
|
41
|
-
return result if
|
|
41
|
+
return result if runtime.unchecked?
|
|
42
42
|
|
|
43
|
-
cast_value(result,
|
|
43
|
+
cast_value(result, runtime.checked_schema)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
def cast_value(result, schema)
|
|
@@ -7,11 +7,12 @@ module Datacaster
|
|
|
7
7
|
def cast(object, runtime:)
|
|
8
8
|
return Datacaster.ErrorResult(I18nValues::Key.new(['.hash_value', 'datacaster.errors.hash_value'], value: object)) unless object.is_a?(Hash)
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
hash_merger = @keys.any? { |k| object[k].is_a?(Hash) }
|
|
11
|
+
result = hash_merger ? {} : []
|
|
11
12
|
|
|
12
13
|
@keys.each do |k|
|
|
13
14
|
result =
|
|
14
|
-
if
|
|
15
|
+
if hash_merger
|
|
15
16
|
merge_hash(result, object[k])
|
|
16
17
|
else
|
|
17
18
|
merge_array_or_scalar(result, object[k])
|
|
@@ -27,15 +28,6 @@ module Datacaster
|
|
|
27
28
|
|
|
28
29
|
private
|
|
29
30
|
|
|
30
|
-
def set_initial_value(object)
|
|
31
|
-
need_hash_merger?(object) ? {} : []
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def need_hash_merger?(object)
|
|
35
|
-
@need_hash_merger =
|
|
36
|
-
@need_hash_merger.nil? ? @keys.any? { |k| object[k].is_a?(Hash) } : @need_hash_merger
|
|
37
|
-
end
|
|
38
|
-
|
|
39
31
|
def merge_array_or_scalar(unit, merge_with)
|
|
40
32
|
merge_with = [merge_with] unless merge_with.is_a?(Array)
|
|
41
33
|
unit = [unit] unless unit.is_a?(Array)
|
data/lib/datacaster/or_node.rb
CHANGED
|
@@ -161,17 +161,17 @@ module Datacaster
|
|
|
161
161
|
return (absent | base).json_schema { base.to_json_schema }.json_schema_attributes(required: false)
|
|
162
162
|
end
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
(!on.nil? && x.respond_to?(on) && x.public_send(on))
|
|
167
|
-
Datacaster.ValidResult(Datacaster.absent)
|
|
168
|
-
else
|
|
169
|
-
base.(x)
|
|
170
|
-
end
|
|
164
|
+
unless on.is_a?(Symbol)
|
|
165
|
+
raise RuntimeError, "`on` should be a Symbol"
|
|
171
166
|
end
|
|
172
167
|
|
|
168
|
+
caster =
|
|
169
|
+
absent |
|
|
170
|
+
(check { |x| x.respond_to?(on) && x.public_send(on) } & transform { Datacaster.absent }) |
|
|
171
|
+
base
|
|
172
|
+
|
|
173
173
|
caster
|
|
174
|
-
.json_schema
|
|
174
|
+
.json_schema { base.to_json_schema }
|
|
175
175
|
.json_schema_attributes(required: false)
|
|
176
176
|
end
|
|
177
177
|
|
|
@@ -342,6 +342,11 @@ module Datacaster
|
|
|
342
342
|
# strictly validate format of string, BigDecimal() doesn't do that
|
|
343
343
|
Float(x)
|
|
344
344
|
|
|
345
|
+
# BigDecimal(Float, digits) keeps `digits` significant digits, so
|
|
346
|
+
# BigDecimal(1234567.89, 8) is 1234567.9. The Float's own string
|
|
347
|
+
# form parses exactly: BigDecimal("1234567.89") is 1234567.89.
|
|
348
|
+
x = x.to_s if x.is_a?(Float)
|
|
349
|
+
|
|
345
350
|
BigDecimal(x, digits)
|
|
346
351
|
end.i18n_key(*error_keys).json_schema(type: 'string')
|
|
347
352
|
end
|
|
@@ -38,6 +38,10 @@ module Datacaster
|
|
|
38
38
|
!@parent.nil? && @parent.respond_to?(m, include_private)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
def record_checks_on_success(&block)
|
|
42
|
+
@parent ? @parent.record_checks_on_success(&block) : yield
|
|
43
|
+
end
|
|
44
|
+
|
|
41
45
|
def after_call!(sender)
|
|
42
46
|
@parent.after_call!(sender) if @parent
|
|
43
47
|
end
|
|
@@ -21,8 +21,9 @@ module Datacaster
|
|
|
21
21
|
return
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
@pointer_stack.last[key] ||= {}
|
|
25
|
-
|
|
24
|
+
entry = (@pointer_stack.last[key] ||= {})
|
|
25
|
+
# A key checked unconditionally stays so; checks made inside it are dropped
|
|
26
|
+
@pointer_stack.push(entry == true ? {} : entry)
|
|
26
27
|
@should_check_stack.push(false)
|
|
27
28
|
result = yield if block_given?
|
|
28
29
|
was_checked = @should_check_stack.pop
|
|
@@ -53,10 +54,33 @@ module Datacaster
|
|
|
53
54
|
# Child runtime's schema should be merged with current runtime's schema
|
|
54
55
|
else
|
|
55
56
|
will_check!
|
|
56
|
-
@pointer_stack[-1]
|
|
57
|
+
Utils.merge_checks!(@pointer_stack[-1], schema)
|
|
57
58
|
end
|
|
58
59
|
end
|
|
59
60
|
|
|
61
|
+
# Records the checks made by the block only if its result is valid,
|
|
62
|
+
# as a nested schema reports its checks to the parent only on success
|
|
63
|
+
def record_checks_on_success
|
|
64
|
+
level = @pointer_stack[-1]
|
|
65
|
+
saved_should_check = @should_check_stack[-1]
|
|
66
|
+
@pointer_stack[-1] = {}
|
|
67
|
+
|
|
68
|
+
result = yield
|
|
69
|
+
branch = @pointer_stack[-1]
|
|
70
|
+
@pointer_stack[-1] = level
|
|
71
|
+
|
|
72
|
+
if result.valid?
|
|
73
|
+
if branch == true
|
|
74
|
+
@pointer_stack[-1] = true unless level == true
|
|
75
|
+
elsif level != true
|
|
76
|
+
Utils.merge_checks!(level, branch)
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
@should_check_stack[-1] = saved_should_check
|
|
80
|
+
end
|
|
81
|
+
result
|
|
82
|
+
end
|
|
83
|
+
|
|
60
84
|
def ignore_checks!(&block)
|
|
61
85
|
@ignore = true
|
|
62
86
|
result = yield
|
|
@@ -63,7 +63,7 @@ module Datacaster
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
@ons.each do |check, clause|
|
|
66
|
-
result = check.with_runtime(runtime).(switch_result)
|
|
66
|
+
result = runtime.record_checks_on_success { check.with_runtime(runtime).(switch_result) }
|
|
67
67
|
next unless result.valid?
|
|
68
68
|
|
|
69
69
|
runtime.checked_key!(@pick_key) if !@pick_key.nil? && !@pick_key.is_a?(Array)
|
data/lib/datacaster/then_node.rb
CHANGED
|
@@ -17,7 +17,7 @@ module Datacaster
|
|
|
17
17
|
raise ArgumentError.new('Datacaster: use "a & b" instead of "a.then(b)" when there is no else-clause')
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
left_result = @left.with_runtime(runtime).(object)
|
|
20
|
+
left_result = runtime.record_checks_on_success { @left.with_runtime(runtime).(object) }
|
|
21
21
|
|
|
22
22
|
if left_result.valid?
|
|
23
23
|
@then.with_runtime(runtime).(left_result.value)
|
data/lib/datacaster/utils.rb
CHANGED
|
@@ -9,6 +9,12 @@ module Datacaster
|
|
|
9
9
|
first.merge(second.to_h, &merger)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
+
# Merges checked schemas key by key: a key accepted whole (true) on either side
|
|
13
|
+
# stays accepted whole, nested checks on both sides combine
|
|
14
|
+
def merge_checks!(into, from)
|
|
15
|
+
into.merge!(from) { |_, a, b| a == true || b == true ? true : merge_checks!(a, b) }
|
|
16
|
+
end
|
|
17
|
+
|
|
12
18
|
def deep_freeze(value, copy: true)
|
|
13
19
|
Ractor.make_shareable(value, copy:)
|
|
14
20
|
end
|
data/lib/datacaster/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: datacaster
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.0
|
|
4
|
+
version: 6.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Eugene Zolotarev
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-10-29 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: activemodel
|
|
@@ -119,6 +120,7 @@ dependencies:
|
|
|
119
120
|
- - ">="
|
|
120
121
|
- !ruby/object:Gem::Version
|
|
121
122
|
version: '0'
|
|
123
|
+
description:
|
|
122
124
|
email:
|
|
123
125
|
- eugzol@gmail.com
|
|
124
126
|
executables: []
|
|
@@ -193,6 +195,7 @@ licenses:
|
|
|
193
195
|
- MIT
|
|
194
196
|
metadata:
|
|
195
197
|
source_code_uri: https://github.com/EugZol/datacaster
|
|
198
|
+
post_install_message:
|
|
196
199
|
rdoc_options: []
|
|
197
200
|
require_paths:
|
|
198
201
|
- lib
|
|
@@ -207,7 +210,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
207
210
|
- !ruby/object:Gem::Version
|
|
208
211
|
version: '0'
|
|
209
212
|
requirements: []
|
|
210
|
-
rubygems_version:
|
|
213
|
+
rubygems_version: 3.5.20
|
|
214
|
+
signing_key:
|
|
211
215
|
specification_version: 4
|
|
212
216
|
summary: Run-time type checker and transformer for Ruby
|
|
213
217
|
test_files: []
|