schemurai 3.1.0-aarch64-linux-gnu

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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +395 -0
  4. data/lib/schemurai/backend.rb +34 -0
  5. data/lib/schemurai/container_checks/array_diagnostics.rb +119 -0
  6. data/lib/schemurai/container_checks/object_diagnostics.rb +152 -0
  7. data/lib/schemurai/container_checks.rb +534 -0
  8. data/lib/schemurai/decimal.rb +11 -0
  9. data/lib/schemurai/dialect.rb +106 -0
  10. data/lib/schemurai/dialect_keywords.rb +91 -0
  11. data/lib/schemurai/dialects/draft2019_09.rb +27 -0
  12. data/lib/schemurai/dialects/draft2020_12.rb +27 -0
  13. data/lib/schemurai/dialects/draft7.rb +27 -0
  14. data/lib/schemurai/ecma_regexp.rb +46 -0
  15. data/lib/schemurai/error_message.rb +102 -0
  16. data/lib/schemurai/evaluation.rb +63 -0
  17. data/lib/schemurai/evaluation_limits.rb +65 -0
  18. data/lib/schemurai/evaluation_pool.rb +66 -0
  19. data/lib/schemurai/evaluator.rb +861 -0
  20. data/lib/schemurai/formats.rb +403 -0
  21. data/lib/schemurai/json_pointer.rb +11 -0
  22. data/lib/schemurai/limit_budget.rb +78 -0
  23. data/lib/schemurai/limit_exceeded.rb +18 -0
  24. data/lib/schemurai/limited_evaluator.rb +43 -0
  25. data/lib/schemurai/meta_schemas/draft2019_09.rb +149 -0
  26. data/lib/schemurai/meta_schemas/draft2020_12.rb +149 -0
  27. data/lib/schemurai/meta_schemas/draft7.rb +121 -0
  28. data/lib/schemurai/meta_schemas.rb +28 -0
  29. data/lib/schemurai/native/4.0/schemurai_native.so +0 -0
  30. data/lib/schemurai/native/diagnostics.rb +53 -0
  31. data/lib/schemurai/native/evaluator.rb +87 -0
  32. data/lib/schemurai/native/null_numeric.rb +23 -0
  33. data/lib/schemurai/number_checks.rb +128 -0
  34. data/lib/schemurai/schema_domain.rb +95 -0
  35. data/lib/schemurai/schema_graph.rb +538 -0
  36. data/lib/schemurai/schema_node.rb +55 -0
  37. data/lib/schemurai/string_checks.rb +166 -0
  38. data/lib/schemurai/type_checks.rb +59 -0
  39. data/lib/schemurai/unique_items.rb +68 -0
  40. data/lib/schemurai/value_equality.rb +72 -0
  41. data/lib/schemurai/version.rb +6 -0
  42. data/lib/schemurai/vm/compiler.rb +410 -0
  43. data/lib/schemurai/vm/evaluator.rb +663 -0
  44. data/lib/schemurai/vm/limited_evaluator.rb +27 -0
  45. data/lib/schemurai.rb +307 -0
  46. data/lib/schemurai_native.rb +4 -0
  47. data/sig/schemurai.rbs +108 -0
  48. metadata +121 -0
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../evaluation"
4
+ require_relative "../error_message"
5
+
6
+ module Schemurai
7
+ module Internal
8
+ module ContainerChecks
9
+ module ObjectDiagnostics
10
+ MISSING_SEGMENT = Object.new.freeze
11
+
12
+ private def check_object(rules, value, prior_evaluation)
13
+ evaluation = nil
14
+ if rules.max_properties && value.length > rules.max_properties
15
+ return Evaluation.invalid unless collecting_object_errors?
16
+
17
+ object_error("maxProperties", rules, value)
18
+ end
19
+ if rules.min_properties && value.length < rules.min_properties
20
+ return Evaluation.invalid unless collecting_object_errors?
21
+
22
+ object_error("minProperties", rules, value)
23
+ end
24
+ if (required = rules.required)
25
+ required.each do |name|
26
+ object_budget&.checkpoint
27
+ next if value.key?(name)
28
+ return Evaluation.invalid unless collecting_object_errors?
29
+
30
+ object_error("required", rules, value, name)
31
+ end
32
+ end
33
+
34
+ properties = rules.properties
35
+ patterns = rules.patterns
36
+ value.each do |name, property_value|
37
+ object_budget&.checkpoint
38
+ matched = false
39
+ if (child = properties[name])
40
+ matched = true
41
+ valid = evaluate_child_at(child, property_value, name, "properties", name)
42
+ return Evaluation.invalid if !valid && !collecting_object_errors?
43
+ (evaluation ||= tracked_evaluation).record_property(name)
44
+ end
45
+ if patterns
46
+ patterns.each do |pattern, child|
47
+ object_budget&.checkpoint
48
+ next unless ecma_regexp(pattern).match?(name)
49
+ matched = true
50
+ valid = evaluate_child_at(child, property_value, name, "patternProperties", pattern)
51
+ return Evaluation.invalid if !valid && !collecting_object_errors?
52
+ (evaluation ||= tracked_evaluation).record_property(name)
53
+ end
54
+ end
55
+ if !matched && (additional = rules.additional)
56
+ valid = evaluate_child_at(additional, property_value, name, "additionalProperties")
57
+ return Evaluation.invalid if !valid && !collecting_object_errors?
58
+ (evaluation ||= tracked_evaluation).record_property(name)
59
+ end
60
+ end
61
+
62
+ if (property_names = rules.property_names)
63
+ value.each_key do |name|
64
+ object_budget&.checkpoint
65
+ valid = evaluate_child_at(property_names, name, name, "propertyNames")
66
+ return Evaluation.invalid if !valid && !collecting_object_errors?
67
+ end
68
+ end
69
+ if (dependencies = rules.dependencies)
70
+ dependencies.each do |name, dependency|
71
+ object_budget&.checkpoint
72
+ next unless value.key?(name)
73
+ if dependency.is_a?(Array)
74
+ dependency.each do |required_name|
75
+ object_budget&.checkpoint
76
+ unless value.key?(required_name)
77
+ return Evaluation.invalid unless collecting_object_errors?
78
+
79
+ object_error("dependencies", rules, value, name, required_name)
80
+ end
81
+ end
82
+ else
83
+ result = evaluate_at(dependency, value, MISSING_SEGMENT, "dependencies", name)
84
+ if result.valid? && !result.evaluated_properties.empty?
85
+ result.evaluated_properties.each do |property|
86
+ object_budget&.checkpoint
87
+ (evaluation ||= tracked_evaluation).record_property(property)
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ if (dependent_required = rules.dependent_required)
94
+ dependent_required.each do |name, required_names|
95
+ object_budget&.checkpoint
96
+ next unless value.key?(name)
97
+ required_names.each do |required_name|
98
+ object_budget&.checkpoint
99
+ unless value.key?(required_name)
100
+ return Evaluation.invalid unless collecting_object_errors?
101
+
102
+ object_error("dependentRequired", rules, value, name, required_name)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ if (dependent_schemas = rules.dependent_schemas)
108
+ dependent_schemas.each do |name, child|
109
+ object_budget&.checkpoint
110
+ next unless value.key?(name)
111
+ result = evaluate_at(child, value, MISSING_SEGMENT, "dependentSchemas", name)
112
+ if result.valid? && !result.evaluated_properties.empty?
113
+ result.evaluated_properties.each do |property|
114
+ object_budget&.checkpoint
115
+ (evaluation ||= tracked_evaluation).record_property(property)
116
+ end
117
+ end
118
+ end
119
+ end
120
+ if (unevaluated = rules.unevaluated)
121
+ prior_properties = prior_evaluation.evaluated_properties
122
+ value.each_key do |name|
123
+ object_budget&.checkpoint
124
+ next if prior_properties.include?(name) || evaluation&.evaluated_properties&.include?(name)
125
+
126
+ valid = evaluate_child_at(unevaluated, value[name], name, "unevaluatedProperties")
127
+ return Evaluation.invalid if !valid && !collecting_object_errors?
128
+ (evaluation ||= tracked_evaluation).record_property(name)
129
+ end
130
+ end
131
+ return Evaluation.valid unless evaluation
132
+
133
+ evaluation
134
+ end
135
+
136
+ private def object_budget = @budget
137
+ private def collecting_object_errors? = @errors
138
+
139
+ private def object_error(keyword, rules, value, name = nil, required_name = nil)
140
+ add_error(keyword) do
141
+ case keyword
142
+ when "maxProperties" then ErrorMessage.size(keyword, rules.max_properties, value.length)
143
+ when "minProperties" then ErrorMessage.size(keyword, rules.min_properties, value.length)
144
+ when "required" then ErrorMessage.required(name)
145
+ when "dependencies", "dependentRequired" then ErrorMessage.dependent_required(name, required_name)
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,534 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "string_checks"
4
+ require_relative "evaluation_pool"
5
+ require_relative "container_checks/array_diagnostics"
6
+ require_relative "container_checks/object_diagnostics"
7
+
8
+ require_relative "error_message"
9
+ require_relative "value_equality"
10
+
11
+ module Schemurai
12
+ module Internal
13
+ module ContainerChecks
14
+ module Properties
15
+ module_function def merge(left, left_keys, left_items, right, right_keys, right_items)
16
+ materialize(left, left_keys, left_items).merge(materialize(right, right_keys, right_items))
17
+ end
18
+
19
+ module_function def materialize(buffer, properties, items)
20
+ return buffer if buffer
21
+ return Evaluation.valid if properties.empty? && items.empty?
22
+
23
+ result = EvaluationBuffer.new
24
+ properties.each { |key| result.record_property(key) }
25
+ items.each { |index| result.record_item(index) }
26
+ result
27
+ end
28
+ private_class_method :materialize
29
+ end
30
+
31
+ module Bounds
32
+ private def valid_container_bounds?(length, maximum, minimum)
33
+ return false if maximum && length > maximum
34
+ return false if minimum && length < minimum
35
+
36
+ true
37
+ end
38
+ end
39
+
40
+ module Required
41
+ private def valid_required_keys?(required, value)
42
+ return true unless required
43
+
44
+ all_keys_present?(required, value)
45
+ end
46
+
47
+ private def all_keys_present?(names, value)
48
+ names.all? do |name|
49
+ @budget&.checkpoint
50
+ value.key?(name)
51
+ end
52
+ end
53
+
54
+ private def valid_dependency_keys?(entries, value)
55
+ return true unless entries
56
+
57
+ entries.each do |name, names|
58
+ @budget&.checkpoint
59
+ next unless value.key?(name)
60
+ return false unless all_keys_present?(names, value)
61
+ end
62
+ true
63
+ end
64
+ end
65
+
66
+ module Contains
67
+ private def valid_contains?(rules, value, &block)
68
+ if rules.count_contains
69
+ matches = value.count(&block)
70
+ return false if matches < rules.min_contains || matches > rules.max_contains
71
+ else
72
+ return false unless value.any?(&block)
73
+ end
74
+ true
75
+ end
76
+ end
77
+
78
+ module ArrayChildren
79
+ include Contains
80
+
81
+ private def valid_array_children?(rules, value, length)
82
+ if (prefix_items = rules.prefix_items)
83
+ prefix_items.each_with_index do |child, index|
84
+ @budget&.checkpoint
85
+ break if index >= length
86
+ return false unless yield(child, value[index])
87
+ end
88
+ end
89
+
90
+ items = rules.items
91
+ if rules.items_list
92
+ items.each_with_index do |child, index|
93
+ @budget&.checkpoint
94
+ break if index >= length
95
+ return false unless yield(child, value[index])
96
+ end
97
+ if length > items.length && (additional = rules.additional)
98
+ index = items.length
99
+ while index < length
100
+ @budget&.checkpoint
101
+ return false unless yield(additional, value[index])
102
+ index += 1
103
+ end
104
+ end
105
+ elsif items
106
+ start = rules.prefix_items&.length || 0
107
+ index = start
108
+ while index < length
109
+ @budget&.checkpoint
110
+ return false unless yield(items, value[index])
111
+ index += 1
112
+ end
113
+ end
114
+
115
+ if (contains = rules.contains)
116
+ return false unless valid_contains?(rules, value) { |item| yield(contains, item) }
117
+ end
118
+ true
119
+ end
120
+ end
121
+
122
+ module ObjectChildren
123
+ include Required
124
+
125
+ private def child_budget = @budget
126
+
127
+ private def valid_object_children?(rules, value)
128
+ properties = rules.properties
129
+ patterns = rules.patterns
130
+ additional = rules.additional
131
+ unless properties.empty? && patterns.nil? && additional.nil?
132
+ value.each do |name, property_value|
133
+ child_budget&.checkpoint
134
+ matched = false
135
+ if (child = properties[name])
136
+ matched = true
137
+ return false unless yield(child, property_value)
138
+ end
139
+ if patterns
140
+ patterns.each do |pattern, child|
141
+ child_budget&.checkpoint
142
+ next unless ecma_regexp(pattern).match?(name)
143
+ matched = true
144
+ return false unless yield(child, property_value)
145
+ end
146
+ end
147
+ return false if !matched && additional && !yield(additional, property_value)
148
+ end
149
+ end
150
+
151
+ if (property_names = rules.property_names)
152
+ value.each_key { |name| return false unless yield(property_names, name) }
153
+ end
154
+ if (dependencies = rules.dependencies)
155
+ dependencies.each do |name, dependency|
156
+ child_budget&.checkpoint
157
+ next unless value.key?(name)
158
+ if dependency.is_a?(Array)
159
+ return false unless all_keys_present?(dependency, value)
160
+ else
161
+ return false unless yield(dependency, value)
162
+ end
163
+ end
164
+ end
165
+ return false unless valid_dependency_keys?(rules.dependent_required, value)
166
+ if (dependent_schemas = rules.dependent_schemas)
167
+ dependent_schemas.each do |name, child|
168
+ child_budget&.checkpoint
169
+ next unless value.key?(name)
170
+ return false unless yield(child, value)
171
+ end
172
+ end
173
+ true
174
+ end
175
+ end
176
+
177
+ # Frames preserve Ruby container operations. Compiled child schema
178
+ # execution remains with the native traversal.
179
+ class Frame
180
+ include Bounds
181
+
182
+ def initialize(rules, value, budget, required)
183
+ @rules = rules
184
+ @value = value
185
+ @budget = budget
186
+ @required = required != 0
187
+ end
188
+
189
+ def valid?
190
+ return !@required unless container?
191
+
192
+ length = @value.length
193
+ return false unless valid_container_bounds?(length, maximum, minimum)
194
+
195
+ valid_tail?(length)
196
+ end
197
+
198
+ def check(step)
199
+ case step
200
+ when 2
201
+ violated = @value.length > maximum
202
+ violated ? false : true
203
+ when 3
204
+ violated = @value.length < minimum
205
+ violated ? false : true
206
+ when 4 then unique?
207
+ when 6
208
+ @value.each do |name, _value|
209
+ @budget&.checkpoint
210
+ @rules.properties[name]
211
+ end
212
+ true
213
+ when 5
214
+ # The VM evaluates this gate even when no additional schema exists.
215
+ _additional = @value.length > @rules.items.length
216
+ true
217
+ else raise "unknown container assertion"
218
+ end
219
+ end
220
+
221
+ def message(keyword, _rescued)
222
+ case keyword
223
+ when "type" then ErrorMessage.type(type_name, @value)
224
+ when "maxItems", "maxProperties" then ErrorMessage.size(keyword, maximum, @value.length)
225
+ when "minItems", "minProperties" then ErrorMessage.size(keyword, minimum, @value.length)
226
+ when "uniqueItems" then ErrorMessage.unique_items
227
+ else raise "unknown container diagnostic"
228
+ end
229
+ end
230
+
231
+ private def valid_tail?(_length) = true
232
+ end
233
+
234
+ class ArrayFrame < Frame
235
+ include ValueEquality
236
+ include UniqueItems
237
+
238
+ def container? = @value.is_a?(Array)
239
+
240
+ private def type_name = "array"
241
+ private def maximum = @rules.max_items
242
+ private def minimum = @rules.min_items
243
+ private def unique?
244
+ return true unless @rules.unique
245
+
246
+ unique_items?(@value)
247
+ end
248
+
249
+ private def valid_tail?(length)
250
+ return false unless unique?
251
+
252
+ length > @rules.items.length if @rules.items_list
253
+ true
254
+ end
255
+ end
256
+
257
+ class LimitedArrayFrame < ArrayFrame
258
+ include ValueEquality::Checkpoints
259
+ end
260
+
261
+ module ChildCallback
262
+ def initialize(rules, value, budget, required, callback)
263
+ super(rules, value, budget, required)
264
+ @callback = callback
265
+ end
266
+ end
267
+
268
+ class CallbackArrayFrame < ArrayFrame
269
+ include ChildCallback
270
+ end
271
+
272
+ class ContainsFrame < CallbackArrayFrame
273
+ include Contains
274
+
275
+ private def valid_tail?(length)
276
+ return false unless super
277
+
278
+ valid_contains?(@rules, @value) { |item| @callback.call(item) }
279
+ end
280
+ end
281
+
282
+ class LimitedContainsFrame < ContainsFrame
283
+ include ValueEquality::Checkpoints
284
+ end
285
+
286
+ class ArrayChildrenFrame < CallbackArrayFrame
287
+ include ArrayChildren
288
+
289
+ private def valid_tail?(length)
290
+ return false unless unique?
291
+
292
+ valid_array_children?(@rules, @value, length) { |child, item| @callback.evaluate_child(child, item) }
293
+ end
294
+ end
295
+
296
+ class LimitedArrayChildrenFrame < ArrayChildrenFrame
297
+ include ValueEquality::Checkpoints
298
+ end
299
+
300
+ class ArrayReportItems
301
+ def initialize(callback, prior)
302
+ @callback = callback
303
+ @prior = prior
304
+ end
305
+
306
+ def valid? = true
307
+ def evaluated_items = self
308
+ def include?(index) = @callback.include_item?(index, @prior)
309
+
310
+ def record_item(index)
311
+ @callback.record_item(index)
312
+ self
313
+ end
314
+ end
315
+
316
+ class ArrayReportFrame < ArrayFrame
317
+ include ArrayDiagnostics
318
+ include ChildCallback
319
+
320
+ def collect
321
+ @failed = false
322
+ unless container?
323
+ if @required && collecting_array_errors?
324
+ @callback.error("type", self)
325
+ end
326
+ return @callback.finish(!@required, nil)
327
+ end
328
+ result = check_array(@rules, @value, ArrayReportItems.new(@callback, true))
329
+ @callback.finish(result.valid? && !@failed, @evaluation)
330
+ end
331
+
332
+ def message(keyword, rescued)
333
+ return ErrorMessage.contains(@matched_count, @rules.min_contains, @rules.max_contains) if keyword == "contains"
334
+
335
+ super
336
+ end
337
+
338
+ private def collecting_array_errors? = !@callback.silent?
339
+
340
+ private def array_error(keyword, _rules, _value, actual = nil)
341
+ @failed = true
342
+ @matched_count = actual
343
+ @callback.error(keyword, self)
344
+ end
345
+
346
+ private def tracked_evaluation = (@evaluation ||= @callback.evaluation_buffer)
347
+
348
+ private def evaluate_child_at(program, instance, index, keyword, child_segment = nil)
349
+ valid = @callback.evaluate(program, instance, index, keyword, child_segment)
350
+ @failed = true unless valid
351
+ valid
352
+ end
353
+
354
+ private def trial(program, instance)
355
+ @callback.trial(program, instance) ? Evaluation.valid : Evaluation.invalid
356
+ end
357
+ end
358
+
359
+ class LimitedArrayReportFrame < ArrayReportFrame
360
+ include ValueEquality::Checkpoints
361
+ end
362
+
363
+ class ObjectFrame < Frame
364
+ include Required
365
+
366
+ def container? = @value.is_a?(Hash)
367
+
368
+ def check(step)
369
+ return super if step < 7
370
+
371
+ if step == 7
372
+ return true unless @rules.required
373
+
374
+ # Preserve errors from malformed required operands before iteration.
375
+ @rules.required.each { break }
376
+ return true
377
+ end
378
+ index = step - 8
379
+ count = iteration_length(@rules.required)
380
+ if index < count
381
+ return check_required_name(iteration_name(@rules.required, index))
382
+ end
383
+ check_dependency(index - count)
384
+ end
385
+
386
+ def message(keyword, rescued)
387
+ return ErrorMessage.required(@required_name) if keyword == "required"
388
+ if keyword == "dependencies" || keyword == "dependentRequired"
389
+ return ErrorMessage.dependent_required(@dependency_name, @required_name)
390
+ end
391
+
392
+ super
393
+ end
394
+
395
+ private def type_name = "object"
396
+ private def maximum = @rules.max_properties
397
+ private def minimum = @rules.min_properties
398
+ private def valid_tail?(_length)
399
+ valid_required_keys?(@rules.required, @value) &&
400
+ valid_dependency_keys?(@rules.dependencies, @value) &&
401
+ valid_dependency_keys?(@rules.dependent_required, @value)
402
+ end
403
+
404
+ private def iteration_length(names)
405
+ (Array === names || Hash === names) ? names.length : 0
406
+ end
407
+
408
+ private def iteration_name(names, at)
409
+ return names[at] if Array === names
410
+
411
+ names.each_with_index { |name, index| return name if index == at }
412
+ end
413
+
414
+ private def dependency_steps
415
+ @dependency_steps ||= [@rules.dependencies, @rules.dependent_required].flat_map do |entries|
416
+ (entries || []).flat_map do |name, names|
417
+ [[:trigger, name], [:prepare, names]] + Array.new(iteration_length(names)) { |index| [:key, names, index] }
418
+ end
419
+ end
420
+ end
421
+
422
+ private def check_dependency(index)
423
+ kind, operand, at = dependency_steps.fetch(index)
424
+ case kind
425
+ when :trigger
426
+ @dependency_name = operand
427
+ @budget&.checkpoint
428
+ @value.key?(operand) || false
429
+ when :prepare
430
+ operand.each { break }
431
+ true
432
+ when :key then check_required_name(iteration_name(operand, at))
433
+ end
434
+ end
435
+ private def check_required_name(name)
436
+ @required_name = name
437
+ @budget&.checkpoint
438
+ @value.key?(name) || false
439
+ end
440
+ end
441
+
442
+ class ObjectReportLocations
443
+ def initialize(properties = Set.new)
444
+ @properties = properties
445
+ end
446
+
447
+ def valid? = true
448
+ def evaluated_properties = @properties
449
+
450
+ def record_property(name)
451
+ @properties.add(name)
452
+ self
453
+ end
454
+ end
455
+
456
+ class ObjectReportPrior
457
+ def initialize(callback)
458
+ @callback = callback
459
+ end
460
+
461
+ def evaluated_properties = @callback.properties(true)
462
+ end
463
+
464
+ class ObjectReportFrame < ObjectFrame
465
+ include ObjectDiagnostics
466
+ include ChildCallback
467
+ include StringChecks::Regexps
468
+
469
+ def collect
470
+ @failed = false
471
+ unless container?
472
+ @callback.object_error("type", self) if @required && collecting_object_errors?
473
+ return @callback.finish_object(!@required, nil)
474
+ end
475
+ result = check_object(@rules, @value, ObjectReportPrior.new(@callback))
476
+ @callback.finish_object(result.valid? && !@failed, @evaluation)
477
+ end
478
+
479
+ private def collecting_object_errors? = !@callback.silent?
480
+ private def object_budget = @callback.invocation_budget
481
+ private def regexp_cache = (@regexps ||= @callback.regexp_cache)
482
+ private def tracked_evaluation = (@evaluation ||= @callback.evaluation_buffer)
483
+
484
+ private def object_error(keyword, _rules, _value, name = nil, required_name = nil)
485
+ @failed = true
486
+ @dependency_name = name
487
+ @required_name = (keyword == "required") ? name : required_name
488
+ @callback.object_error(keyword, self)
489
+ end
490
+
491
+ private def evaluate_child_at(program, instance, segment, keyword, child = ObjectDiagnostics::MISSING_SEGMENT)
492
+ flags = child.equal?(ObjectDiagnostics::MISSING_SEGMENT) ? 0 : 2
493
+ valid = @callback.evaluate_object(program, instance, segment, keyword, child, flags, false)
494
+ @failed = true unless valid
495
+ valid
496
+ end
497
+
498
+ private def evaluate_at(program, instance, segment, keyword, child)
499
+ flags = segment.equal?(ObjectDiagnostics::MISSING_SEGMENT) ? 3 : 2
500
+ valid, properties = @callback.evaluate_object(program, instance, segment, keyword, child, flags, true)
501
+ @failed = true unless valid
502
+ valid ? ObjectReportLocations.new(properties) : Evaluation.invalid
503
+ end
504
+ end
505
+
506
+ class LimitedObjectReportFrame < ObjectReportFrame
507
+ include StringChecks::TimedRegexps
508
+
509
+ private def regexp_budget = object_budget
510
+ end
511
+
512
+ class ObjectChildrenFrame < ObjectFrame
513
+ include ChildCallback
514
+ include ObjectChildren
515
+ include StringChecks::Regexps
516
+
517
+ private def child_budget = @callback.invocation_budget
518
+ private def regexp_cache = (@regexps ||= @callback.regexp_cache)
519
+
520
+ private def valid_tail?(_length)
521
+ return false unless valid_required_keys?(@rules.required, @value)
522
+
523
+ valid_object_children?(@rules, @value) { |child, item| @callback.evaluate_child(child, item) }
524
+ end
525
+ end
526
+
527
+ class LimitedObjectChildrenFrame < ObjectChildrenFrame
528
+ include StringChecks::TimedRegexps
529
+
530
+ private def regexp_budget = child_budget
531
+ end
532
+ end
533
+ end
534
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schemurai
4
+ module Internal
5
+ module Decimal
6
+ module_function def parse(value)
7
+ Rational(value.to_s)
8
+ end
9
+ end
10
+ end
11
+ end