jsonschema_rs 0.48.2 → 0.49.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.
data/src/canonical.rs CHANGED
@@ -1,5 +1,7 @@
1
1
  use jsonschema::{
2
- canonical::{CanonicalSchema, CanonicalView, CanonicalizationError},
2
+ canonical::{
3
+ CanonicalSchema, CanonicalView, CanonicalizationError, ContainsView as CoreContainsView,
4
+ },
3
5
  JsonType,
4
6
  };
5
7
  use magnus::{
@@ -91,13 +93,13 @@ impl RbCanonicalSchema {
91
93
  rb_self.inner.is_satisfiable()
92
94
  }
93
95
 
94
- fn inspect(rb_self: &Self) -> String {
96
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> String {
95
97
  // Bounded: `inspect` runs implicitly (IRB, error messages) and a full
96
98
  // `to_json_schema` re-emits the whole document.
97
99
  format!(
98
- "#<JSONSchema::Canonical::CanonicalSchema kind={} draft={:?}>",
99
- rb_self.inner.kind().as_str(),
100
- rb_self.inner.draft()
100
+ "#<JSONSchema::Canonical::CanonicalSchema kind={} draft={}>",
101
+ Self::kind(ruby, rb_self).inspect(),
102
+ Self::draft(ruby, rb_self).inspect()
101
103
  )
102
104
  }
103
105
 
@@ -125,9 +127,55 @@ impl RbCanonicalSchema {
125
127
  CanonicalView::Enum(values) => ruby.obj_wrap(EnumView { values }).as_value(),
126
128
  CanonicalView::True => ruby.obj_wrap(TrueView).as_value(),
127
129
  CanonicalView::False => ruby.obj_wrap(FalseView).as_value(),
130
+ CanonicalView::String(view) => ruby
131
+ .obj_wrap(StringView {
132
+ min_length: view.min_length,
133
+ max_length: view.max_length,
134
+ patterns: view.patterns,
135
+ formats: view.formats,
136
+ content_media_types: view.content_media_types,
137
+ content_encodings: view.content_encodings,
138
+ })
139
+ .as_value(),
140
+ CanonicalView::Number(view) => ruby
141
+ .obj_wrap(NumberView {
142
+ minimum: view.minimum,
143
+ exclusive_minimum: view.exclusive_minimum,
144
+ maximum: view.maximum,
145
+ exclusive_maximum: view.exclusive_maximum,
146
+ multiple_of: view.multiple_of,
147
+ })
148
+ .as_value(),
149
+ CanonicalView::Integer(view) => ruby
150
+ .obj_wrap(IntegerView {
151
+ minimum: view.minimum,
152
+ maximum: view.maximum,
153
+ multiple_of: view.multiple_of,
154
+ })
155
+ .as_value(),
156
+ CanonicalView::Array(view) => ruby
157
+ .obj_wrap(ArrayView {
158
+ min_items: view.min_items,
159
+ max_items: view.max_items,
160
+ unique_items: view.unique_items,
161
+ prefix_items: view.prefix_items,
162
+ items: view.items,
163
+ contains: view.contains,
164
+ })
165
+ .as_value(),
166
+ CanonicalView::Object(view) => ruby
167
+ .obj_wrap(ObjectView {
168
+ min_properties: view.min_properties,
169
+ max_properties: view.max_properties,
170
+ required: view.required,
171
+ property_names: view.property_names,
172
+ properties: view.properties,
173
+ pattern_properties: view.pattern_properties,
174
+ additional_properties: view.additional_properties,
175
+ })
176
+ .as_value(),
177
+ CanonicalView::AnyOf(branches) => ruby.obj_wrap(AnyOfView { branches }).as_value(),
128
178
  CanonicalView::Raw(schema) => ruby.obj_wrap(RawView { schema }).as_value(),
129
- // TODO(canonical): new `CanonicalView` variants need view classes here.
130
- other => unreachable!("unsupported canonical view: {other:?}"),
131
179
  }
132
180
  }
133
181
 
@@ -155,11 +203,11 @@ impl RawView {
155
203
  value_to_ruby(ruby, &rb_self.schema)
156
204
  }
157
205
 
158
- fn inspect(rb_self: &Self) -> String {
159
- format!(
206
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
207
+ Ok(format!(
160
208
  "#<JSONSchema::Canonical::RawView schema={}>",
161
- rb_self.schema
162
- )
209
+ Self::schema(ruby, rb_self)?.inspect()
210
+ ))
163
211
  }
164
212
 
165
213
  fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
@@ -177,6 +225,12 @@ impl RawView {
177
225
  #[magnus(class = "JSONSchema::Canonical::TrueView", free_immediately)]
178
226
  pub struct TrueView;
179
227
 
228
+ impl TrueView {
229
+ fn inspect(_rb_self: &Self) -> String {
230
+ "#<JSONSchema::Canonical::TrueView>".to_string()
231
+ }
232
+ }
233
+
180
234
  impl DataTypeFunctions for TrueView {}
181
235
 
182
236
  /// Matches no value.
@@ -184,6 +238,12 @@ impl DataTypeFunctions for TrueView {}
184
238
  #[magnus(class = "JSONSchema::Canonical::FalseView", free_immediately)]
185
239
  pub struct FalseView;
186
240
 
241
+ impl FalseView {
242
+ fn inspect(_rb_self: &Self) -> String {
243
+ "#<JSONSchema::Canonical::FalseView>".to_string()
244
+ }
245
+ }
246
+
187
247
  impl DataTypeFunctions for FalseView {}
188
248
 
189
249
  /// A value matches iff its JSON type is in `types`.
@@ -204,11 +264,11 @@ impl MultiTypeView {
204
264
  Ok(array.as_value())
205
265
  }
206
266
 
207
- fn inspect(rb_self: &Self) -> String {
208
- format!(
209
- "#<JSONSchema::Canonical::MultiTypeView types={:?}>",
210
- rb_self.types
211
- )
267
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
268
+ Ok(format!(
269
+ "#<JSONSchema::Canonical::MultiTypeView types={}>",
270
+ Self::types(ruby, rb_self)?.inspect()
271
+ ))
212
272
  }
213
273
 
214
274
  fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
@@ -240,10 +300,10 @@ impl TypedGroupView {
240
300
  .as_value()
241
301
  }
242
302
 
243
- fn inspect(rb_self: &Self) -> String {
303
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> String {
244
304
  format!(
245
- "#<JSONSchema::Canonical::TypedGroupView type_name={:?}>",
246
- rb_self.type_name
305
+ "#<JSONSchema::Canonical::TypedGroupView type_name={}>",
306
+ Self::type_name(ruby, rb_self).inspect()
247
307
  )
248
308
  }
249
309
 
@@ -255,6 +315,519 @@ impl TypedGroupView {
255
315
  }
256
316
  }
257
317
 
318
+ /// An absent bound is `nil`; a present one keeps its exact value.
319
+ fn bound_to_ruby(ruby: &Ruby, bound: Option<&serde_json::Number>) -> Result<Value, Error> {
320
+ match bound {
321
+ Some(number) => value_to_ruby(ruby, &serde_json::Value::Number(number.clone())),
322
+ None => Ok(ruby.qnil().as_value()),
323
+ }
324
+ }
325
+
326
+ fn divisors_to_ruby(ruby: &Ruby, divisors: &[serde_json::Number]) -> Result<Value, Error> {
327
+ let array = ruby.ary_new_capa(divisors.len());
328
+ for divisor in divisors {
329
+ array.push(value_to_ruby(
330
+ ruby,
331
+ &serde_json::Value::Number(divisor.clone()),
332
+ )?)?;
333
+ }
334
+ Ok(array.as_value())
335
+ }
336
+
337
+ fn strings_to_ruby(ruby: &Ruby, values: &[String]) -> Result<Value, Error> {
338
+ let array = ruby.ary_new_capa(values.len());
339
+ for value in values {
340
+ array.push(ruby.str_new(value).as_value())?;
341
+ }
342
+ Ok(array.as_value())
343
+ }
344
+
345
+ /// A string value within a length window, matching every pattern, format, media type, and
346
+ /// encoding.
347
+ #[derive(magnus::TypedData)]
348
+ #[magnus(class = "JSONSchema::Canonical::StringView", free_immediately)]
349
+ pub struct StringView {
350
+ min_length: Option<serde_json::Number>,
351
+ max_length: Option<serde_json::Number>,
352
+ patterns: Vec<String>,
353
+ formats: Vec<String>,
354
+ content_media_types: Vec<String>,
355
+ content_encodings: Vec<String>,
356
+ }
357
+
358
+ impl DataTypeFunctions for StringView {}
359
+
360
+ impl StringView {
361
+ fn min_length(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
362
+ bound_to_ruby(ruby, rb_self.min_length.as_ref())
363
+ }
364
+
365
+ fn max_length(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
366
+ bound_to_ruby(ruby, rb_self.max_length.as_ref())
367
+ }
368
+
369
+ fn patterns(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
370
+ strings_to_ruby(ruby, &rb_self.patterns)
371
+ }
372
+
373
+ fn formats(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
374
+ strings_to_ruby(ruby, &rb_self.formats)
375
+ }
376
+
377
+ fn content_media_types(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
378
+ strings_to_ruby(ruby, &rb_self.content_media_types)
379
+ }
380
+
381
+ fn content_encodings(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
382
+ strings_to_ruby(ruby, &rb_self.content_encodings)
383
+ }
384
+
385
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
386
+ Ok(format!(
387
+ "#<JSONSchema::Canonical::StringView min_length={} max_length={} patterns={} formats={} content_media_types={} content_encodings={}>",
388
+ Self::min_length(ruby, rb_self)?.inspect(),
389
+ Self::max_length(ruby, rb_self)?.inspect(),
390
+ Self::patterns(ruby, rb_self)?.inspect(),
391
+ Self::formats(ruby, rb_self)?.inspect(),
392
+ Self::content_media_types(ruby, rb_self)?.inspect(),
393
+ Self::content_encodings(ruby, rb_self)?.inspect()
394
+ ))
395
+ }
396
+
397
+ fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
398
+ let hash = ruby.hash_new();
399
+ hash.aset(ruby.sym_new("min_length"), Self::min_length(ruby, rb_self)?)?;
400
+ hash.aset(ruby.sym_new("max_length"), Self::max_length(ruby, rb_self)?)?;
401
+ hash.aset(ruby.sym_new("patterns"), Self::patterns(ruby, rb_self)?)?;
402
+ hash.aset(ruby.sym_new("formats"), Self::formats(ruby, rb_self)?)?;
403
+ hash.aset(
404
+ ruby.sym_new("content_media_types"),
405
+ Self::content_media_types(ruby, rb_self)?,
406
+ )?;
407
+ hash.aset(
408
+ ruby.sym_new("content_encodings"),
409
+ Self::content_encodings(ruby, rb_self)?,
410
+ )?;
411
+ Ok(hash)
412
+ }
413
+ }
414
+
415
+ /// A number value within a real interval.
416
+ #[derive(magnus::TypedData)]
417
+ #[magnus(class = "JSONSchema::Canonical::NumberView", free_immediately)]
418
+ pub struct NumberView {
419
+ minimum: Option<serde_json::Number>,
420
+ exclusive_minimum: bool,
421
+ maximum: Option<serde_json::Number>,
422
+ exclusive_maximum: bool,
423
+ multiple_of: Vec<serde_json::Number>,
424
+ }
425
+
426
+ impl DataTypeFunctions for NumberView {}
427
+
428
+ impl NumberView {
429
+ fn minimum(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
430
+ bound_to_ruby(ruby, rb_self.minimum.as_ref())
431
+ }
432
+
433
+ fn exclusive_minimum(ruby: &Ruby, rb_self: &Self) -> Value {
434
+ ruby.into_value(rb_self.exclusive_minimum)
435
+ }
436
+
437
+ fn maximum(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
438
+ bound_to_ruby(ruby, rb_self.maximum.as_ref())
439
+ }
440
+
441
+ fn exclusive_maximum(ruby: &Ruby, rb_self: &Self) -> Value {
442
+ ruby.into_value(rb_self.exclusive_maximum)
443
+ }
444
+
445
+ fn multiple_of(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
446
+ divisors_to_ruby(ruby, &rb_self.multiple_of)
447
+ }
448
+
449
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
450
+ Ok(format!(
451
+ "#<JSONSchema::Canonical::NumberView minimum={} exclusive_minimum={} maximum={} exclusive_maximum={} multiple_of={}>",
452
+ Self::minimum(ruby, rb_self)?.inspect(),
453
+ Self::exclusive_minimum(ruby, rb_self).inspect(),
454
+ Self::maximum(ruby, rb_self)?.inspect(),
455
+ Self::exclusive_maximum(ruby, rb_self).inspect(),
456
+ Self::multiple_of(ruby, rb_self)?.inspect()
457
+ ))
458
+ }
459
+
460
+ fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
461
+ let hash = ruby.hash_new();
462
+ hash.aset(ruby.sym_new("minimum"), Self::minimum(ruby, rb_self)?)?;
463
+ hash.aset(
464
+ ruby.sym_new("exclusive_minimum"),
465
+ Self::exclusive_minimum(ruby, rb_self),
466
+ )?;
467
+ hash.aset(ruby.sym_new("maximum"), Self::maximum(ruby, rb_self)?)?;
468
+ hash.aset(
469
+ ruby.sym_new("exclusive_maximum"),
470
+ Self::exclusive_maximum(ruby, rb_self),
471
+ )?;
472
+ hash.aset(
473
+ ruby.sym_new("multiple_of"),
474
+ Self::multiple_of(ruby, rb_self)?,
475
+ )?;
476
+ Ok(hash)
477
+ }
478
+ }
479
+
480
+ /// An integer value within a closed interval, optionally a multiple of a divisor.
481
+ #[derive(magnus::TypedData)]
482
+ #[magnus(class = "JSONSchema::Canonical::IntegerView", free_immediately)]
483
+ pub struct IntegerView {
484
+ minimum: Option<serde_json::Number>,
485
+ maximum: Option<serde_json::Number>,
486
+ multiple_of: Vec<serde_json::Number>,
487
+ }
488
+
489
+ impl DataTypeFunctions for IntegerView {}
490
+
491
+ impl IntegerView {
492
+ fn minimum(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
493
+ bound_to_ruby(ruby, rb_self.minimum.as_ref())
494
+ }
495
+
496
+ fn maximum(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
497
+ bound_to_ruby(ruby, rb_self.maximum.as_ref())
498
+ }
499
+
500
+ fn multiple_of(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
501
+ divisors_to_ruby(ruby, &rb_self.multiple_of)
502
+ }
503
+
504
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
505
+ Ok(format!(
506
+ "#<JSONSchema::Canonical::IntegerView minimum={} maximum={} multiple_of={}>",
507
+ Self::minimum(ruby, rb_self)?.inspect(),
508
+ Self::maximum(ruby, rb_self)?.inspect(),
509
+ Self::multiple_of(ruby, rb_self)?.inspect()
510
+ ))
511
+ }
512
+
513
+ fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
514
+ let hash = ruby.hash_new();
515
+ hash.aset(ruby.sym_new("minimum"), Self::minimum(ruby, rb_self)?)?;
516
+ hash.aset(ruby.sym_new("maximum"), Self::maximum(ruby, rb_self)?)?;
517
+ hash.aset(
518
+ ruby.sym_new("multiple_of"),
519
+ Self::multiple_of(ruby, rb_self)?,
520
+ )?;
521
+ Ok(hash)
522
+ }
523
+ }
524
+
525
+ /// An array value's constraints.
526
+ #[derive(magnus::TypedData)]
527
+ #[magnus(class = "JSONSchema::Canonical::ArrayView", free_immediately)]
528
+ #[allow(clippy::struct_field_names)]
529
+ pub struct ArrayView {
530
+ min_items: Option<serde_json::Number>,
531
+ max_items: Option<serde_json::Number>,
532
+ unique_items: bool,
533
+ prefix_items: Vec<CanonicalSchema>,
534
+ items: Option<CanonicalSchema>,
535
+ contains: Vec<CoreContainsView>,
536
+ }
537
+
538
+ impl DataTypeFunctions for ArrayView {}
539
+
540
+ impl ArrayView {
541
+ fn min_items(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
542
+ bound_to_ruby(ruby, rb_self.min_items.as_ref())
543
+ }
544
+
545
+ fn max_items(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
546
+ bound_to_ruby(ruby, rb_self.max_items.as_ref())
547
+ }
548
+
549
+ fn unique_items(ruby: &Ruby, rb_self: &Self) -> Value {
550
+ ruby.into_value(rb_self.unique_items)
551
+ }
552
+
553
+ fn prefix_items(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
554
+ let array = ruby.ary_new_capa(rb_self.prefix_items.len());
555
+ for schema in &rb_self.prefix_items {
556
+ array.push(
557
+ ruby.obj_wrap(RbCanonicalSchema {
558
+ inner: schema.clone(),
559
+ })
560
+ .as_value(),
561
+ )?;
562
+ }
563
+ Ok(array.as_value())
564
+ }
565
+
566
+ fn items(ruby: &Ruby, rb_self: &Self) -> Value {
567
+ match &rb_self.items {
568
+ Some(items) => ruby
569
+ .obj_wrap(RbCanonicalSchema {
570
+ inner: items.clone(),
571
+ })
572
+ .as_value(),
573
+ None => ruby.qnil().as_value(),
574
+ }
575
+ }
576
+
577
+ fn contains(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
578
+ let array = ruby.ary_new_capa(rb_self.contains.len());
579
+ for facet in &rb_self.contains {
580
+ array.push(ruby.obj_wrap(ContainsView::from_core(facet)).as_value())?;
581
+ }
582
+ Ok(array.as_value())
583
+ }
584
+
585
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
586
+ Ok(format!(
587
+ "#<JSONSchema::Canonical::ArrayView min_items={} max_items={} unique_items={} prefix_items={} items={} contains={}>",
588
+ Self::min_items(ruby, rb_self)?.inspect(),
589
+ Self::max_items(ruby, rb_self)?.inspect(),
590
+ Self::unique_items(ruby, rb_self).inspect(),
591
+ Self::prefix_items(ruby, rb_self)?.inspect(),
592
+ Self::items(ruby, rb_self).inspect(),
593
+ Self::contains(ruby, rb_self)?.inspect()
594
+ ))
595
+ }
596
+
597
+ fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
598
+ let hash = ruby.hash_new();
599
+ hash.aset(ruby.sym_new("min_items"), Self::min_items(ruby, rb_self)?)?;
600
+ hash.aset(ruby.sym_new("max_items"), Self::max_items(ruby, rb_self)?)?;
601
+ hash.aset(
602
+ ruby.sym_new("unique_items"),
603
+ Self::unique_items(ruby, rb_self),
604
+ )?;
605
+ hash.aset(
606
+ ruby.sym_new("prefix_items"),
607
+ Self::prefix_items(ruby, rb_self)?,
608
+ )?;
609
+ hash.aset(ruby.sym_new("items"), Self::items(ruby, rb_self))?;
610
+ hash.aset(ruby.sym_new("contains"), Self::contains(ruby, rb_self)?)?;
611
+ Ok(hash)
612
+ }
613
+ }
614
+
615
+ /// One `contains` demand of an array. An absent minimum spells the default of one.
616
+ #[derive(magnus::TypedData)]
617
+ #[magnus(class = "JSONSchema::Canonical::ContainsView", free_immediately)]
618
+ pub struct ContainsView {
619
+ schema: CanonicalSchema,
620
+ min_contains: Option<serde_json::Number>,
621
+ max_contains: Option<serde_json::Number>,
622
+ }
623
+
624
+ impl DataTypeFunctions for ContainsView {}
625
+
626
+ impl ContainsView {
627
+ fn from_core(facet: &CoreContainsView) -> Self {
628
+ Self {
629
+ schema: facet.schema.clone(),
630
+ min_contains: facet.min_contains.clone(),
631
+ max_contains: facet.max_contains.clone(),
632
+ }
633
+ }
634
+
635
+ fn schema(ruby: &Ruby, rb_self: &Self) -> Value {
636
+ ruby.obj_wrap(RbCanonicalSchema {
637
+ inner: rb_self.schema.clone(),
638
+ })
639
+ .as_value()
640
+ }
641
+
642
+ fn min_contains(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
643
+ bound_to_ruby(ruby, rb_self.min_contains.as_ref())
644
+ }
645
+
646
+ fn max_contains(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
647
+ bound_to_ruby(ruby, rb_self.max_contains.as_ref())
648
+ }
649
+
650
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
651
+ Ok(format!(
652
+ "#<JSONSchema::Canonical::ContainsView schema={} min_contains={} max_contains={}>",
653
+ Self::schema(ruby, rb_self).inspect(),
654
+ Self::min_contains(ruby, rb_self)?.inspect(),
655
+ Self::max_contains(ruby, rb_self)?.inspect()
656
+ ))
657
+ }
658
+
659
+ fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
660
+ let hash = ruby.hash_new();
661
+ hash.aset(ruby.sym_new("schema"), Self::schema(ruby, rb_self))?;
662
+ hash.aset(
663
+ ruby.sym_new("min_contains"),
664
+ Self::min_contains(ruby, rb_self)?,
665
+ )?;
666
+ hash.aset(
667
+ ruby.sym_new("max_contains"),
668
+ Self::max_contains(ruby, rb_self)?,
669
+ )?;
670
+ Ok(hash)
671
+ }
672
+ }
673
+
674
+ /// An object value's constraints.
675
+ #[derive(magnus::TypedData)]
676
+ #[magnus(class = "JSONSchema::Canonical::ObjectView", free_immediately)]
677
+ pub struct ObjectView {
678
+ min_properties: Option<serde_json::Number>,
679
+ max_properties: Option<serde_json::Number>,
680
+ required: Vec<String>,
681
+ property_names: Option<CanonicalSchema>,
682
+ properties: std::collections::BTreeMap<String, CanonicalSchema>,
683
+ pattern_properties: std::collections::BTreeMap<String, CanonicalSchema>,
684
+ additional_properties: Option<CanonicalSchema>,
685
+ }
686
+
687
+ impl DataTypeFunctions for ObjectView {}
688
+
689
+ impl ObjectView {
690
+ fn min_properties(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
691
+ bound_to_ruby(ruby, rb_self.min_properties.as_ref())
692
+ }
693
+
694
+ fn max_properties(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
695
+ bound_to_ruby(ruby, rb_self.max_properties.as_ref())
696
+ }
697
+
698
+ fn required(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
699
+ let array = ruby.ary_new_capa(rb_self.required.len());
700
+ for key in &rb_self.required {
701
+ array.push(ruby.str_new(key))?;
702
+ }
703
+ Ok(array.as_value())
704
+ }
705
+
706
+ fn property_names(ruby: &Ruby, rb_self: &Self) -> Value {
707
+ match &rb_self.property_names {
708
+ Some(names) => ruby
709
+ .obj_wrap(RbCanonicalSchema {
710
+ inner: names.clone(),
711
+ })
712
+ .as_value(),
713
+ None => ruby.qnil().as_value(),
714
+ }
715
+ }
716
+
717
+ fn properties(ruby: &Ruby, rb_self: &Self) -> Result<RHash, Error> {
718
+ let hash = ruby.hash_new();
719
+ for (key, schema) in &rb_self.properties {
720
+ let wrapped = ruby.obj_wrap(RbCanonicalSchema {
721
+ inner: schema.clone(),
722
+ });
723
+ hash.aset(key.as_str(), wrapped)?;
724
+ }
725
+ Ok(hash)
726
+ }
727
+
728
+ fn pattern_properties(ruby: &Ruby, rb_self: &Self) -> Result<RHash, Error> {
729
+ let hash = ruby.hash_new();
730
+ for (pattern, schema) in &rb_self.pattern_properties {
731
+ let wrapped = ruby.obj_wrap(RbCanonicalSchema {
732
+ inner: schema.clone(),
733
+ });
734
+ hash.aset(pattern.as_str(), wrapped)?;
735
+ }
736
+ Ok(hash)
737
+ }
738
+
739
+ fn additional_properties(ruby: &Ruby, rb_self: &Self) -> Value {
740
+ match &rb_self.additional_properties {
741
+ Some(shield) => ruby
742
+ .obj_wrap(RbCanonicalSchema {
743
+ inner: shield.clone(),
744
+ })
745
+ .as_value(),
746
+ None => ruby.qnil().as_value(),
747
+ }
748
+ }
749
+
750
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
751
+ Ok(format!(
752
+ "#<JSONSchema::Canonical::ObjectView min_properties={} max_properties={} required={} property_names={} properties={} pattern_properties={}>",
753
+ Self::min_properties(ruby, rb_self)?.inspect(),
754
+ Self::max_properties(ruby, rb_self)?.inspect(),
755
+ Self::required(ruby, rb_self)?.inspect(),
756
+ Self::property_names(ruby, rb_self).inspect(),
757
+ Self::properties(ruby, rb_self)?.inspect(),
758
+ Self::pattern_properties(ruby, rb_self)?.inspect()
759
+ ))
760
+ }
761
+
762
+ fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
763
+ let hash = ruby.hash_new();
764
+ hash.aset(
765
+ ruby.sym_new("min_properties"),
766
+ Self::min_properties(ruby, rb_self)?,
767
+ )?;
768
+ hash.aset(
769
+ ruby.sym_new("max_properties"),
770
+ Self::max_properties(ruby, rb_self)?,
771
+ )?;
772
+ hash.aset(ruby.sym_new("required"), Self::required(ruby, rb_self)?)?;
773
+ hash.aset(
774
+ ruby.sym_new("property_names"),
775
+ Self::property_names(ruby, rb_self),
776
+ )?;
777
+ hash.aset(ruby.sym_new("properties"), Self::properties(ruby, rb_self)?)?;
778
+ hash.aset(
779
+ ruby.sym_new("pattern_properties"),
780
+ Self::pattern_properties(ruby, rb_self)?,
781
+ )?;
782
+ hash.aset(
783
+ ruby.sym_new("additional_properties"),
784
+ Self::additional_properties(ruby, rb_self),
785
+ )?;
786
+ Ok(hash)
787
+ }
788
+ }
789
+
790
+ /// A value matches iff at least one branch matches.
791
+ #[derive(magnus::TypedData)]
792
+ #[magnus(class = "JSONSchema::Canonical::AnyOfView", free_immediately)]
793
+ pub struct AnyOfView {
794
+ branches: Vec<CanonicalSchema>,
795
+ }
796
+
797
+ impl DataTypeFunctions for AnyOfView {}
798
+
799
+ impl AnyOfView {
800
+ fn branches(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
801
+ let array = ruby.ary_new_capa(rb_self.branches.len());
802
+ for branch in &rb_self.branches {
803
+ array.push(
804
+ ruby.obj_wrap(RbCanonicalSchema {
805
+ inner: branch.clone(),
806
+ })
807
+ .as_value(),
808
+ )?;
809
+ }
810
+ Ok(array.as_value())
811
+ }
812
+
813
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
814
+ let kinds = ruby.ary_new_capa(rb_self.branches.len());
815
+ for branch in &rb_self.branches {
816
+ kinds.push(ruby.sym_new(branch.kind().as_str()).as_value())?;
817
+ }
818
+ Ok(format!(
819
+ "#<JSONSchema::Canonical::AnyOfView branches={}>",
820
+ kinds.as_value().inspect()
821
+ ))
822
+ }
823
+
824
+ fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
825
+ let hash = ruby.hash_new();
826
+ hash.aset(ruby.sym_new("branches"), Self::branches(ruby, rb_self)?)?;
827
+ Ok(hash)
828
+ }
829
+ }
830
+
258
831
  /// Exactly one admitted value.
259
832
  #[derive(magnus::TypedData)]
260
833
  #[magnus(class = "JSONSchema::Canonical::ConstView", free_immediately)]
@@ -269,11 +842,11 @@ impl ConstView {
269
842
  value_to_ruby(ruby, &rb_self.value)
270
843
  }
271
844
 
272
- fn inspect(rb_self: &Self) -> String {
273
- format!(
845
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
846
+ Ok(format!(
274
847
  "#<JSONSchema::Canonical::ConstView value={}>",
275
- rb_self.value
276
- )
848
+ Self::value(ruby, rb_self)?.inspect()
849
+ ))
277
850
  }
278
851
 
279
852
  fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
@@ -301,11 +874,11 @@ impl EnumView {
301
874
  Ok(array.as_value())
302
875
  }
303
876
 
304
- fn inspect(rb_self: &Self) -> String {
305
- format!(
306
- "#<JSONSchema::Canonical::EnumView values={:?}>",
307
- rb_self.values
308
- )
877
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
878
+ Ok(format!(
879
+ "#<JSONSchema::Canonical::EnumView values={}>",
880
+ Self::values(ruby, rb_self)?.inspect()
881
+ ))
309
882
  }
310
883
 
311
884
  fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
@@ -368,8 +941,10 @@ pub(crate) fn init_canonical(ruby: &Ruby, module: &RModule) -> Result<(), Error>
368
941
  canonical_schema.define_method("definitions", method!(RbCanonicalSchema::definitions, 0))?;
369
942
  canonical_schema.define_method("satisfiable?", method!(RbCanonicalSchema::satisfiable, 0))?;
370
943
 
371
- canonical_module.define_class("TrueView", ruby.class_object())?;
372
- canonical_module.define_class("FalseView", ruby.class_object())?;
944
+ let true_view = canonical_module.define_class("TrueView", ruby.class_object())?;
945
+ true_view.define_method("inspect", method!(TrueView::inspect, 0))?;
946
+ let false_view = canonical_module.define_class("FalseView", ruby.class_object())?;
947
+ false_view.define_method("inspect", method!(FalseView::inspect, 0))?;
373
948
 
374
949
  let multi_type_view = canonical_module.define_class("MultiTypeView", ruby.class_object())?;
375
950
  multi_type_view.define_method("types", method!(MultiTypeView::types, 0))?;
@@ -398,6 +973,88 @@ pub(crate) fn init_canonical(ruby: &Ruby, module: &RModule) -> Result<(), Error>
398
973
  enum_view.define_method("inspect", method!(EnumView::inspect, 0))?;
399
974
  enum_view.define_method("deconstruct_keys", method!(EnumView::deconstruct_keys, 1))?;
400
975
 
976
+ let string_view = canonical_module.define_class("StringView", ruby.class_object())?;
977
+ string_view.define_method("min_length", method!(StringView::min_length, 0))?;
978
+ string_view.define_method("max_length", method!(StringView::max_length, 0))?;
979
+ string_view.define_method("patterns", method!(StringView::patterns, 0))?;
980
+ string_view.define_method("formats", method!(StringView::formats, 0))?;
981
+ string_view.define_method(
982
+ "content_media_types",
983
+ method!(StringView::content_media_types, 0),
984
+ )?;
985
+ string_view.define_method(
986
+ "content_encodings",
987
+ method!(StringView::content_encodings, 0),
988
+ )?;
989
+ string_view.define_method("inspect", method!(StringView::inspect, 0))?;
990
+ string_view.define_method("deconstruct_keys", method!(StringView::deconstruct_keys, 1))?;
991
+
992
+ let number_view = canonical_module.define_class("NumberView", ruby.class_object())?;
993
+ number_view.define_method("minimum", method!(NumberView::minimum, 0))?;
994
+ number_view.define_method(
995
+ "exclusive_minimum",
996
+ method!(NumberView::exclusive_minimum, 0),
997
+ )?;
998
+ number_view.define_method("maximum", method!(NumberView::maximum, 0))?;
999
+ number_view.define_method(
1000
+ "exclusive_maximum",
1001
+ method!(NumberView::exclusive_maximum, 0),
1002
+ )?;
1003
+ number_view.define_method("multiple_of", method!(NumberView::multiple_of, 0))?;
1004
+ number_view.define_method("inspect", method!(NumberView::inspect, 0))?;
1005
+ number_view.define_method("deconstruct_keys", method!(NumberView::deconstruct_keys, 1))?;
1006
+
1007
+ let integer_view = canonical_module.define_class("IntegerView", ruby.class_object())?;
1008
+ integer_view.define_method("minimum", method!(IntegerView::minimum, 0))?;
1009
+ integer_view.define_method("maximum", method!(IntegerView::maximum, 0))?;
1010
+ integer_view.define_method("multiple_of", method!(IntegerView::multiple_of, 0))?;
1011
+ integer_view.define_method("inspect", method!(IntegerView::inspect, 0))?;
1012
+ integer_view.define_method(
1013
+ "deconstruct_keys",
1014
+ method!(IntegerView::deconstruct_keys, 1),
1015
+ )?;
1016
+
1017
+ let array_view = canonical_module.define_class("ArrayView", ruby.class_object())?;
1018
+ array_view.define_method("min_items", method!(ArrayView::min_items, 0))?;
1019
+ array_view.define_method("max_items", method!(ArrayView::max_items, 0))?;
1020
+ array_view.define_method("unique_items", method!(ArrayView::unique_items, 0))?;
1021
+ array_view.define_method("prefix_items", method!(ArrayView::prefix_items, 0))?;
1022
+ array_view.define_method("items", method!(ArrayView::items, 0))?;
1023
+ array_view.define_method("contains", method!(ArrayView::contains, 0))?;
1024
+ array_view.define_method("inspect", method!(ArrayView::inspect, 0))?;
1025
+ array_view.define_method("deconstruct_keys", method!(ArrayView::deconstruct_keys, 1))?;
1026
+ let contains_view = canonical_module.define_class("ContainsView", ruby.class_object())?;
1027
+ contains_view.define_method("schema", method!(ContainsView::schema, 0))?;
1028
+ contains_view.define_method("min_contains", method!(ContainsView::min_contains, 0))?;
1029
+ contains_view.define_method("max_contains", method!(ContainsView::max_contains, 0))?;
1030
+ contains_view.define_method("inspect", method!(ContainsView::inspect, 0))?;
1031
+ contains_view.define_method(
1032
+ "deconstruct_keys",
1033
+ method!(ContainsView::deconstruct_keys, 1),
1034
+ )?;
1035
+
1036
+ let object_view = canonical_module.define_class("ObjectView", ruby.class_object())?;
1037
+ object_view.define_method("min_properties", method!(ObjectView::min_properties, 0))?;
1038
+ object_view.define_method("max_properties", method!(ObjectView::max_properties, 0))?;
1039
+ object_view.define_method("required", method!(ObjectView::required, 0))?;
1040
+ object_view.define_method("property_names", method!(ObjectView::property_names, 0))?;
1041
+ object_view.define_method("properties", method!(ObjectView::properties, 0))?;
1042
+ object_view.define_method(
1043
+ "pattern_properties",
1044
+ method!(ObjectView::pattern_properties, 0),
1045
+ )?;
1046
+ object_view.define_method(
1047
+ "additional_properties",
1048
+ method!(ObjectView::additional_properties, 0),
1049
+ )?;
1050
+ object_view.define_method("inspect", method!(ObjectView::inspect, 0))?;
1051
+ object_view.define_method("deconstruct_keys", method!(ObjectView::deconstruct_keys, 1))?;
1052
+
1053
+ let any_of_view = canonical_module.define_class("AnyOfView", ruby.class_object())?;
1054
+ any_of_view.define_method("branches", method!(AnyOfView::branches, 0))?;
1055
+ any_of_view.define_method("inspect", method!(AnyOfView::inspect, 0))?;
1056
+ any_of_view.define_method("deconstruct_keys", method!(AnyOfView::deconstruct_keys, 1))?;
1057
+
401
1058
  let raw_view = canonical_module.define_class("RawView", ruby.class_object())?;
402
1059
  raw_view.define_method("schema", method!(RawView::schema, 0))?;
403
1060
  raw_view.define_method("inspect", method!(RawView::inspect, 0))?;