julewire-core 1.0.1 → 1.1.1
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/CHANGELOG.md +22 -0
- data/docs/configuration.md +14 -7
- data/docs/context-and-propagation.md +20 -0
- data/docs/contracts.md +23 -49
- data/docs/extensions-and-api.md +78 -82
- data/docs/health-schema.md +12 -2
- data/docs/internals.md +21 -20
- data/docs/outputs-and-lifecycle.md +10 -6
- data/docs/records-and-data-policy.md +36 -5
- data/lib/julewire/core/cli/doctor.rb +20 -16
- data/lib/julewire/core/cli/line_helpers.rb +23 -12
- data/lib/julewire/core/cli/log_formats/core_json_decoder.rb +3 -3
- data/lib/julewire/core/cli/log_formats.rb +9 -9
- data/lib/julewire/core/cli/tail.rb +19 -14
- data/lib/julewire/core/cli/transcode.rb +4 -5
- data/lib/julewire/core/cli.rb +1 -1
- data/lib/julewire/core/configuration.rb +1 -1
- data/lib/julewire/core/context_store.rb +51 -87
- data/lib/julewire/core/destinations/chaos_output.rb +2 -2
- data/lib/julewire/core/destinations/collection.rb +8 -16
- data/lib/julewire/core/destinations/definition.rb +1 -9
- data/lib/julewire/core/destinations/destination.rb +13 -63
- data/lib/julewire/core/destinations/processor_handling.rb +78 -0
- data/lib/julewire/core/destinations/registry.rb +1 -1
- data/lib/julewire/core/destinations/sink.rb +0 -1
- data/lib/julewire/core/destinations/synchronized_output.rb +14 -13
- data/lib/julewire/core/destinations/tail_sampling.rb +18 -27
- data/lib/julewire/core/destinations/write_step.rb +5 -5
- data/lib/julewire/core/destinations.rb +0 -7
- data/lib/julewire/core/diagnostics/callback_notifier.rb +4 -2
- data/lib/julewire/core/diagnostics/doctor.rb +16 -9
- data/lib/julewire/core/diagnostics/failure_snapshot.rb +6 -2
- data/lib/julewire/core/diagnostics/health.rb +41 -57
- data/lib/julewire/core/diagnostics/integration_health_store.rb +11 -24
- data/lib/julewire/core/diagnostics/internal_records.rb +8 -12
- data/lib/julewire/core/diagnostics/invalid_severity_reporter.rb +16 -55
- data/lib/julewire/core/diagnostics/meta_observer.rb +37 -44
- data/lib/julewire/core/diagnostics/process_integration_health.rb +0 -5
- data/lib/julewire/core/diagnostics/tail/renderer.rb +1 -1
- data/lib/julewire/core/diagnostics/tail.rb +18 -22
- data/lib/julewire/core/execution/boundary.rb +2 -8
- data/lib/julewire/core/execution/handle.rb +12 -17
- data/lib/julewire/core/execution/lineage.rb +16 -56
- data/lib/julewire/core/execution/measurement_handle.rb +6 -10
- data/lib/julewire/core/execution/scope.rb +15 -20
- data/lib/julewire/core/execution/scope_fields.rb +3 -12
- data/lib/julewire/core/execution/scope_identity.rb +1 -9
- data/lib/julewire/core/execution/scope_snapshot.rb +18 -39
- data/lib/julewire/core/execution/summary_state.rb +16 -19
- data/lib/julewire/core/execution/view.rb +8 -17
- data/lib/julewire/core/facade_methods.rb +67 -65
- data/lib/julewire/core/fields/attribute_keys.rb +0 -2
- data/lib/julewire/core/fields/bags.rb +23 -27
- data/lib/julewire/core/fields/field_set.rb +29 -19
- data/lib/julewire/core/fields/field_stack.rb +68 -134
- data/lib/julewire/core/fields/internal/deletion.rb +6 -9
- data/lib/julewire/core/fields/internal.rb +19 -38
- data/lib/julewire/core/fields/lookup.rb +9 -13
- data/lib/julewire/core/fields/section_proxy.rb +1 -9
- data/lib/julewire/core/fields/stack_set.rb +7 -12
- data/lib/julewire/core/fields/static_labels.rb +1 -1
- data/lib/julewire/core/integration/configurable.rb +4 -3
- data/lib/julewire/core/integration/destination_health.rb +17 -7
- data/lib/julewire/core/integration/event_subscriber.rb +1 -1
- data/lib/julewire/core/integration/facade.rb +12 -15
- data/lib/julewire/core/integration/fork_hooks.rb +12 -36
- data/lib/julewire/core/integration/health.rb +0 -3
- data/lib/julewire/core/integration/ivar_state.rb +0 -5
- data/lib/julewire/core/integration/protocol.rb +20 -0
- data/lib/julewire/core/integration/settings.rb +4 -4
- data/lib/julewire/core/integration/subscriber_install.rb +2 -2
- data/lib/julewire/core/integration/subscription.rb +3 -2
- data/lib/julewire/core/integration/values.rb +0 -17
- data/lib/julewire/core/local_storage.rb +3 -19
- data/lib/julewire/core/processing/invalid_result_failure.rb +23 -0
- data/lib/julewire/core/processing/level_threshold.rb +7 -14
- data/lib/julewire/core/processing/match.rb +6 -4
- data/lib/julewire/core/processing/pipeline.rb +46 -40
- data/lib/julewire/core/processing/processor_chain.rb +22 -11
- data/lib/julewire/core/processing/processor_registry.rb +3 -4
- data/lib/julewire/core/processing/record_field_transform.rb +0 -4
- data/lib/julewire/core/processing/sampling.rb +1 -3
- data/lib/julewire/core/processing.rb +2 -2
- data/lib/julewire/core/propagation/carrier.rb +14 -14
- data/lib/julewire/core/propagation.rb +15 -2
- data/lib/julewire/core/records/build_input.rb +75 -0
- data/lib/julewire/core/records/console_formatter.rb +6 -6
- data/lib/julewire/core/records/deconstruct.rb +1 -1
- data/lib/julewire/core/records/display_message.rb +2 -4
- data/lib/julewire/core/records/draft.rb +125 -262
- data/lib/julewire/core/records/lazy_emit_input.rb +2 -12
- data/lib/julewire/core/records/metadata.rb +4 -3
- data/lib/julewire/core/records/public_projection.rb +2 -2
- data/lib/julewire/core/records/raw_input.rb +1 -1
- data/lib/julewire/core/records/record.rb +19 -37
- data/lib/julewire/core/records/severity.rb +7 -15
- data/lib/julewire/core/runtime.rb +67 -71
- data/lib/julewire/core/runtime_registry.rb +20 -15
- data/lib/julewire/core/runtime_state.rb +5 -3
- data/lib/julewire/core/scheduling/shared_scheduler.rb +28 -22
- data/lib/julewire/core/serialization/backtrace_limiter.rb +13 -9
- data/lib/julewire/core/serialization/bounded_transform.rb +2 -12
- data/lib/julewire/core/serialization/bounded_traversal.rb +49 -66
- data/lib/julewire/core/serialization/deep_compact_empty.rb +9 -11
- data/lib/julewire/core/serialization/deep_freeze.rb +45 -6
- data/lib/julewire/core/serialization/encoding_sanitizer.rb +2 -3
- data/lib/julewire/core/serialization/exception_shape.rb +7 -6
- data/lib/julewire/core/serialization/json_encoder.rb +10 -13
- data/lib/julewire/core/serialization/serializer.rb +23 -50
- data/lib/julewire/core/serialization/serializer_pool.rb +9 -0
- data/lib/julewire/core/serialization/text_encoder.rb +5 -5
- data/lib/julewire/core/serialization/truncation_metadata.rb +63 -48
- data/lib/julewire/core/serialization/value_copy.rb +60 -227
- data/lib/julewire/core/serialization/value_traversal.rb +10 -127
- data/lib/julewire/core/testing.rb +6 -56
- data/lib/julewire/core/validation.rb +2 -3
- data/lib/julewire/core/version.rb +1 -1
- data/lib/julewire/core.rb +2 -7
- metadata +6 -19
- data/lib/julewire/core/scheduling/deadline_scheduler.rb +0 -207
- data/lib/julewire/core/testing/chaos/catalog.rb +0 -72
- data/lib/julewire/core/testing/chaos/core_runtime.rb +0 -120
- data/lib/julewire/core/testing/chaos/destination.rb +0 -55
- data/lib/julewire/core/testing/chaos/emitter.rb +0 -20
- data/lib/julewire/core/testing/chaos/raising_output.rb +0 -42
- data/lib/julewire/core/testing/chaos.rb +0 -80
- data/lib/julewire/core/testing/contracts/component.rb +0 -162
- data/lib/julewire/core/testing/contracts/deadline_scheduler.rb +0 -59
- data/lib/julewire/core/testing/contracts/integration.rb +0 -166
- data/lib/julewire/core/testing/contracts/integration_fields.rb +0 -36
- data/lib/julewire/core/testing/contracts/record_draft.rb +0 -37
- data/lib/julewire/core/testing/contracts/runtime.rb +0 -178
- data/lib/julewire/core/testing/contracts/wire.rb +0 -60
- data/lib/julewire/core/testing/contracts.rb +0 -24
- data/lib/julewire/core/testing/coverage.rb +0 -58
- data/lib/julewire/core/testing/test_reports.rb +0 -78
|
@@ -28,7 +28,7 @@ module Julewire
|
|
|
28
28
|
max_array_items: DEFAULT_MAX_ARRAY_ITEMS,
|
|
29
29
|
max_hash_keys: DEFAULT_MAX_HASH_KEYS,
|
|
30
30
|
compact_empty: false,
|
|
31
|
-
max_backtrace_lines:
|
|
31
|
+
max_backtrace_lines: MAX_BACKTRACE_LINES
|
|
32
32
|
)
|
|
33
33
|
new(
|
|
34
34
|
max_depth: max_depth,
|
|
@@ -47,8 +47,7 @@ module Julewire
|
|
|
47
47
|
max_array_items: DEFAULT_MAX_ARRAY_ITEMS,
|
|
48
48
|
max_hash_keys: DEFAULT_MAX_HASH_KEYS,
|
|
49
49
|
compact_empty: false,
|
|
50
|
-
max_backtrace_lines:
|
|
51
|
-
copy_strings: true
|
|
50
|
+
max_backtrace_lines: MAX_BACKTRACE_LINES
|
|
52
51
|
)
|
|
53
52
|
super(
|
|
54
53
|
max_array_items: max_array_items,
|
|
@@ -63,7 +62,6 @@ module Julewire
|
|
|
63
62
|
name: :max_backtrace_lines
|
|
64
63
|
)
|
|
65
64
|
@compact_empty = compact_empty
|
|
66
|
-
@copy_strings = copy_strings
|
|
67
65
|
end
|
|
68
66
|
|
|
69
67
|
def serialize(value)
|
|
@@ -77,27 +75,25 @@ module Julewire
|
|
|
77
75
|
|
|
78
76
|
private
|
|
79
77
|
|
|
80
|
-
def scalar_value(value, depth
|
|
78
|
+
def scalar_value(value, depth)
|
|
81
79
|
return serialize_exception(value, depth) if value.is_a?(Exception)
|
|
82
80
|
|
|
83
81
|
case value
|
|
84
82
|
when nil, true, false
|
|
85
|
-
|
|
83
|
+
value
|
|
86
84
|
when Numeric
|
|
87
85
|
serialize_numeric(value)
|
|
88
86
|
when Symbol
|
|
89
|
-
|
|
87
|
+
value.to_s
|
|
90
88
|
when String
|
|
91
89
|
serialize_string(value)
|
|
92
|
-
when Time,
|
|
90
|
+
when Time, Date
|
|
93
91
|
serialize_temporal(value)
|
|
94
92
|
else
|
|
95
93
|
return serialize_iso8601_temporal(value) if zone_temporal?(value)
|
|
96
94
|
|
|
97
95
|
serialize_object(value)
|
|
98
96
|
end
|
|
99
|
-
rescue StandardError => e
|
|
100
|
-
clear_truncated(unserializable_marker(e))
|
|
101
97
|
end
|
|
102
98
|
|
|
103
99
|
def serialize_exception(error, depth)
|
|
@@ -116,30 +112,30 @@ module Julewire
|
|
|
116
112
|
end
|
|
117
113
|
|
|
118
114
|
def serialize_numeric(value)
|
|
119
|
-
return serialize_float(value) if value.
|
|
120
|
-
return
|
|
121
|
-
return serialize_string(value.to_s("F")) if defined?(BigDecimal) && value.
|
|
115
|
+
return serialize_float(value) if value.instance_of?(Float)
|
|
116
|
+
return value if value.instance_of?(Integer)
|
|
117
|
+
return serialize_string(value.to_s("F")) if defined?(BigDecimal) && value.instance_of?(::BigDecimal)
|
|
122
118
|
|
|
123
|
-
serialize_string(
|
|
119
|
+
serialize_string(value.to_s)
|
|
124
120
|
end
|
|
125
121
|
|
|
126
122
|
def serialize_float(value)
|
|
127
|
-
return
|
|
128
|
-
return
|
|
123
|
+
return value if value.finite?
|
|
124
|
+
return NAN_VALUE if value.nan?
|
|
129
125
|
|
|
130
|
-
|
|
126
|
+
value.positive? ? INFINITY_VALUE : NEGATIVE_INFINITY_VALUE
|
|
131
127
|
end
|
|
132
128
|
|
|
133
129
|
def serialize_temporal(value)
|
|
134
|
-
return
|
|
135
|
-
return
|
|
130
|
+
return value.getutc.iso8601(9) if value.is_a?(Time)
|
|
131
|
+
return value.iso8601(9) if value.is_a?(DateTime)
|
|
136
132
|
|
|
137
|
-
|
|
133
|
+
value.iso8601
|
|
138
134
|
end
|
|
139
135
|
|
|
140
136
|
def serialize_iso8601_temporal(value)
|
|
141
137
|
temporal = value.respond_to?(:utc) ? value.utc : value
|
|
142
|
-
|
|
138
|
+
EncodingSanitizer.call(temporal.iso8601(9))
|
|
143
139
|
end
|
|
144
140
|
|
|
145
141
|
def zone_temporal?(value)
|
|
@@ -152,9 +148,9 @@ module Julewire
|
|
|
152
148
|
|
|
153
149
|
def raw_omitted_value?(value) = DeepCompactEmpty.omitted?(value)
|
|
154
150
|
|
|
155
|
-
def key_value(key
|
|
151
|
+
def key_value(key) = serialize_key(key)
|
|
156
152
|
|
|
157
|
-
def error_value(error) =
|
|
153
|
+
def error_value(error) = unserializable_marker(error)
|
|
158
154
|
|
|
159
155
|
def serialize_key(key)
|
|
160
156
|
case key
|
|
@@ -170,31 +166,18 @@ module Julewire
|
|
|
170
166
|
end
|
|
171
167
|
|
|
172
168
|
def serialize_symbol_key(key)
|
|
173
|
-
|
|
174
|
-
return serialize_trusted_key_string(name) if safe_trusted_key_name?(name)
|
|
175
|
-
|
|
176
|
-
serialize_key_string(name)
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def safe_trusted_key_name?(value)
|
|
180
|
-
value.ascii_only? || (value.encoding == Encoding::UTF_8 && value.valid_encoding?)
|
|
169
|
+
serialize_key_string(key.name)
|
|
181
170
|
end
|
|
182
171
|
|
|
183
172
|
def serialize_key_string(value)
|
|
184
173
|
string = EncodingSanitizer.call(value)
|
|
185
|
-
return
|
|
174
|
+
return copy_string(string) if string.bytesize <= MAX_KEY_BYTES
|
|
186
175
|
|
|
187
176
|
mark_truncated("#{string.byteslice(0, MAX_KEY_BYTES).scrub("?")}#{TRUNCATED_SUFFIX}")
|
|
188
177
|
end
|
|
189
178
|
|
|
190
|
-
def serialize_trusted_key_string(value)
|
|
191
|
-
return clear_truncated(value) if value.bytesize <= MAX_KEY_BYTES
|
|
192
|
-
|
|
193
|
-
mark_truncated("#{value.byteslice(0, MAX_KEY_BYTES).scrub("?")}#{TRUNCATED_SUFFIX}")
|
|
194
|
-
end
|
|
195
|
-
|
|
196
179
|
def serialize_object(value)
|
|
197
|
-
|
|
180
|
+
object_marker(value)
|
|
198
181
|
end
|
|
199
182
|
|
|
200
183
|
def object_marker(value)
|
|
@@ -213,20 +196,10 @@ module Julewire
|
|
|
213
196
|
|
|
214
197
|
def serialize_string(value)
|
|
215
198
|
string = EncodingSanitizer.call(value)
|
|
216
|
-
return
|
|
199
|
+
return copy_string(string) if string.bytesize <= @max_string_bytes
|
|
217
200
|
|
|
218
201
|
mark_truncated("#{string.byteslice(0, @max_string_bytes).scrub("?")}#{TRUNCATED_SUFFIX}")
|
|
219
202
|
end
|
|
220
|
-
|
|
221
|
-
def copy_string(value)
|
|
222
|
-
value.frozen? || !@copy_strings ? value : value.dup
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
def record_hash_truncation(fields, _raw_key, key, key_truncated, child_truncated)
|
|
226
|
-
return fields unless key_truncated || child_truncated
|
|
227
|
-
|
|
228
|
-
append_truncation_field(fields, key)
|
|
229
|
-
end
|
|
230
203
|
end
|
|
231
204
|
end
|
|
232
205
|
end
|
|
@@ -14,6 +14,15 @@ module Julewire
|
|
|
14
14
|
end
|
|
15
15
|
pool[serializer_key] ||= yield
|
|
16
16
|
end
|
|
17
|
+
|
|
18
|
+
def serialize(pool_key, serializer_key, payload, &)
|
|
19
|
+
serialize_with(serializer(pool_key, serializer_key, &), payload, &)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def serialize_with(serializer, payload)
|
|
23
|
+
serializer = yield if serializer.in_use?
|
|
24
|
+
serializer.serialize(payload)
|
|
25
|
+
end
|
|
17
26
|
end
|
|
18
27
|
end
|
|
19
28
|
end
|
|
@@ -48,13 +48,13 @@ module Julewire
|
|
|
48
48
|
positive: true
|
|
49
49
|
)
|
|
50
50
|
@color = color
|
|
51
|
-
@
|
|
51
|
+
@append_newline = append_newline
|
|
52
52
|
@theme = validate_theme(theme)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def call(payload)
|
|
56
56
|
text = payload.is_a?(String) ? payload : line_for(payload)
|
|
57
|
-
"#{text}
|
|
57
|
+
@append_newline ? "#{text}\n" : text
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
private
|
|
@@ -82,7 +82,7 @@ module Julewire
|
|
|
82
82
|
# Console output is human-facing; JSON keeps nanosecond precision.
|
|
83
83
|
return value.iso8601(6) if value.respond_to?(:iso8601)
|
|
84
84
|
|
|
85
|
-
value
|
|
85
|
+
value
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
def severity(payload)
|
|
@@ -123,7 +123,7 @@ module Julewire
|
|
|
123
123
|
def compact_hash(name, value)
|
|
124
124
|
return unless value.is_a?(Hash) && !value.empty?
|
|
125
125
|
|
|
126
|
-
"#{name}=#{truncate(JSON.generate(value
|
|
126
|
+
"#{name}=#{truncate(JSON.generate(value))}"
|
|
127
127
|
rescue StandardError
|
|
128
128
|
"#{name}=#{truncate(value.inspect)}"
|
|
129
129
|
end
|
|
@@ -135,7 +135,7 @@ module Julewire
|
|
|
135
135
|
end
|
|
136
136
|
|
|
137
137
|
def value_at(payload, key)
|
|
138
|
-
Fields::Lookup.
|
|
138
|
+
Fields::Lookup.wire_value(payload, key)
|
|
139
139
|
end
|
|
140
140
|
|
|
141
141
|
def blank?(value)
|
|
@@ -4,39 +4,41 @@ module Julewire
|
|
|
4
4
|
module Core
|
|
5
5
|
module Serialization
|
|
6
6
|
module TruncationMetadata
|
|
7
|
+
NAMES = %i[truncated truncated_fields limits max_array_items max_depth max_hash_keys max_string_bytes].freeze
|
|
7
8
|
KEYS = {
|
|
8
|
-
string: {
|
|
9
|
-
|
|
10
|
-
truncated_fields: "truncated_fields",
|
|
11
|
-
limits: "limits",
|
|
12
|
-
max_array_items: "max_array_items",
|
|
13
|
-
max_depth: "max_depth",
|
|
14
|
-
max_hash_keys: "max_hash_keys",
|
|
15
|
-
max_string_bytes: "max_string_bytes"
|
|
16
|
-
}.freeze,
|
|
17
|
-
symbol: {
|
|
18
|
-
truncated: :truncated,
|
|
19
|
-
truncated_fields: :truncated_fields,
|
|
20
|
-
limits: :limits,
|
|
21
|
-
max_array_items: :max_array_items,
|
|
22
|
-
max_depth: :max_depth,
|
|
23
|
-
max_hash_keys: :max_hash_keys,
|
|
24
|
-
max_string_bytes: :max_string_bytes
|
|
25
|
-
}.freeze
|
|
9
|
+
string: NAMES.to_h { [it, it.to_s] }.freeze,
|
|
10
|
+
symbol: NAMES.to_h { [it, it] }.freeze
|
|
26
11
|
}.freeze
|
|
27
12
|
METADATA_KEYS = KEYS.fetch(:symbol).values_at(:truncated, :truncated_fields, :limits).freeze
|
|
28
|
-
METADATA_KEY_NAMES =
|
|
13
|
+
METADATA_KEY_NAMES = KEYS.fetch(:string).values_at(:truncated, :truncated_fields, :limits).freeze
|
|
29
14
|
LIMIT_KEYS = KEYS.fetch(:symbol).values_at(
|
|
30
15
|
:max_array_items,
|
|
31
16
|
:max_depth,
|
|
32
17
|
:max_hash_keys,
|
|
33
18
|
:max_string_bytes
|
|
34
19
|
).freeze
|
|
35
|
-
LIMIT_KEY_NAMES =
|
|
36
|
-
|
|
20
|
+
LIMIT_KEY_NAMES = KEYS.fetch(:string).values_at(
|
|
21
|
+
:max_array_items,
|
|
22
|
+
:max_depth,
|
|
23
|
+
:max_hash_keys,
|
|
24
|
+
:max_string_bytes
|
|
25
|
+
).freeze
|
|
26
|
+
SYMBOL_METADATA_KEYS = KEYS.fetch(:symbol).merge(limit_keys: LIMIT_KEYS).freeze
|
|
27
|
+
STRING_METADATA_KEYS = KEYS.fetch(:string).merge(limit_keys: LIMIT_KEY_NAMES).freeze
|
|
28
|
+
[
|
|
29
|
+
NAMES,
|
|
30
|
+
KEYS,
|
|
31
|
+
METADATA_KEYS,
|
|
32
|
+
METADATA_KEY_NAMES,
|
|
33
|
+
LIMIT_KEYS,
|
|
34
|
+
LIMIT_KEY_NAMES,
|
|
35
|
+
SYMBOL_METADATA_KEYS,
|
|
36
|
+
STRING_METADATA_KEYS
|
|
37
|
+
].each do |constant|
|
|
37
38
|
::Ractor.make_shareable(constant) if defined?(::Ractor) && ::Ractor.respond_to?(:make_shareable)
|
|
38
39
|
end
|
|
39
|
-
private_constant :KEYS, :METADATA_KEYS, :METADATA_KEY_NAMES, :LIMIT_KEYS, :LIMIT_KEY_NAMES
|
|
40
|
+
private_constant :NAMES, :KEYS, :METADATA_KEYS, :METADATA_KEY_NAMES, :LIMIT_KEYS, :LIMIT_KEY_NAMES,
|
|
41
|
+
:SYMBOL_METADATA_KEYS, :STRING_METADATA_KEYS
|
|
40
42
|
|
|
41
43
|
class << self
|
|
42
44
|
def build(fields, max_array_items:, max_depth:, max_hash_keys:, max_string_bytes:, key_style: :string,
|
|
@@ -66,12 +68,25 @@ module Julewire
|
|
|
66
68
|
|
|
67
69
|
def valid?(value, max_fields: nil)
|
|
68
70
|
return false unless value.is_a?(Hash)
|
|
69
|
-
return false unless valid_top_level_keys?(value)
|
|
70
|
-
return false unless fetch_key(value, :truncated) == true
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
keys = metadata_keys(value)
|
|
73
|
+
return false unless keys
|
|
74
|
+
return false unless value.fetch(keys.fetch(:truncated)) == true
|
|
75
|
+
|
|
76
|
+
valid_fields?(value.fetch(keys.fetch(:truncated_fields)), max_fields: max_fields) &&
|
|
77
|
+
valid_limits?(value.fetch(keys.fetch(:limits)), limit_keys: keys.fetch(:limit_keys))
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def copy(value, freeze_values:, key_style: :symbol)
|
|
81
|
+
source_keys = metadata_keys(value)
|
|
82
|
+
target_keys = KEYS.fetch(key_style)
|
|
83
|
+
metadata = {
|
|
84
|
+
target_keys.fetch(:truncated) => true,
|
|
85
|
+
target_keys.fetch(:truncated_fields) => copy_fields(value.fetch(source_keys.fetch(:truncated_fields))),
|
|
86
|
+
target_keys.fetch(:limits) => copy_limits(value.fetch(source_keys.fetch(:limits)), source_keys,
|
|
87
|
+
target_keys)
|
|
88
|
+
}
|
|
89
|
+
freeze_values ? deep_freeze(metadata, target_keys) : metadata
|
|
75
90
|
end
|
|
76
91
|
|
|
77
92
|
private
|
|
@@ -97,43 +112,43 @@ module Julewire
|
|
|
97
112
|
metadata.freeze
|
|
98
113
|
end
|
|
99
114
|
|
|
100
|
-
def
|
|
101
|
-
|
|
115
|
+
def copy_fields(fields)
|
|
116
|
+
fields.map(&:dup)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def copy_limits(limits, source_keys, target_keys)
|
|
120
|
+
LIMIT_KEYS.each_with_object({}) do |name, copied|
|
|
121
|
+
source_key = source_keys.fetch(name)
|
|
122
|
+
next unless limits.key?(source_key)
|
|
102
123
|
|
|
103
|
-
|
|
124
|
+
copied[target_keys.fetch(name)] = limits.fetch(source_key)
|
|
125
|
+
end
|
|
104
126
|
end
|
|
105
127
|
|
|
106
|
-
def
|
|
107
|
-
return
|
|
128
|
+
def metadata_keys(value)
|
|
129
|
+
return SYMBOL_METADATA_KEYS if exact_keys?(value, METADATA_KEYS)
|
|
108
130
|
|
|
109
|
-
|
|
110
|
-
|
|
131
|
+
STRING_METADATA_KEYS if exact_keys?(value, METADATA_KEY_NAMES)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def exact_keys?(value, keys)
|
|
135
|
+
value.length == keys.length && keys.all? { value.key?(it) }
|
|
111
136
|
end
|
|
112
137
|
|
|
113
138
|
def valid_fields?(fields, max_fields:)
|
|
114
139
|
return false unless fields.is_a?(Array)
|
|
140
|
+
return false if max_fields && fields.length > max_fields
|
|
115
141
|
|
|
116
|
-
|
|
117
|
-
fields.each do |field|
|
|
118
|
-
seen += 1
|
|
119
|
-
return false if max_fields && seen > max_fields
|
|
120
|
-
return false unless field.is_a?(String) || field.is_a?(Symbol)
|
|
121
|
-
end
|
|
122
|
-
true
|
|
142
|
+
fields.all?(String)
|
|
123
143
|
end
|
|
124
144
|
|
|
125
|
-
def valid_limits?(limits)
|
|
145
|
+
def valid_limits?(limits, limit_keys:)
|
|
126
146
|
return false unless limits.is_a?(Hash)
|
|
127
|
-
return false if limits.length > LIMIT_KEYS.length * 2
|
|
128
147
|
|
|
129
148
|
limits.all? do |key, value|
|
|
130
|
-
|
|
149
|
+
limit_keys.include?(key) && (value.nil? || value.instance_of?(Integer))
|
|
131
150
|
end
|
|
132
151
|
end
|
|
133
|
-
|
|
134
|
-
def known_key?(key, symbol_keys, string_keys)
|
|
135
|
-
symbol_keys.include?(key) || string_keys.include?(key)
|
|
136
|
-
end
|
|
137
152
|
end
|
|
138
153
|
end
|
|
139
154
|
private_constant :TruncationMetadata
|