schemacop 3.0.0.rc1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.releaser_config +0 -1
- data/CHANGELOG.md +41 -1
- data/README.md +1 -1
- data/README_V3.md +296 -87
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/lib/schemacop.rb +1 -0
- data/lib/schemacop/railtie.rb +7 -0
- data/lib/schemacop/scoped_env.rb +3 -3
- data/lib/schemacop/v2.rb +0 -1
- data/lib/schemacop/v2/caster.rb +1 -0
- data/lib/schemacop/v3/array_node.rb +1 -2
- data/lib/schemacop/v3/hash_node.rb +55 -26
- data/lib/schemacop/v3/node.rb +10 -5
- data/lib/schemacop/v3/node_registry.rb +0 -4
- data/lib/schemacop/v3/reference_node.rb +7 -1
- data/lib/schemacop/v3/string_node.rb +15 -7
- data/schemacop.gemspec +8 -5
- data/test/lib/test_helper.rb +17 -2
- data/test/unit/schemacop/v2/casting_test.rb +37 -0
- data/test/unit/schemacop/v2/validator_hash_test.rb +11 -0
- data/test/unit/schemacop/v3/all_of_node_test.rb +1 -2
- data/test/unit/schemacop/v3/any_of_node_test.rb +6 -6
- data/test/unit/schemacop/v3/array_node_test.rb +13 -3
- data/test/unit/schemacop/v3/global_context_test.rb +2 -0
- data/test/unit/schemacop/v3/hash_node_test.rb +167 -21
- data/test/unit/schemacop/v3/node_test.rb +14 -0
- data/test/unit/schemacop/v3/one_of_node_test.rb +6 -6
- data/test/unit/schemacop/v3/reference_node_test.rb +18 -2
- data/test/unit/schemacop/v3/string_node_test.rb +38 -0
- metadata +18 -5
- data/lib/schemacop/v2/root_node.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb25d83997e507cf7bf5e905143584e01b543c296f74e190eae487fe1a8bfdc0
|
4
|
+
data.tar.gz: 896f9bc4e14ac0e59831eacd83ae2e5a691a53e377f0b4895790b3686c24c2db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 461b762ba18edeac632010db52d368978ead449c6de8a88f6b6883d0109cfa3ff3e8b9bf4c8f2780023b60624bfc80f6456a421a8044fdf4ed7b565d8779db5c
|
7
|
+
data.tar.gz: 693beb806323f0695fce4183ad65d65670d5cab8b76692d74b4a467e396a52540bbb4fa9b9c03bef9940a35c1f62a32fcd0e51ea435f450bc134b502ca5839df
|
data/.releaser_config
CHANGED
data/CHANGELOG.md
CHANGED
@@ -10,7 +10,47 @@
|
|
10
10
|
### Changes
|
11
11
|
-->
|
12
12
|
|
13
|
-
## 3.0.0
|
13
|
+
## 3.0.0 (2021-02-08)
|
14
|
+
|
15
|
+
* Setup Zeitwerk ignores for Rails applications
|
16
|
+
|
17
|
+
* Read previous `3.0.0.rcX` entries for all changes included
|
18
|
+
in this stable release
|
19
|
+
|
20
|
+
## 3.0.0.rc5 (2021-02-05)
|
21
|
+
|
22
|
+
* Use `ruby2_keywords` for compatibility with ruby `2.6.2`
|
23
|
+
|
24
|
+
## 3.0.0.rc4 (2021-02-02)
|
25
|
+
|
26
|
+
* Fix some minor bugs
|
27
|
+
|
28
|
+
* Improve documentation
|
29
|
+
|
30
|
+
* `used_external_schemas` for the `ReferenceNode` is now applied
|
31
|
+
recursively
|
32
|
+
|
33
|
+
## 3.0.0.rc3 (2021-01-28)
|
34
|
+
|
35
|
+
* Add minor improvements to the documentation
|
36
|
+
|
37
|
+
* Internal restructuring, no changes in API
|
38
|
+
|
39
|
+
## 3.0.0.rc2 (2021-01-28)
|
40
|
+
|
41
|
+
* Represent node names as strings internally
|
42
|
+
|
43
|
+
* Update documentation
|
44
|
+
|
45
|
+
## 3.0.0.rc1 (2021-01-22)
|
46
|
+
|
47
|
+
* Add support for ruby `3.0.0`
|
48
|
+
|
49
|
+
* Add `ruby-3.0.0` to travis testing
|
50
|
+
|
51
|
+
* Document all `v3` nodes
|
52
|
+
|
53
|
+
## 3.0.0.rc0 (2021-01-14)
|
14
54
|
|
15
55
|
* Add `Schemacop::Schema3`
|
16
56
|
|
data/README.md
CHANGED
data/README_V3.md
CHANGED
@@ -1,15 +1,11 @@
|
|
1
1
|
# Schemacop schema V3
|
2
2
|
|
3
|
-
|
3
|
+
## Table of Contents
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
29
|
-
## Introduction
|
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
|
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
|
-
|
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:
|
76
|
+
|
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
|
+
```
|
78
85
|
|
79
|
-
`Schemacop::Exceptions::
|
80
|
-
|
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
|
-
|
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
|
+
```
|
85
165
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
+
```
|
174
|
+
|
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
|
-
|
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: `
|
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.
|
@@ -309,11 +402,11 @@ It consists of one or multiple values, which can be validated using arbitrary no
|
|
309
402
|
|
310
403
|
#### Contains
|
311
404
|
|
312
|
-
The `array` node features the contains node, which you can use with the DSL
|
313
|
-
method `cont`. With that DSL method, you can specify a schema which at least
|
314
|
-
|
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.
|
315
408
|
|
316
|
-
One
|
409
|
+
One use case for example could be that you want an array of integers, from which
|
317
410
|
at least one must be 5 or larger:
|
318
411
|
|
319
412
|
```ruby
|
@@ -353,9 +446,10 @@ how you specify your array contents.
|
|
353
446
|
|
354
447
|
List validation validates a sequence of arbitrary length where each item matches
|
355
448
|
the same schema. Unless you specify a `min_items` count on the array node, an
|
356
|
-
empty array will also
|
357
|
-
|
358
|
-
|
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`).
|
359
453
|
|
360
454
|
For example, you can specify that you want an array with only integers between 1 and 5:
|
361
455
|
|
@@ -448,8 +542,8 @@ schema.validate!([1, 'foo', 'bar']) # => Schemacop::Exceptions::ValidationError:
|
|
448
542
|
schema.validate!([1, 'foo', 2, 3]) # => [1, "foo", 2, 3]
|
449
543
|
```
|
450
544
|
|
451
|
-
Please note
|
452
|
-
an exception:
|
545
|
+
Please note that you cannot use multiple `add` in the same array schema, this
|
546
|
+
will result in an exception:
|
453
547
|
|
454
548
|
```ruby
|
455
549
|
schema = Schemacop::Schema3.new :array do
|
@@ -461,9 +555,10 @@ end
|
|
461
555
|
# => Schemacop::Exceptions::InvalidSchemaError: You can only use "add" once to specify additional items.
|
462
556
|
```
|
463
557
|
|
464
|
-
If you want to specify that your schema accept multiple additional types, use
|
465
|
-
type (see below for more infos). The correct way to specify that
|
466
|
-
items, which may be an integer or a string is as
|
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:
|
467
562
|
|
468
563
|
```ruby
|
469
564
|
schema = Schemacop::Schema3.new :array do
|
@@ -492,13 +587,14 @@ It consists of key-value-pairs that can be validated using arbitrary nodes.
|
|
492
587
|
|
493
588
|
* `additional_properties`
|
494
589
|
This option specifies whether additional, unspecified properties are allowed
|
495
|
-
(`true`) or not (`false`). By default, this is `
|
496
|
-
|
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.
|
497
593
|
|
498
594
|
* `property_names`
|
499
595
|
This option allows to specify a regexp pattern (as string) which validates the
|
500
596
|
keys of any properties that are not specified in the hash. This option only
|
501
|
-
makes sense if `additional_properties` is enabled. See below for more
|
597
|
+
makes sense if `additional_properties` is enabled. See below for more information.
|
502
598
|
|
503
599
|
* `min_properties`
|
504
600
|
Specifies the (inclusive) minimum number of properties a hash must contain.
|
@@ -523,11 +619,116 @@ schema = Schemacop::Schema3.new :hash do
|
|
523
619
|
end
|
524
620
|
|
525
621
|
schema.validate!({}) # => Schemacop::Exceptions::ValidationError: /foo: Value must be given.
|
526
|
-
schema.validate!({foo: 'str'}) # => {
|
527
|
-
schema.validate!({foo: 'str', bar: 42}) # => {
|
622
|
+
schema.validate!({foo: 'str'}) # => {"foo"=>"str"}
|
623
|
+
schema.validate!({foo: 'str', bar: 42}) # => {"foo"=>"str", "bar"=>42}
|
528
624
|
schema.validate!({bar: 42}) # => Schemacop::Exceptions::ValidationError: /foo: Value must be given.
|
529
625
|
```
|
530
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}
|
646
|
+
```
|
647
|
+
|
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:
|
652
|
+
|
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:
|
668
|
+
|
669
|
+
```ruby
|
670
|
+
schema = Schemacop::Schema3.new :hash do
|
671
|
+
int! :foo
|
672
|
+
end
|
673
|
+
|
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
|
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}
|
715
|
+
```
|
716
|
+
|
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):
|
719
|
+
|
720
|
+
```ruby
|
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
|
+
|
531
732
|
##### Pattern properties
|
532
733
|
|
533
734
|
In addition to symbols, property keys can also be a regular expression. Here,
|
@@ -543,8 +744,8 @@ schema = Schemacop::Schema3.new :hash do
|
|
543
744
|
end
|
544
745
|
|
545
746
|
schema.validate!({}) # => {}
|
546
|
-
schema.validate!({id_foo: 1}) # => {
|
547
|
-
schema.validate!({id_foo: 1, id_bar: 2}) # => {
|
747
|
+
schema.validate!({id_foo: 1}) # => {"id_foo"=>1}
|
748
|
+
schema.validate!({id_foo: 1, id_bar: 2}) # => {"id_foo"=>1, "id_bar"=>2}
|
548
749
|
schema.validate!({foo: 3}) # => Schemacop::Exceptions::ValidationError: /: Obsolete property "foo".
|
549
750
|
```
|
550
751
|
|
@@ -562,7 +763,7 @@ enable all of them by enabling the option `additional_properties`:
|
|
562
763
|
schema = Schemacop::Schema3.new :hash, additional_properties: true
|
563
764
|
|
564
765
|
schema.validate!({}) # => {}
|
565
|
-
schema.validate!({foo: :bar, baz: 42}) # => {
|
766
|
+
schema.validate!({foo: :bar, baz: 42}) # => {"foo"=>:bar, "baz"=>42}
|
566
767
|
```
|
567
768
|
|
568
769
|
Using the DSL method `add` in the hash-node's body however, you can specify
|
@@ -578,8 +779,8 @@ Schemacop::Schema3.new :hash do
|
|
578
779
|
add :string
|
579
780
|
end
|
580
781
|
|
581
|
-
schema.validate!({id: 1}) # => {
|
582
|
-
schema.validate!({id: 1, foo: 'bar'}) # => {
|
782
|
+
schema.validate!({id: 1}) # => {"id"=>1}
|
783
|
+
schema.validate!({id: 1, foo: 'bar'}) # => {"id"=>1, "foo"=>"bar"}
|
583
784
|
schema.validate!({id: 1, foo: 42}) # => Schemacop::Exceptions::ValidationError: /foo: Invalid type, expected "string".
|
584
785
|
```
|
585
786
|
|
@@ -589,12 +790,12 @@ any additional property **keys** must adhere to:
|
|
589
790
|
```ruby
|
590
791
|
# The following schema allows any number of properties, but all keys must
|
591
792
|
# consist of downcase letters from a-z.
|
592
|
-
schema = Schemacop::Schema3.new :hash, additional_properties:
|
793
|
+
schema = Schemacop::Schema3.new :hash, additional_properties: true, property_names: '^[a-z]+$'
|
593
794
|
|
594
795
|
|
595
796
|
schema.validate!({}) # => {}
|
596
|
-
schema.validate!({foo: 123}) # => {
|
597
|
-
schema.validate!({Foo: 'bar'}) # => Schemacop::Exceptions::ValidationError: /: Property name
|
797
|
+
schema.validate!({foo: 123}) # => {"foo"=>123}
|
798
|
+
schema.validate!({Foo: 'bar'}) # => Schemacop::Exceptions::ValidationError: /: Property name "Foo" does not match "^[a-z]+$".
|
598
799
|
|
599
800
|
# The following schema allows any number of properties, but all keys must
|
600
801
|
# consist of downcase letters from a-z AND the properties must be arrays.
|
@@ -603,7 +804,7 @@ schema = Schemacop::Schema3.new :hash, additional_properties: true, property_nam
|
|
603
804
|
end
|
604
805
|
|
605
806
|
schema.validate!({}) # => {}
|
606
|
-
schema.validate!({foo: [1, 2, 3]}) # => {
|
807
|
+
schema.validate!({foo: [1, 2, 3]}) # => {"foo"=>[1, 2, 3]}
|
607
808
|
schema.validate!({foo: :bar}) # => Schemacop::Exceptions::ValidationError: /foo: Invalid type, expected "array".
|
608
809
|
schema.validate!({Foo: :bar}) # => Schemacop::Exceptions::ValidationError: /: Property name :Foo does not match "^[a-z]+$". /Foo: Invalid type, expected "array".
|
609
810
|
```
|
@@ -627,7 +828,7 @@ schema = Schemacop::Schema3.new :hash do
|
|
627
828
|
end
|
628
829
|
|
629
830
|
schema.validate!({}) # => Schemacop::Exceptions::ValidationError: /name: Value must be given.
|
630
|
-
schema.validate!({name: 'Joe Doe'}) # => {
|
831
|
+
schema.validate!({name: 'Joe Doe'}) # => {"name"=>"Joe Doe"}
|
631
832
|
schema.validate!({
|
632
833
|
name: 'Joe Doe',
|
633
834
|
billing_address: 'Street 42'
|
@@ -646,7 +847,7 @@ schema.validate!({
|
|
646
847
|
phone_number: '000-000-00-00',
|
647
848
|
credit_card: 'XXXX XXXX XXXX XXXX X'
|
648
849
|
})
|
649
|
-
# => {
|
850
|
+
# => {"name"=>"Joe Doe", "credit_card"=>"XXXX XXXX XXXX XXXX X", "billing_address"=>"Street 42", "phone_number"=>"000-000-00-00"}
|
650
851
|
```
|
651
852
|
|
652
853
|
### Object
|
@@ -654,10 +855,11 @@ schema.validate!({
|
|
654
855
|
Type: `:object`\
|
655
856
|
DSL: `obj`
|
656
857
|
|
657
|
-
The object type represents a
|
658
|
-
on nodes of this type will just return `{}` (an empty JSON object), as
|
659
|
-
a useful way to represent a
|
660
|
-
If you want to represent
|
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.
|
661
863
|
|
662
864
|
In the most basic form, this node will accept anything:
|
663
865
|
|
@@ -738,7 +940,7 @@ schema.validate!('foooo') # => Schemacop::Exceptions::ValidationError: /: Does n
|
|
738
940
|
Type: `:any_of`\
|
739
941
|
DSL: `any_of`
|
740
942
|
|
741
|
-
Similar to the
|
943
|
+
Similar to the `all_of` node, you can specify multiple schemas, for which the
|
742
944
|
given value needs to validate against at least one of the schemas.
|
743
945
|
|
744
946
|
For example, your value needs to be either a string which is at least 2
|
@@ -755,7 +957,7 @@ schema.validate!('foo') # => "foo"
|
|
755
957
|
schema.validate!(42) # => 42
|
756
958
|
```
|
757
959
|
|
758
|
-
Please note that you need to specify at least one item in the
|
960
|
+
Please note that you need to specify at least one item in the `any_of` node:
|
759
961
|
|
760
962
|
```ruby
|
761
963
|
Schemacop::Schema3.new :any_of # => Schemacop::Exceptions::InvalidSchemaError: Node "any_of" makes only sense with at least 1 item.
|
@@ -766,9 +968,9 @@ Schemacop::Schema3.new :any_of # => Schemacop::Exceptions::InvalidSchemaError: N
|
|
766
968
|
Type: `:one_of`\
|
767
969
|
DSL: `one_of`
|
768
970
|
|
769
|
-
Similar to the
|
770
|
-
given value needs to validate against
|
771
|
-
|
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.
|
772
974
|
|
773
975
|
For example, if you want an integer which is either a multiple of 2 or 3,
|
774
976
|
but not both (i.e. no multiple of 6), you could do it as follows:
|
@@ -807,7 +1009,7 @@ schema.validate!(6) # => Schemacop::Exceptions::ValidationError: /: Matches 2 de
|
|
807
1009
|
Type: `:is_not`\
|
808
1010
|
DSL: `is_not`
|
809
1011
|
|
810
|
-
With the
|
1012
|
+
With the `is_not` node, you can specify a schema which the given value must not
|
811
1013
|
validate against, i.e. every value which matches the schema will make this node
|
812
1014
|
invalid.
|
813
1015
|
|
@@ -825,7 +1027,7 @@ schema.validate!(3) # => Schemacop::Exceptions::ValidationError: /: Must not
|
|
825
1027
|
schema.validate!('foo') # => "foo"
|
826
1028
|
```
|
827
1029
|
|
828
|
-
Note that a
|
1030
|
+
Note that a `is_not` node needs exactly one item:
|
829
1031
|
|
830
1032
|
```ruby
|
831
1033
|
schema = Schemacop::Schema3.new :is_not # => Schemacop::Exceptions::InvalidSchemaError: Node "is_not" only allows exactly one item.
|
@@ -840,7 +1042,7 @@ Type: `reference`
|
|
840
1042
|
**Definition**
|
841
1043
|
DSL: `scm`
|
842
1044
|
|
843
|
-
Finally, with the Reference node, you can define schemas and then later reference
|
1045
|
+
Finally, with the *Reference* node, you can define schemas and then later reference
|
844
1046
|
them for usage, e.g. when you have a rather long schema which you need at multiple
|
845
1047
|
places.
|
846
1048
|
|
@@ -884,7 +1086,7 @@ schema.validate!({
|
|
884
1086
|
}
|
885
1087
|
})
|
886
1088
|
|
887
|
-
# => {
|
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"}}
|
888
1090
|
```
|
889
1091
|
|
890
1092
|
Note that if you use the reference node with the long type name `reference`,
|
@@ -902,13 +1104,13 @@ schema = Schemacop::Schema3.new :array do
|
|
902
1104
|
end
|
903
1105
|
|
904
1106
|
schema.validate!([]) # => []
|
905
|
-
schema.validate!([{first_name: 'Joe', last_name: 'Doe'}]) # => [{
|
1107
|
+
schema.validate!([{first_name: 'Joe', last_name: 'Doe'}]) # => [{"first_name"=>"Joe", "last_name"=>"Doe"}]
|
906
1108
|
schema.validate!([id: 42, first_name: 'Joe']) # => Schemacop::Exceptions::ValidationError: /[0]/last_name: Value must be given. /[0]: Obsolete property "id".
|
907
1109
|
```
|
908
1110
|
|
909
1111
|
## Context
|
910
1112
|
|
911
|
-
Schemacop
|
1113
|
+
Schemacop also features the concept of a `Context`. You can define schemas in a
|
912
1114
|
context, and then reference them in other schemas in that context. This is e.g.
|
913
1115
|
useful if you need a part of the schema to be different depending on the
|
914
1116
|
business action.
|
@@ -932,7 +1134,7 @@ context.schema :PersonInfo do
|
|
932
1134
|
end
|
933
1135
|
|
934
1136
|
# Now we can define our general schema, where we reference the :Person schema.
|
935
|
-
# Note that at this point, we don't know what's in the :Person
|
1137
|
+
# Note that at this point, we don't know what's in the :Person schema.
|
936
1138
|
schema = Schemacop::Schema3.new :reference, path: :Person
|
937
1139
|
|
938
1140
|
# Validate the data in the context we defined before, where we need the first_name
|
@@ -940,7 +1142,7 @@ schema = Schemacop::Schema3.new :reference, path: :Person
|
|
940
1142
|
# of the person.
|
941
1143
|
Schemacop.with_context context do
|
942
1144
|
schema.validate!({first_name: 'Joe', last_name: 'Doe', info: { born_at: '1980-01-01'} })
|
943
|
-
# => {
|
1145
|
+
# => {"first_name"=>"Joe", "last_name"=>"Doe", "info"=>{"born_at"=>Tue, 01 Jan 1980}}
|
944
1146
|
end
|
945
1147
|
|
946
1148
|
# Now we might want another context, where the person is more anonymous, and as
|
@@ -953,7 +1155,7 @@ other_context.schema :Person do
|
|
953
1155
|
end
|
954
1156
|
|
955
1157
|
# Finally, validate the data in the new context. We do not want the real name or
|
956
|
-
# birth date of the person, instead only the nickname is allowed
|
1158
|
+
# birth date of the person, instead only the nickname is allowed.
|
957
1159
|
Schemacop.with_context other_context do
|
958
1160
|
schema.validate!({first_name: 'Joe', last_name: 'Doe', info: { born_at: '1980-01-01'} })
|
959
1161
|
# => Schemacop::Exceptions::ValidationError: /nickname: Value must be given.
|
@@ -961,7 +1163,7 @@ Schemacop.with_context other_context do
|
|
961
1163
|
# /: Obsolete property "last_name".
|
962
1164
|
# /: Obsolete property "info".
|
963
1165
|
|
964
|
-
schema.validate!({nickname: 'J.'}) # => {
|
1166
|
+
schema.validate!({nickname: 'J.'}) # => {"nickname"=>"J."}
|
965
1167
|
end
|
966
1168
|
```
|
967
1169
|
|
@@ -971,11 +1173,11 @@ to use other data in the second context than in the first.
|
|
971
1173
|
|
972
1174
|
## External schemas
|
973
1175
|
|
974
|
-
Finally,
|
975
|
-
This is especially useful is you have schemas in your application which
|
976
|
-
multiple times
|
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.
|
977
1179
|
|
978
|
-
For each schema, you define the schema in a
|
1180
|
+
For each schema, you define the schema in a separate file, and after loading the
|
979
1181
|
schemas, you can reference them in other schemas.
|
980
1182
|
|
981
1183
|
The default load path is `'app/schemas'`, but this can be configured by setting
|
@@ -989,14 +1191,17 @@ local schemas > context schemas > global schemas
|
|
989
1191
|
|
990
1192
|
Where:
|
991
1193
|
|
992
|
-
* local schemas: Defined by using the DSL method
|
1194
|
+
* local schemas: Defined by using the DSL method `scm`
|
993
1195
|
* context schemas: Defined in the current context using `context.schema`
|
994
1196
|
* global schemas: Defined in a ruby file in the load path
|
995
1197
|
|
996
1198
|
### Rails applications
|
997
1199
|
|
998
|
-
In Rails applications, your schemas are automatically eager-
|
999
|
-
path `'app/schemas'` when your application is started
|
1200
|
+
In Rails applications, your schemas are automatically eager-loaded from the load
|
1201
|
+
path `'app/schemas'` when your application is started, unless your application
|
1202
|
+
is running in the `DEVELOPMENT` environment. In the `DEVELOPMENT` environment,
|
1203
|
+
schemas are loaded each time when they are used, and as such you can make changes
|
1204
|
+
to your external schemas without having to restart the server each time.
|
1000
1205
|
|
1001
1206
|
After starting your application, you can reference them like normally defined
|
1002
1207
|
reference schemas, with the name being relative to the load path.
|
@@ -1032,20 +1237,24 @@ schema = Schemacop::Schema3.new :hash do
|
|
1032
1237
|
end
|
1033
1238
|
|
1034
1239
|
schema.validate!({usr: {first_name: 'Joe', last_name: 'Doe'}})
|
1035
|
-
# => {
|
1240
|
+
# => {"usr"=>{"first_name"=>"Joe", "last_name"=>"Doe"}}
|
1036
1241
|
|
1037
1242
|
schema.validate!({usr: {first_name: 'Joe', last_name: 'Doe', groups: []}})
|
1038
|
-
# => {
|
1243
|
+
# => {"usr"=>{"first_name"=>"Joe", "last_name"=>"Doe", "groups"=>[]}}
|
1039
1244
|
|
1040
1245
|
schema.validate!({usr: {first_name: 'Joe', last_name: 'Doe', groups: [{name: 'foo'}, {name: 'bar'}]}})
|
1041
|
-
# => {
|
1246
|
+
# => {"usr"=>{"first_name"=>"Joe", "last_name"=>"Doe", "groups"=>[{"name"=>"foo"}, {"name"=>"bar"}]}}
|
1042
1247
|
```
|
1043
1248
|
|
1044
1249
|
### Non-Rails applications
|
1045
1250
|
|
1046
1251
|
Usage in non-Rails applications is the same as with usage in Rails applications,
|
1047
|
-
however you need to eager load the schemas yourself:
|
1252
|
+
however you might need to eager load the schemas yourself:
|
1048
1253
|
|
1049
1254
|
```ruby
|
1050
1255
|
Schemacop::V3::GlobalContext.eager_load!
|
1051
|
-
```
|
1256
|
+
```
|
1257
|
+
|
1258
|
+
As mentioned before, you can also use the external schemas without having to
|
1259
|
+
eager-load them, but if you use the schemas multiple times, it might be better
|
1260
|
+
to eager-load them on start of your application / script.
|