schemacop 3.0.0.rc0 → 3.0.0.rc5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5b9526bd5d67ae7a463ab9f5592fe0d23ae06090061b391f0e3f0e1cea5c6cd
4
- data.tar.gz: d34ec2afccc0ddf874e4875babdbe3e733b5cd2b71cc85993920ca4d473e1e9c
3
+ metadata.gz: 7fdf2a714534a94acf7c83e028fe7ce1e4b62c76266cc3e01786cd408d5c17c9
4
+ data.tar.gz: 21ba336e330bf881d4f99cb63c4070dea7559813d7387faa0a2ee53c85fdbb1e
5
5
  SHA512:
6
- metadata.gz: 8ebed3cb5eaf93f6f60f23231cfb3e88f49c00082641a3ba79531692c77802aa5e59eeb619a7f18c71cb23e8ea3438a5aef95c14769dd62dfd5f3b6d3fd50ec7
7
- data.tar.gz: 184241911ffd97e75d4b9ecedc5d796b0b7269d63bff0b869e011011a382ab3f98ca75fbbdb25d507bab66dc9c0c56213df7212e49616210c15b94f1844f7cd7
6
+ metadata.gz: 3636130ba0c0ee471e97e3ef9e259cc86840eaaf6b6435466fcaa17dafdb17aaff406b052e7e3eeffbbbb6e0f1fe3283feb5dda4dfcd5a008d3d60ee8c01f5bf
7
+ data.tar.gz: 46fa1c3b015cfa725e9c624f74fc16f0bf07c6db64e74282e12136c17dc664ae02edb128fe3110516728fab47c2fd105068fb2d9b318f617db39f82dc6264b64
data/.releaser_config CHANGED
@@ -1,4 +1,3 @@
1
1
  version_file: VERSION
2
2
  always_from_master: true
3
- yard_path: doc
4
3
  gem_style: github
data/.travis.yml CHANGED
@@ -2,6 +2,7 @@ language: ruby
2
2
  rvm:
3
3
  - 2.6.2
4
4
  - 2.7.1
5
+ - 3.0.0
5
6
  script:
6
7
  - bundle install
7
8
  - bundle exec rake test
data/CHANGELOG.md CHANGED
@@ -10,7 +10,40 @@
10
10
  ### Changes
11
11
  -->
12
12
 
13
- ## 3.0.0.rc0
13
+ ## 3.0.0.rc5 (2021-02-05)
14
+
15
+ * Use `ruby2_keywords` for compatibility with ruby `2.6.2`
16
+
17
+ ## 3.0.0.rc4 (2021-02-02)
18
+
19
+ * Fix some minor bugs
20
+
21
+ * Improve documentation
22
+
23
+ * `used_external_schemas` for the `ReferenceNode` is now applied
24
+ recursively
25
+
26
+ ## 3.0.0.rc3 (2021-01-28)
27
+
28
+ * Add minor improvements to the documentation
29
+
30
+ * Internal restructuring, no changes in API
31
+
32
+ ## 3.0.0.rc2 (2021-01-28)
33
+
34
+ * Represent node names as strings internally
35
+
36
+ * Update documentation
37
+
38
+ ## 3.0.0.rc1 (2021-01-22)
39
+
40
+ * Add support for ruby `3.0.0`
41
+
42
+ * Add `ruby-3.0.0` to travis testing
43
+
44
+ * Document all `v3` nodes
45
+
46
+ ## 3.0.0.rc0 (2021-01-14)
14
47
 
15
48
  * Add `Schemacop::Schema3`
16
49
 
data/README.md CHANGED
@@ -8,6 +8,16 @@ against schema definitions described by a simple DSL. It is also able to
8
8
  generate [JSON Schema](https://json-schema.org) compliant JSON output, i.e. for
9
9
  use in conjunction with [OpenAPI](https://swagger.io/specification/).
10
10
 
11
+ ## Compatibility
12
+
13
+ Schemacop is tested with the following ruby versions:
14
+
15
+ * 2.6.2
16
+ * 2.7.1
17
+ * 3.0.0
18
+
19
+ For these versions, the automated CI tests are ran on travis. Other ruby versions might work, but stick to these versions for best results.
20
+
11
21
  ## Basic example
12
22
 
13
23
  ```ruby
@@ -84,11 +94,11 @@ actual JSON string.
84
94
 
85
95
  Schemacop will throw one of the following checked exceptions:
86
96
 
87
- * {Schemacop::Exceptions::InvalidSchemaError}
97
+ * `Schemacop::Exceptions::InvalidSchemaError`
88
98
 
89
99
  This exception is thrown when the given schema definition format is invalid.
90
100
 
91
- * {Schemacop::Exceptions::ValidationError}
101
+ * `Schemacop::Exceptions::ValidationError`
92
102
 
93
103
  This exception is thrown when the given data does not comply with the given
94
104
  schema definition.
@@ -108,4 +118,4 @@ To run tests:
108
118
 
109
119
  ## Copyright
110
120
 
111
- Copyright (c) 2020 Sitrox. See `LICENSE` for further details.
121
+ Copyright © 2016 - 2021 Sitrox. See `LICENSE` for further details.
data/README_V3.md CHANGED
@@ -1,15 +1,11 @@
1
1
  # Schemacop schema V3
2
2
 
3
- Please note that Schemacop v3 is still a work in progress, especially the documentation.
3
+ ## Table of Contents
4
4
 
5
- Use at your own discretion.
6
-
7
- # Table of Contents
8
- 1. [Introcution](#Introcution)
9
- 2. [Validation](#validation)
10
- 3. [Exceptions](#exceptions)
11
- 4. [Generic Keywords](#generic-keywords)
12
- 5. [Nodes](#nodes)
5
+ 1. [Validation](#validation)
6
+ 2. [Exceptions](#exceptions)
7
+ 3. [Generic Keywords](#generic-keywords)
8
+ 4. [Nodes](#nodes)
13
9
  1. [String](#string)
14
10
  2. [Integer](#integer)
15
11
  3. [Number](#number)
@@ -23,16 +19,12 @@ Use at your own discretion.
23
19
  11. [OneOf](#oneOf)
24
20
  12. [IsNot](#isNot)
25
21
  13. [Reference](#reference)
26
- 6. [Context](#context)
27
- 7. [External schemas](#external-schemas)
28
-
29
- ## Introcution
30
-
31
- TODO: Write short section about using schemacop V3
22
+ 5. [Context](#context)
23
+ 6. [External schemas](#external-schemas)
32
24
 
33
25
  ## Validation
34
26
 
35
- Using schemacop, you can either choose to validate the data either using the
27
+ Using Schemacop, you can either choose to validate your data either using the
36
28
  graceful `validate` method, or the bang variant, `validate!`.
37
29
 
38
30
  The `validate` method on a schema with some supplied data will return a
@@ -74,19 +66,120 @@ schema.validate!('Foo') # => Schemacop::Exceptions::ValidationError: /:
74
66
 
75
67
  ## Exceptions
76
68
 
77
- TODO: Describe the exceptions raised by schemacop
69
+ Schemacop can raise the following exceptions:
70
+
71
+ * `Schemacop::Exceptions::ValidationError`: This exception is raised when the
72
+ `validate!` method is used, and the data that was passed in is invalid. The
73
+ exception message contains additional information why the validation failed.
74
+
75
+ Example:
78
76
 
79
- `Schemacop::Exceptions::ValidationError`
80
- `Schemacop::Exceptions::InvalidSchemaError`
77
+ ```ruby
78
+ schema = Schemacop::Schema3.new do
79
+ int! :foo
80
+ end
81
+
82
+ schema.validate!(foo: 'bar')
83
+ # => Schemacop::Exceptions::ValidationError: /foo: Invalid type, expected "integer".
84
+ ```
85
+
86
+ * `Schemacop::Exceptions::InvalidSchemaError`: This exception is raised when the
87
+ schema itself is not valid. The exception message contains additional
88
+ information why the validation failed.
89
+
90
+ Example:
91
+
92
+ ```ruby
93
+ Schemacop::Schema3.new :hash do
94
+ int!
95
+ end
96
+
97
+ # => Schemacop::Exceptions::InvalidSchemaError: Child nodes must have a name.
98
+ ```
81
99
 
82
100
  ## Generic Keywords
83
101
 
84
- TODO: Complete this
102
+ The nodes in Schemacop v3 also support generic keywords, similar to JSON schema:
103
+
104
+ * `title`: Short string, should be self-explanatory
105
+ * `description`: Description of the schema
106
+ * `examples`: Here, you can provide examples which will be valid for the schema
107
+ * `enum`: Here, you may enumerate values which will be valid, if the provided
108
+ value is not in the array, the validation will fail
109
+ * `default`: You may provide a default value for items that will be set if the
110
+ value is not given
111
+
112
+ The three keywords `title`, `description` and `examples` aren't used for validation,
113
+ but can be used to document the schema. They will be included in the JSON output
114
+ when you use the `as_json` method:
115
+
116
+ ```ruby
117
+ schema = Schemacop::Schema3.new :hash do
118
+ str! :name, title: 'Name', description: 'Holds the name of the user', examples: ['Joe', 'Anna']
119
+ end
120
+
121
+ schema.as_json
122
+
123
+ # => {"properties"=>{"name"=>{"type"=>"string", "title"=>"Name", "examples"=>["Joe", "Anna"], "description"=>"Holds the name of the user"}}, "additionalProperties"=>false, "required"=>["name"], "type"=>"object"}
124
+ ```
125
+
126
+ The `enum` keyword can be used to only allow a subset of values:
127
+
128
+ ```ruby
129
+ schema = Schemacop::Schema3.new :string, enum: ['foo', 'bar']
130
+
131
+ schema.validate!('foo') # => "foo"
132
+ schema.validate!('bar') # => "bar"
133
+ schema.validate!('baz') # => Schemacop::Exceptions::ValidationError: /: Value not included in enum ["foo", "bar"].
134
+ ```
135
+
136
+ Please note that you can also specify values in the enum that are not valid for
137
+ the schema. This means that the validation will still fail:
138
+
139
+ ```ruby
140
+ schema = Schemacop::Schema3.new :string, enum: ['foo', 'bar', 42]
141
+
142
+ schema.validate!('foo') # => "foo"
143
+ schema.validate!('bar') # => "bar"
144
+ schema.validate!(42) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "string".
145
+ ```
146
+
147
+ The enum will also be provided in the json output:
148
+
149
+ ```ruby
150
+ schema = Schemacop::Schema3.new :string, enum: ['foo', 'bar']
151
+
152
+ schema.as_json
153
+ # => {"type"=>"string", "enum"=>["foo", "bar", 42]}
154
+ ```
155
+
156
+ And finally, the `default` keyword lets you set a default value to use when no
157
+ value is provided:
158
+
159
+ ```ruby
160
+ schema = Schemacop::Schema3.new :string, default: 'Schemacop'
161
+
162
+ schema.validate!('foo') # => "foo"
163
+ schema.validate!(nil) # => "Schemacop"
164
+ ```
165
+
166
+ The default value will also be provided in the json output:
167
+
168
+ ```ruby
169
+ schema = Schemacop::Schema3.new :string, default: 'Schemacop'
170
+
171
+ schema.as_json
172
+ # => {"type"=>"string", "default"=>"Schemacop"}
173
+ ```
85
174
 
86
- * enum
87
- * title
88
- * description
89
- * examples
175
+ Note that the default value you use is also validated against the schema:
176
+
177
+ ```ruby
178
+ schema = Schemacop::Schema3.new :string, default: 42
179
+
180
+ schema.validate!('foo') # => "foo"
181
+ schema.validate!(nil) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "string".
182
+ ```
90
183
 
91
184
  ## Nodes
92
185
 
@@ -102,9 +195,9 @@ transformed into various types.
102
195
  #### Options
103
196
 
104
197
  * `min_length`
105
- Defines the minimum required string length
198
+ Defines the (inclusive) minimum required string length
106
199
  * `max_length`
107
- Defines the maximum required string length
200
+ Defines the (inclusive) maximum required string length
108
201
  * `pattern`
109
202
  Defines a (ruby) regex pattern the value will be matched against. Must be a
110
203
  string and should generally start with `^` and end with `$` so as to evaluate
@@ -136,7 +229,7 @@ transformed into various types.
136
229
 
137
230
  * `boolean`
138
231
  The string must be either `true` or `false`. This value will be casted to
139
- ruby's `TrueClass` or `FalseClass`.
232
+ Ruby's `TrueClass` or `FalseClass`.
140
233
 
141
234
  * `binary`
142
235
  The string is expected to contain binary contents. No casting or additional
@@ -287,7 +380,7 @@ schema.validate!(1234) # => Schemacop::Exceptions::ValidationError: /: Invali
287
380
  ### Array
288
381
 
289
382
  Type: `:array`\
290
- DSL: `arr`
383
+ DSL: `ary`
291
384
 
292
385
  The array type represents a ruby `Array`.
293
386
  It consists of one or multiple values, which can be validated using arbitrary nodes.
@@ -307,6 +400,42 @@ It consists of one or multiple values, which can be validated using arbitrary no
307
400
  each other, or if there may be duplicate values. By default, this is false,
308
401
  i.e. duplicate values are allowed
309
402
 
403
+ #### Contains
404
+
405
+ The `array` node features the *contains* node, which you can use with the DSL
406
+ method `cont`. With that DSL method, you can specify a schema which at least one
407
+ item in the array needs to validate against.
408
+
409
+ One use case for example could be that you want an array of integers, from which
410
+ at least one must be 5 or larger:
411
+
412
+ ```ruby
413
+ schema = Schemacop::Schema3.new :array do
414
+ list :integer
415
+ cont :integer, minimum: 5
416
+ end
417
+
418
+ schema.validate!([]) # => Schemacop::Exceptions::ValidationError: /: At least one entry must match schema {"type"=>"integer", "minimum"=>5}.
419
+ schema.validate!([1, 5]) # => [1, 5]
420
+ schema.validate!(['foo']) # => Schemacop::Exceptions::ValidationError: /[0]: Invalid type, expected "integer". /: At least one entry must match schema {"type"=>"integer", "minimum"=>5}
421
+ ```
422
+
423
+ You can also use it with the tuple validation (see below), e.g. if you want
424
+ an array of 3 integers, from which at least one needs to be 5 or larger:
425
+
426
+ ```ruby
427
+ schema = Schemacop::Schema3.new :array do
428
+ int
429
+ int
430
+ int
431
+ cont :integer, minimum: 5
432
+ end
433
+
434
+ schema.validate!([]) # => /: Array has 0 items but must have exactly 3. /: At least one entry must match schema {"type"=>"integer", "minimum"=>5}.
435
+ schema.validate!([1, 2, 3]) # => Schemacop::Exceptions::ValidationError: /: At least one entry must match schema {"type"=>"integer", "minimum"=>5}.
436
+ schema.validate!([1, 3, 5]) # => [1, 3, 5]
437
+ ```
438
+
310
439
  #### Specifying properties
311
440
 
312
441
  Array nodes support a block in which you can specify the required array contents.
@@ -317,9 +446,10 @@ how you specify your array contents.
317
446
 
318
447
  List validation validates a sequence of arbitrary length where each item matches
319
448
  the same schema. Unless you specify a `min_items` count on the array node, an
320
- empty array will also validate. To specify a list validation, use the `list`
321
- DSL method, and specify the type you want to validate against. Here, you need
322
- to specify the type of the element using the long `type` name (e.g. `integer` and not `int`).
449
+ empty array will also suffice. To specify a list validation, use the `list` DSL
450
+ method, and specify the type you want to validate against. Here, you need to
451
+ specify the type of the element using the long `type` name (e.g. `integer` and
452
+ not `int`).
323
453
 
324
454
  For example, you can specify that you want an array with only integers between 1 and 5:
325
455
 
@@ -412,8 +542,8 @@ schema.validate!([1, 'foo', 'bar']) # => Schemacop::Exceptions::ValidationError:
412
542
  schema.validate!([1, 'foo', 2, 3]) # => [1, "foo", 2, 3]
413
543
  ```
414
544
 
415
- Please note, that you cannot use multiple `add` in the same array schema, this will result in
416
- an exception:
545
+ Please note that you cannot use multiple `add` in the same array schema, this
546
+ will result in an exception:
417
547
 
418
548
  ```ruby
419
549
  schema = Schemacop::Schema3.new :array do
@@ -425,9 +555,10 @@ end
425
555
  # => Schemacop::Exceptions::InvalidSchemaError: You can only use "add" once to specify additional items.
426
556
  ```
427
557
 
428
- If you want to specify that your schema accept multiple additional types, use the `one_of`
429
- type (see below for more infos). The correct way to specify that you want to allow additional
430
- items, which may be an integer or a string is as follows:
558
+ If you want to specify that your schema accept multiple additional types, use
559
+ the `one_of` type (see below for more infos). The correct way to specify that
560
+ you want to allow additional items, which may be an integer or a string is as
561
+ follows:
431
562
 
432
563
  ```ruby
433
564
  schema = Schemacop::Schema3.new :array do
@@ -437,11 +568,12 @@ schema = Schemacop::Schema3.new :array do
437
568
  str
438
569
  end
439
570
  end
440
- ```
441
571
 
442
- #### Contains
443
-
444
- TODO: Describe `cont` DSL method
572
+ schema.validate!([]) # => Schemacop::Exceptions::ValidationError: /: Array has 0 items but must have exactly 1.
573
+ schema.validate!([1, 2]) # => [1, 2]
574
+ schema.validate!([1, 'foo']) # => [1, "foo"]
575
+ schema.validate!([1, :bar]) # => Schemacop::Exceptions::ValidationError: /[1]: Matches 0 definitions but should match exactly 1.
576
+ ```
445
577
 
446
578
  ### Hash
447
579
 
@@ -453,15 +585,16 @@ It consists of key-value-pairs that can be validated using arbitrary nodes.
453
585
 
454
586
  #### Options
455
587
 
456
- * `additional_properties` TODO: Check this
588
+ * `additional_properties`
457
589
  This option specifies whether additional, unspecified properties are allowed
458
- (`true`) or not (`false`). By default, this is `true` if no properties are
459
- specified and `false` if you have specified at least one property.
590
+ (`true`) or not (`false`). By default, this is `false`, i.e. you need to
591
+ explicitly set it to `true` if you want to allow arbitrary additional properties,
592
+ or use the `add` DSL method (see below) to specify additional properties.
460
593
 
461
594
  * `property_names`
462
595
  This option allows to specify a regexp pattern (as string) which validates the
463
596
  keys of any properties that are not specified in the hash. This option only
464
- makes sense if `additional_properties` is enabled.
597
+ makes sense if `additional_properties` is enabled. See below for more information.
465
598
 
466
599
  * `min_properties`
467
600
  Specifies the (inclusive) minimum number of properties a hash must contain.
@@ -480,28 +613,140 @@ property, which specifies whether a property is required (`!`) or optional
480
613
  (`?`).
481
614
 
482
615
  ```ruby
483
- str! :my_required_property
484
- int! :my_optional_property
616
+ schema = Schemacop::Schema3.new :hash do
617
+ str! :foo # Is a required property
618
+ int? :bar # Is an optional property
619
+ end
620
+
621
+ schema.validate!({}) # => Schemacop::Exceptions::ValidationError: /foo: Value must be given.
622
+ schema.validate!({foo: 'str'}) # => {"foo"=>"str"}
623
+ schema.validate!({foo: 'str', bar: 42}) # => {"foo"=>"str", "bar"=>42}
624
+ schema.validate!({bar: 42}) # => Schemacop::Exceptions::ValidationError: /foo: Value must be given.
625
+ ```
626
+
627
+ The name of the properties may either be a string or a symbol, and you can pass
628
+ in the property either identified by a symbol or a string:
629
+
630
+ The following two schemas are equal:
631
+
632
+ ```ruby
633
+ schema = Schemacop::Schema3.new :hash do
634
+ int! :foo
635
+ end
636
+
637
+ schema.validate!(foo: 42) # => {"foo"=>42}
638
+ schema.validate!('foo' => 42) # => {"foo"=>42}
639
+
640
+ schema = Schemacop::Schema3.new :hash do
641
+ int! 'foo'
642
+ end
643
+
644
+ schema.validate!(foo: 42) # => {"foo"=>42}
645
+ schema.validate!('foo' => 42) # => {"foo"=>42}
485
646
  ```
486
647
 
487
- ##### Pattern properties
648
+ The result in both cases will be a
649
+ [HashWithIndifferentAccess](https://api.rubyonrails.org/classes/ActiveSupport/HashWithIndifferentAccess.html),
650
+ which means that you can access the data in the hash with the symbol as well as
651
+ the string representation:
488
652
 
489
- In addition to symbols, property keys can also be a regular expression:
653
+ ```ruby
654
+ schema = Schemacop::Schema3.new :hash do
655
+ int! :foo
656
+ end
657
+
658
+ result = schema.validate!(foo: 42)
659
+
660
+ result.class # => ActiveSupport::HashWithIndifferentAccess
661
+ result[:foo] # => 42
662
+ result['foo'] # 42
663
+ ```
664
+
665
+ Please note that if you specify the value twice in the data you want to
666
+ validate, once with the key being a symbol and once being a string, Schemacop
667
+ will raise an error:
490
668
 
491
669
  ```ruby
492
- Schemacop::Schema3.new do
493
- str! :name
670
+ schema = Schemacop::Schema3.new :hash do
671
+ int! :foo
672
+ end
494
673
 
495
- # The following statement allows any number of integer properties of which the
496
- # name starts with `id_`.
497
- int! /^id_.*$/
674
+ schema.validate!(foo: 42, 'foo' => 43) # => Schemacop::Exceptions::ValidationError: /: Has 1 ambiguous properties: [:foo].
675
+ ```
676
+
677
+ In addition to the normal node options (which vary from type to type, check
678
+ the respective nodes for details), properties also support the `as` option.
679
+
680
+ With this, you can "rename" properties in the output:
681
+
682
+ ```ruby
683
+ schema = Schemacop::Schema3.new :hash do
684
+ int! :foo, as: :bar
685
+ end
686
+
687
+ schema.validate!({foo: 42}) # => {"bar"=>42}
688
+ ```
689
+
690
+ Please note that if you specify a node with the same property name multiple
691
+ times, or use the `as` option to rename a node to the same name of another
692
+ node, the last specified node will be used:
693
+
694
+ ```ruby
695
+ schema = Schemacop::Schema3.new :hash do
696
+ int? :foo
697
+ str? :foo
698
+ end
699
+
700
+ schema.validate!({foo: 1}) # => Schemacop::Exceptions::ValidationError: /foo: Invalid type, expected "string".
701
+ schema.validate!({foo: 'bar'}) # => {"foo"=>"bar"}
702
+ ```
703
+
704
+ As well as:
705
+
706
+ ```ruby
707
+ schema = Schemacop::Schema3.new :hash do
708
+ int? :foo
709
+ int? :bar, as: :foo
498
710
  end
711
+
712
+ schema.validate!({foo: 1}) # => {"foo"=>1}
713
+ schema.validate!({foo: 1, bar: 2}) # => {"foo"=>2}
714
+ schema.validate!({bar: 2}) # => {"foo"=>2}
499
715
  ```
500
716
 
501
- For example, the above example would successfully validate the following hash:
717
+ If you want to specify a node which may be one of multiple types, use the `one_of`
718
+ node (see further down for more details):
502
719
 
503
720
  ```ruby
504
- { name: 'John Doe', id_a: 42, id_b: 42 }
721
+ schema = Schemacop::Schema3.new :hash do
722
+ one_of! :foo do
723
+ int
724
+ str
725
+ end
726
+ end
727
+
728
+ schema.validate!({foo: 1}) # => {"foo"=>1}
729
+ schema.validate!({foo: 'bar'}) # => {"foo"=>"bar"}
730
+ ```
731
+
732
+ ##### Pattern properties
733
+
734
+ In addition to symbols, property keys can also be a regular expression. Here,
735
+ you may only use the optional `?` suffix for the property. This allows any
736
+ property, which matches the type and the name of the property matches the
737
+ regular expression.
738
+
739
+ ```ruby
740
+ schema = Schemacop::Schema3.new :hash do
741
+ # The following statement allows any number of integer properties of which the
742
+ # name starts with `id_`.
743
+ int? /^id_.*$/
744
+ end
745
+
746
+ schema.validate!({}) # => {}
747
+ schema.validate!({id_foo: 1}) # => {"id_foo"=>1}
748
+ schema.validate!({id_foo: 1, id_bar: 2}) # => {"id_foo"=>1, "id_bar"=>2}
749
+ schema.validate!({foo: 3}) # => Schemacop::Exceptions::ValidationError: /: Obsolete property "foo".
505
750
  ```
506
751
 
507
752
  ##### Additional properties & property names
@@ -511,19 +756,32 @@ additional, unspecified properties. By default, this is turned off if you have
511
756
  defined at least one standard property.
512
757
 
513
758
  When it comes to additional properties, you have the choice to either just
514
- enable all of them by enabling the option `additional_properties`. Using the DSL
515
- method `add` in the hash-node's body however, you can specify an additional
516
- schema to which additional properties must adhere:
759
+ enable all of them by enabling the option `additional_properties`:
760
+
761
+ ```ruby
762
+ # This schema will accept any additional properties
763
+ schema = Schemacop::Schema3.new :hash, additional_properties: true
764
+
765
+ schema.validate!({}) # => {}
766
+ schema.validate!({foo: :bar, baz: 42}) # => {"foo"=>:bar, "baz"=>42}
767
+ ```
768
+
769
+ Using the DSL method `add` in the hash-node's body however, you can specify
770
+ an additional schema to which additional properties must adhere:
771
+
517
772
 
518
773
  ```ruby
519
- Schemacop::Schema3.new do
774
+ Schemacop::Schema3.new :hash do
520
775
  int! :id
521
776
 
522
777
  # Allow any additional properties besides `id`, but their value must be a
523
- # string. Note that using the `add` node, the option `additional_properties`
524
- # is automatically enabled.
525
- add :str
778
+ # string.
779
+ add :string
526
780
  end
781
+
782
+ schema.validate!({id: 1}) # => {"id"=>1}
783
+ schema.validate!({id: 1, foo: 'bar'}) # => {"id"=>1, "foo"=>"bar"}
784
+ schema.validate!({id: 1, foo: 42}) # => Schemacop::Exceptions::ValidationError: /foo: Invalid type, expected "string".
527
785
  ```
528
786
 
529
787
  Using the option `property_names`, you can additionaly specify a pattern that
@@ -532,13 +790,23 @@ any additional property **keys** must adhere to:
532
790
  ```ruby
533
791
  # The following schema allows any number of properties, but all keys must
534
792
  # consist of downcase letters from a-z.
535
- Schemacop::Schema3.new additional_properties: :true, property_names: '^[a-z]+$'
793
+ schema = Schemacop::Schema3.new :hash, additional_properties: true, property_names: '^[a-z]+$'
794
+
795
+
796
+ schema.validate!({}) # => {}
797
+ schema.validate!({foo: 123}) # => {"foo"=>123}
798
+ schema.validate!({Foo: 'bar'}) # => Schemacop::Exceptions::ValidationError: /: Property name "Foo" does not match "^[a-z]+$".
536
799
 
537
800
  # The following schema allows any number of properties, but all keys must
538
801
  # consist of downcase letters from a-z AND the properties must be arrays.
539
- Schemacop::Schema3.new additional_properties: :true, property_names: '^[a-z]+$' do
802
+ schema = Schemacop::Schema3.new :hash, additional_properties: true, property_names: '^[a-z]+$' do
540
803
  add :array
541
804
  end
805
+
806
+ schema.validate!({}) # => {}
807
+ schema.validate!({foo: [1, 2, 3]}) # => {"foo"=>[1, 2, 3]}
808
+ schema.validate!({foo: :bar}) # => Schemacop::Exceptions::ValidationError: /foo: Invalid type, expected "array".
809
+ schema.validate!({Foo: :bar}) # => Schemacop::Exceptions::ValidationError: /: Property name :Foo does not match "^[a-z]+$". /Foo: Invalid type, expected "array".
542
810
  ```
543
811
 
544
812
  ##### Dependencies
@@ -549,7 +817,7 @@ Using the DSL method `dep`, you can specifiy (non-nested) property dependencies:
549
817
  # In this example, `billing_address` and `phone_number` are required if
550
818
  # `credit_card` is given, and `credit_card` is required if `billing_address` is
551
819
  # given.
552
- Schemacop::Schema3.new do
820
+ schema = Schemacop::Schema3.new :hash do
553
821
  str! :name
554
822
  str? :credit_card
555
823
  str? :billing_address
@@ -558,126 +826,428 @@ Schemacop::Schema3.new do
558
826
  dep :credit_card, :billing_address, :phone_number
559
827
  dep :billing_address, :credit_card
560
828
  end
829
+
830
+ schema.validate!({}) # => Schemacop::Exceptions::ValidationError: /name: Value must be given.
831
+ schema.validate!({name: 'Joe Doe'}) # => {"name"=>"Joe Doe"}
832
+ schema.validate!({
833
+ name: 'Joe Doe',
834
+ billing_address: 'Street 42'
835
+ })
836
+ # => Schemacop::Exceptions::ValidationError: /: Missing property "credit_card" because "billing_address" is given.
837
+
838
+ schema.validate!({
839
+ name: 'Joe Doe',
840
+ credit_card: 'XXXX XXXX XXXX XXXX X'
841
+ })
842
+ # => Schemacop::Exceptions::ValidationError: /: Missing property "billing_address" because "credit_card" is given. /: Missing property "phone_number" because "credit_card" is given.
843
+
844
+ schema.validate!({
845
+ name: 'Joe Doe',
846
+ billing_address: 'Street 42',
847
+ phone_number: '000-000-00-00',
848
+ credit_card: 'XXXX XXXX XXXX XXXX X'
849
+ })
850
+ # => {"name"=>"Joe Doe", "credit_card"=>"XXXX XXXX XXXX XXXX X", "billing_address"=>"Street 42", "phone_number"=>"000-000-00-00"}
561
851
  ```
562
852
 
563
- #### Examples
564
- ```ruby
565
- schema = Schemacop::Schema3.new do
566
- # Define built-in schema 'address' for re-use
567
- scm :address do
568
- str! :street
569
- int! :number
570
- str! :zip
571
- end
853
+ ### Object
572
854
 
573
- int? :id
574
- str! :name
855
+ Type: `:object`\
856
+ DSL: `obj`
575
857
 
576
- # Reference above defined schema 'address' and use it for key 'address'
577
- ref! :address, :address
858
+ The object type represents a Ruby `Object`. Please note that the `as_json`
859
+ method on nodes of this type will just return `{}` (an empty JSON object), as
860
+ there isn't a useful way to represent a Ruby object without conflicting with the
861
+ `Hash` type. If you want to represent a JSON object, you should use the `Hash`
862
+ node.
578
863
 
579
- # Reference above defined schema 'address' and use it as contents for array
580
- # in key `additional_addresses`
581
- ary! :additional_addresses, default: [] do
582
- ref :address
583
- end
584
- ary? :comments, :array, default: [] { str }
864
+ In the most basic form, this node will accept anything:
585
865
 
586
- # Define a hash with key `jobs` that needs at least one property, and all
587
- # properties must be valid integers and their values must be strings.
588
- hsh! :jobs, min_properties: 1 do
589
- str? /^[0-9]+$/
590
- end
591
- end
866
+ ```ruby
867
+ schema = Schemacop::Schema3.new :object
592
868
 
593
- schema.valid?(
594
- id: 42,
595
- name: 'John Doe',
596
- address: {
597
- street: 'Silver Street',
598
- number: 4,
599
- zip: '38234C'
600
- },
601
- additional_addresses: [
602
- { street: 'Example street', number: 42, zip: '8048' }
603
- ],
604
- comments: [
605
- 'This is a comment'
606
- ],
607
- jobs: {
608
- 2020 => 'Software Engineer'
609
- }
610
- ) # => true
869
+ schema.validate!(nil) # => nil
870
+ schema.validate!(true) # => true
871
+ schema.validate!(false) # => false
872
+ schema.validate!(Object.new) # => #<Object:0x0000556ab4f58dd0>
873
+ schema.validate!('foo') # => "foo"
611
874
  ```
612
875
 
876
+ If you want to limit the allowed classes, you can so so by specifying an array
877
+ of allowed classes:
878
+
613
879
  ```ruby
614
- # The following schema supports exactly the properties defined below, `options`
615
- # being a nested hash.
616
- Schemacop::Schema3.new do
617
- int? :id # Optional integer with key 'id'
618
- str! :name # Required string with name 'name'
619
- hsh! :options do # Required hash with name `options`
620
- boo! :enabled # Required boolean with name `enabled`
621
- end
622
- end
880
+ schema = Schemacop::Schema3.new :object, classes: [String]
623
881
 
624
- # Allow any hash with any contents.
625
- Schemacop::Schema3.new(additional_properties: true)
882
+ schema.validate!(nil) # => nil
883
+ schema.validate!(true) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "String".
884
+ schema.validate!(Object.new) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "String".
885
+ schema.validate!('foo') # => "foo"
886
+ schema.validate!('foo'.html_safe) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "String".
887
+ ```
626
888
 
627
- # Allow a hash where `id` is given, but any additional properties of any name
628
- # and any type are supported as well.
629
- Schemacop::Schema3.new(additional_properties: true) do
630
- int! :id
631
- end
889
+ Here, the node checks if the given value is an instance of any of the given
890
+ classes with `instance_of?`, i.e. the exact class and not a subclass.
632
891
 
633
- # Allow a hash where `id` is given, but any additional properties of which the
634
- # key starts with `k_` and of any value type are allowed.
635
- Schemacop::Schema3.new(additional_properties: true, property_names: '^k_.*$') do
636
- int! :id
637
- end
892
+ If you want to allow subclasses, you can specify this by using the `strict` option:
638
893
 
639
- # Allow a hash where `id` is given, but any additional properties of which the
640
- # key starts with `k_` and the additional value is a string are allowed.
641
- Schemacop::Schema3.new(additional_properties: true, property_names: '^k_.*$') do
642
- int! :id
643
- add :string
644
- end
894
+ ```ruby
895
+ schema = Schemacop::Schema3.new :object, classes: [String], strict: false
645
896
 
646
- # Allow a hash where `id` is given, and any additional string properties that start
647
- # with `k_` are allowed. At least one string with key `k_*` must be given though
648
- # as this property is required.
649
- Schemacop::Schema3.new(property_names: '^k_.*$') do
650
- int! :id
651
- str! /^k_.*$/
652
- end
897
+ schema.validate!(nil) # => nil
898
+ schema.validate!(true) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "String".
899
+ schema.validate!(Object.new) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "String".
900
+ schema.validate!('foo') # => "foo"
901
+ schema.validate!('foo'.html_safe) # => "foo"
653
902
  ```
654
903
 
655
- ### Object
656
-
657
- Type: `:object`\
658
- DSL: `obj`
904
+ If you set the `strict` option to `false`, the check is done using `is_a?` instead of
905
+ `instance_of?`, which also allows subclasses
659
906
 
660
907
  ### AllOf
661
908
 
662
909
  Type: `:all_of`\
663
910
  DSL: `all_of`
664
911
 
912
+ With the AllOf node you can specify multiple schemas, for which the given value
913
+ needs to validate against every one:
914
+
915
+ ```ruby
916
+ schema = Schemacop::Schema3.new :all_of do
917
+ str min_length: 2
918
+ str max_length: 4
919
+ end
920
+
921
+ schema.validate!('foo') # => "foo"
922
+ schema.validate!('foooo') # => Schemacop::Exceptions::ValidationError: /: Does not match all allOf conditions.
923
+ ```
924
+
925
+ Please note that it's possible to create nonsensical schemas with this node, as
926
+ you can combine multiple schemas which contradict each other:
927
+
928
+ ```ruby
929
+ schema = Schemacop::Schema3.new :all_of do
930
+ str min_length: 4
931
+ str max_length: 1
932
+ end
933
+
934
+ schema.validate!('foo') # => Schemacop::Exceptions::ValidationError: /: Does not match all allOf conditions.
935
+ schema.validate!('foooo') # => Schemacop::Exceptions::ValidationError: /: Does not match all allOf conditions.
936
+ ```
937
+
665
938
  ### AnyOf
666
939
 
667
940
  Type: `:any_of`\
668
941
  DSL: `any_of`
669
942
 
943
+ Similar to the `all_of` node, you can specify multiple schemas, for which the
944
+ given value needs to validate against at least one of the schemas.
945
+
946
+ For example, your value needs to be either a string which is at least 2
947
+ characters long, or an integer:
948
+
949
+ ```ruby
950
+ schema = Schemacop::Schema3.new :any_of do
951
+ str min_length: 2
952
+ int
953
+ end
954
+
955
+ schema.validate!('f') # => Schemacop::Exceptions::ValidationError: /: Does not match any anyOf condition.
956
+ schema.validate!('foo') # => "foo"
957
+ schema.validate!(42) # => 42
958
+ ```
959
+
960
+ Please note that you need to specify at least one item in the `any_of` node:
961
+
962
+ ```ruby
963
+ Schemacop::Schema3.new :any_of # => Schemacop::Exceptions::InvalidSchemaError: Node "any_of" makes only sense with at least 1 item.
964
+ ```
965
+
670
966
  ### OneOf
671
967
 
672
968
  Type: `:one_of`\
673
969
  DSL: `one_of`
674
970
 
971
+ Similar to the `all_of` node, you can specify multiple schemas, for which the
972
+ given value needs to validate against exaclty one of the schemas. If the given
973
+ value validates against multiple schemas, the value is invalid.
974
+
975
+ For example, if you want an integer which is either a multiple of 2 or 3,
976
+ but not both (i.e. no multiple of 6), you could do it as follows:
977
+
978
+ ```ruby
979
+ schema = Schemacop::Schema3.new :one_of do
980
+ int multiple_of: 2
981
+ int multiple_of: 3
982
+ end
983
+
984
+ schema.validate!(2) # => 2
985
+ schema.validate!(3) # => 3
986
+ schema.validate!(4) # => 4
987
+ schema.validate!(5) # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
988
+ schema.validate!(6) # => Schemacop::Exceptions::ValidationError: /: Matches 2 definitions but should match exactly 1.
989
+ ```
990
+
991
+ Again, as previously with the AllOf node, you're allowed to create schemas
992
+ which will not work for any input, e.g. by specifying the same schema twice:
993
+
994
+ ```ruby
995
+ schema = Schemacop::Schema3.new :one_of do
996
+ int multiple_of: 2
997
+ int multiple_of: 2
998
+ end
999
+
1000
+ schema.validate!(2) # => Schemacop::Exceptions::ValidationError: /: Matches 2 definitions but should match exactly 1.
1001
+ schema.validate!(3) # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
1002
+ schema.validate!(4) # => Schemacop::Exceptions::ValidationError: /: Matches 2 definitions but should match exactly 1.
1003
+ schema.validate!(5) # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
1004
+ schema.validate!(6) # => Schemacop::Exceptions::ValidationError: /: Matches 2 definitions but should match exactly 1.
1005
+ ```
1006
+
675
1007
  ### IsNot
676
1008
 
677
1009
  Type: `:is_not`\
678
1010
  DSL: `is_not`
679
1011
 
1012
+ With the `is_not` node, you can specify a schema which the given value must not
1013
+ validate against, i.e. every value which matches the schema will make this node
1014
+ invalid.
1015
+
1016
+ For example, you want anything but the numbers between 3 and 5:
1017
+
1018
+ ```ruby
1019
+ schema = Schemacop::Schema3.new :is_not do
1020
+ int minimum: 3, maximum: 5
1021
+ end
1022
+
1023
+ schema.validate!(nil) # => nil
1024
+ schema.validate!(1) # => 1
1025
+ schema.validate!(2) # => 2
1026
+ schema.validate!(3) # => Schemacop::Exceptions::ValidationError: /: Must not match schema: {"type"=>"integer", "minimum"=>3, "maximum"=>5}.
1027
+ schema.validate!('foo') # => "foo"
1028
+ ```
1029
+
1030
+ Note that a `is_not` node needs exactly one item:
1031
+
1032
+ ```ruby
1033
+ schema = Schemacop::Schema3.new :is_not # => Schemacop::Exceptions::InvalidSchemaError: Node "is_not" only allows exactly one item.
1034
+ ```
1035
+
680
1036
  ### Reference
681
1037
 
682
- DSL: `ref`
1038
+ **Referencing**
1039
+ DSL: `ref`\
1040
+ Type: `reference`
1041
+
1042
+ **Definition**
1043
+ DSL: `scm`
1044
+
1045
+ Finally, with the *Reference* node, you can define schemas and then later reference
1046
+ them for usage, e.g. when you have a rather long schema which you need at multiple
1047
+ places.
683
1048
 
1049
+ #### Examples
1050
+
1051
+ For example, let's define an object with an schema called `Address`, which we'll
1052
+ reference multiple times:
1053
+
1054
+ ```ruby
1055
+ schema = Schemacop::Schema3.new :hash do
1056
+ scm :Address do
1057
+ str! :street
1058
+ str! :zip_code
1059
+ str! :location
1060
+ str! :country
1061
+ end
1062
+
1063
+ ref! :shipping_address, :Address
1064
+ ref! :billing_address, :Address
1065
+ end
1066
+
1067
+ schema.validate!({}) # => Schemacop::Exceptions::ValidationError: /shipping_address: Value must be given. /billing_address: Value must be given.
1068
+ schema.validate!({
1069
+ shipping_address: 'foo',
1070
+ billing_address: 42
1071
+ })
1072
+ # => Schemacop::Exceptions::ValidationError: /shipping_address: Invalid type, expected "object". /billing_address: Invalid type, expected "object".
1073
+
1074
+ schema.validate!({
1075
+ shipping_address: {
1076
+ street: 'Example Street 42',
1077
+ zip_code: '12345',
1078
+ location: 'London',
1079
+ country: 'United Kingdom'
1080
+ },
1081
+ billing_address: {
1082
+ street: 'Main St.',
1083
+ zip_code: '54321',
1084
+ location: 'Washington DC',
1085
+ country: 'USA'
1086
+ }
1087
+ })
1088
+
1089
+ # => {"shipping_address"=>{"street"=>"Example Street 42", "zip_code"=>"12345", "location"=>"London", "country"=>"United Kingdom"}, "billing_address"=>{"street"=>"Main St.", "zip_code"=>"54321", "location"=>"Washington DC", "country"=>"USA"}}
1090
+ ```
1091
+
1092
+ Note that if you use the reference node with the long type name `reference`,
1093
+ e.g. in an array, you need to specify the "name" of the schema in the
1094
+ `path` option:
1095
+
1096
+ ```ruby
1097
+ schema = Schemacop::Schema3.new :array do
1098
+ scm :User do
1099
+ str! :first_name
1100
+ str! :last_name
1101
+ end
1102
+
1103
+ list :reference, path: :User
1104
+ end
1105
+
1106
+ schema.validate!([]) # => []
1107
+ schema.validate!([{first_name: 'Joe', last_name: 'Doe'}]) # => [{"first_name"=>"Joe", "last_name"=>"Doe"}]
1108
+ schema.validate!([id: 42, first_name: 'Joe']) # => Schemacop::Exceptions::ValidationError: /[0]/last_name: Value must be given. /[0]: Obsolete property "id".
1109
+ ```
1110
+
1111
+ ## Context
1112
+
1113
+ Schemacop also features the concept of a `Context`. You can define schemas in a
1114
+ context, and then reference them in other schemas in that context. This is e.g.
1115
+ useful if you need a part of the schema to be different depending on the
1116
+ business action.
1117
+
1118
+ Examples:
1119
+
1120
+ ```ruby
1121
+ # Define a new context
1122
+ context = Schemacop::V3::Context.new
1123
+
1124
+ # Define the :Person schema in that context
1125
+ context.schema :Person do
1126
+ str! :first_name
1127
+ str! :last_name
1128
+ ref? :info, :PersonInfo
1129
+ end
1130
+
1131
+ # And also define the :PersonInfo schema in that context
1132
+ context.schema :PersonInfo do
1133
+ str! :born_at, format: :date
1134
+ end
1135
+
1136
+ # Now we can define our general schema, where we reference the :Person schema.
1137
+ # Note that at this point, we don't know what's in the :Person schema.
1138
+ schema = Schemacop::Schema3.new :reference, path: :Person
1139
+
1140
+ # Validate the data in the context we defined before, where we need the first_name
1141
+ # and last_name of a person, as well as an optional info hash with the born_at date
1142
+ # of the person.
1143
+ Schemacop.with_context context do
1144
+ schema.validate!({first_name: 'Joe', last_name: 'Doe', info: { born_at: '1980-01-01'} })
1145
+ # => {"first_name"=>"Joe", "last_name"=>"Doe", "info"=>{"born_at"=>Tue, 01 Jan 1980}}
1146
+ end
1147
+
1148
+ # Now we might want another context, where the person is more anonymous, and as
1149
+ # such, we need another schema
1150
+ other_context = Schemacop::V3::Context.new
1151
+
1152
+ # Here, we only want the nickname of the person
1153
+ other_context.schema :Person do
1154
+ str! :nickname
1155
+ end
1156
+
1157
+ # Finally, validate the data in the new context. We do not want the real name or
1158
+ # birth date of the person, instead only the nickname is allowed.
1159
+ Schemacop.with_context other_context do
1160
+ schema.validate!({first_name: 'Joe', last_name: 'Doe', info: { born_at: '1980-01-01'} })
1161
+ # => Schemacop::Exceptions::ValidationError: /nickname: Value must be given.
1162
+ # /: Obsolete property "first_name".
1163
+ # /: Obsolete property "last_name".
1164
+ # /: Obsolete property "info".
1165
+
1166
+ schema.validate!({nickname: 'J.'}) # => {"nickname"=>"J."}
1167
+ end
1168
+ ```
1169
+
1170
+ As one can see, we validated the data against the same schema, but because we
1171
+ defined the referenced schemas differently in the two contexts, we were able
1172
+ to use other data in the second context than in the first.
1173
+
1174
+ ## External schemas
1175
+
1176
+ Finally, Schemacop features the possibility to specify schemas in seperate
1177
+ files. This is especially useful is you have schemas in your application which
1178
+ are used multiple times throughout the application.
1179
+
1180
+ For each schema, you define the schema in a separate file, and after loading the
1181
+ schemas, you can reference them in other schemas.
1182
+
1183
+ The default load path is `'app/schemas'`, but this can be configured by setting
1184
+ the value of the `load_paths` attribute of the `Schemacop` module.
1185
+
1186
+ Please note that the following predescence order is used for the schemas:
1187
+
1188
+ ```
1189
+ local schemas > context schemas > global schemas
1190
+ ```
1191
+
1192
+ Where:
1193
+
1194
+ * local schemas: Defined by using the DSL method? `scm`
1195
+ * context schemas: Defined in the current context using `context.schema`
1196
+ * global schemas: Defined in a ruby file in the load path
1197
+
1198
+ ### Rails applications
1199
+
1200
+ In Rails applications, your schemas are automatically eager-laoded from the load
1201
+ path `'app/schemas'` when your application is started.
1202
+
1203
+ After starting your application, you can reference them like normally defined
1204
+ reference schemas, with the name being relative to the load path.
1205
+
1206
+ Example:
1207
+
1208
+ You defined the following two schemas in the `'app/schemas'` directory:
1209
+
1210
+ ```ruby
1211
+ # app/schemas/user.rb
1212
+ schema :hash do
1213
+ str! :first_name
1214
+ str! :last_name
1215
+ ary? :groups do
1216
+ list :reference, path: 'nested/group'
1217
+ end
1218
+ end
1219
+ ```
1220
+
1221
+ ```ruby
1222
+ # app/schemas/nested/user.rb
1223
+ schema :hash do
1224
+ str! :name
1225
+ end
1226
+ ```
1227
+
1228
+ To use the schema, you then can simply reference the schema as with normal
1229
+ reference schemas:
1230
+
1231
+ ```ruby
1232
+ schema = Schemacop::Schema3.new :hash do
1233
+ ref! :usr, :user
1234
+ end
1235
+
1236
+ schema.validate!({usr: {first_name: 'Joe', last_name: 'Doe'}})
1237
+ # => {"usr"=>{"first_name"=>"Joe", "last_name"=>"Doe"}}
1238
+
1239
+ schema.validate!({usr: {first_name: 'Joe', last_name: 'Doe', groups: []}})
1240
+ # => {"usr"=>{"first_name"=>"Joe", "last_name"=>"Doe", "groups"=>[]}}
1241
+
1242
+ schema.validate!({usr: {first_name: 'Joe', last_name: 'Doe', groups: [{name: 'foo'}, {name: 'bar'}]}})
1243
+ # => {"usr"=>{"first_name"=>"Joe", "last_name"=>"Doe", "groups"=>[{"name"=>"foo"}, {"name"=>"bar"}]}}
1244
+ ```
1245
+
1246
+ ### Non-Rails applications
1247
+
1248
+ Usage in non-Rails applications is the same as with usage in Rails applications,
1249
+ however you need to eager load the schemas yourself:
1250
+
1251
+ ```ruby
1252
+ Schemacop::V3::GlobalContext.eager_load!
1253
+ ```