schemacop 2.4.7 → 3.0.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (172) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.rubocop.yml +25 -1
  4. data/.travis.yml +2 -1
  5. data/CHANGELOG.md +8 -0
  6. data/README.md +41 -708
  7. data/README_V2.md +775 -0
  8. data/README_V3.md +683 -0
  9. data/Rakefile +8 -12
  10. data/VERSION +1 -1
  11. data/lib/schemacop.rb +35 -37
  12. data/lib/schemacop/base_schema.rb +37 -0
  13. data/lib/schemacop/railtie.rb +10 -0
  14. data/lib/schemacop/schema.rb +1 -60
  15. data/lib/schemacop/schema2.rb +22 -0
  16. data/lib/schemacop/schema3.rb +21 -0
  17. data/lib/schemacop/scoped_env.rb +25 -13
  18. data/lib/schemacop/v2.rb +26 -0
  19. data/lib/schemacop/{caster.rb → v2/caster.rb} +16 -2
  20. data/lib/schemacop/{collector.rb → v2/collector.rb} +5 -2
  21. data/lib/schemacop/{dupper.rb → v2/dupper.rb} +1 -1
  22. data/lib/schemacop/{field_node.rb → v2/field_node.rb} +4 -3
  23. data/lib/schemacop/v2/node.rb +142 -0
  24. data/lib/schemacop/{node_resolver.rb → v2/node_resolver.rb} +1 -1
  25. data/lib/schemacop/{node_supporting_field.rb → v2/node_supporting_field.rb} +8 -10
  26. data/lib/schemacop/{node_supporting_type.rb → v2/node_supporting_type.rb} +6 -3
  27. data/lib/schemacop/{node_with_block.rb → v2/node_with_block.rb} +3 -2
  28. data/lib/schemacop/v2/root_node.rb +6 -0
  29. data/lib/schemacop/v2/validator/array_validator.rb +32 -0
  30. data/lib/schemacop/{validator → v2/validator}/boolean_validator.rb +1 -1
  31. data/lib/schemacop/v2/validator/float_validator.rb +7 -0
  32. data/lib/schemacop/v2/validator/hash_validator.rb +37 -0
  33. data/lib/schemacop/v2/validator/integer_validator.rb +7 -0
  34. data/lib/schemacop/{validator → v2/validator}/nil_validator.rb +1 -1
  35. data/lib/schemacop/v2/validator/number_validator.rb +21 -0
  36. data/lib/schemacop/v2/validator/object_validator.rb +29 -0
  37. data/lib/schemacop/v2/validator/string_validator.rb +39 -0
  38. data/lib/schemacop/{validator → v2/validator}/symbol_validator.rb +1 -1
  39. data/lib/schemacop/v3.rb +45 -0
  40. data/lib/schemacop/v3/all_of_node.rb +27 -0
  41. data/lib/schemacop/v3/any_of_node.rb +28 -0
  42. data/lib/schemacop/v3/array_node.rb +219 -0
  43. data/lib/schemacop/v3/boolean_node.rb +16 -0
  44. data/lib/schemacop/v3/combination_node.rb +45 -0
  45. data/lib/schemacop/v3/context.rb +17 -0
  46. data/lib/schemacop/v3/dsl_scope.rb +46 -0
  47. data/lib/schemacop/v3/global_context.rb +114 -0
  48. data/lib/schemacop/v3/hash_node.rb +217 -0
  49. data/lib/schemacop/v3/integer_node.rb +13 -0
  50. data/lib/schemacop/v3/is_not_node.rb +32 -0
  51. data/lib/schemacop/v3/node.rb +214 -0
  52. data/lib/schemacop/v3/node_registry.rb +49 -0
  53. data/lib/schemacop/v3/number_node.rb +18 -0
  54. data/lib/schemacop/v3/numeric_node.rb +76 -0
  55. data/lib/schemacop/v3/object_node.rb +40 -0
  56. data/lib/schemacop/v3/one_of_node.rb +28 -0
  57. data/lib/schemacop/v3/reference_node.rb +49 -0
  58. data/lib/schemacop/v3/result.rb +58 -0
  59. data/lib/schemacop/v3/string_node.rb +124 -0
  60. data/lib/schemacop/v3/symbol_node.rb +13 -0
  61. data/schemacop.gemspec +24 -27
  62. data/test/lib/test_helper.rb +152 -0
  63. data/test/schemas/nested/group.rb +6 -0
  64. data/test/schemas/user.rb +7 -0
  65. data/test/unit/schemacop/v2/casting_test.rb +120 -0
  66. data/test/unit/schemacop/v2/collector_test.rb +47 -0
  67. data/test/unit/schemacop/v2/custom_check_test.rb +95 -0
  68. data/test/unit/schemacop/v2/custom_if_test.rb +97 -0
  69. data/test/unit/schemacop/v2/defaults_test.rb +95 -0
  70. data/test/unit/schemacop/v2/empty_test.rb +16 -0
  71. data/test/unit/schemacop/v2/nil_dis_allow_test.rb +43 -0
  72. data/test/unit/schemacop/v2/node_resolver_test.rb +28 -0
  73. data/test/unit/schemacop/v2/short_forms_test.rb +351 -0
  74. data/test/unit/schemacop/v2/types_test.rb +88 -0
  75. data/test/unit/schemacop/v2/validator_array_test.rb +99 -0
  76. data/test/unit/schemacop/v2/validator_boolean_test.rb +17 -0
  77. data/test/unit/schemacop/v2/validator_float_test.rb +59 -0
  78. data/test/unit/schemacop/v2/validator_hash_test.rb +95 -0
  79. data/test/unit/schemacop/v2/validator_integer_test.rb +48 -0
  80. data/test/unit/schemacop/v2/validator_nil_test.rb +15 -0
  81. data/test/unit/schemacop/v2/validator_number_test.rb +62 -0
  82. data/test/unit/schemacop/v2/validator_object_test.rb +141 -0
  83. data/test/unit/schemacop/v2/validator_string_test.rb +78 -0
  84. data/test/unit/schemacop/v2/validator_symbol_test.rb +18 -0
  85. data/test/unit/schemacop/v3/all_of_node_test.rb +199 -0
  86. data/test/unit/schemacop/v3/any_of_node_test.rb +218 -0
  87. data/test/unit/schemacop/v3/array_node_test.rb +805 -0
  88. data/test/unit/schemacop/v3/boolean_node_test.rb +126 -0
  89. data/test/unit/schemacop/v3/global_context_test.rb +164 -0
  90. data/test/unit/schemacop/v3/hash_node_test.rb +775 -0
  91. data/test/unit/schemacop/v3/integer_node_test.rb +323 -0
  92. data/test/unit/schemacop/v3/is_not_node_test.rb +173 -0
  93. data/test/unit/schemacop/v3/node_test.rb +148 -0
  94. data/test/unit/schemacop/v3/number_node_test.rb +292 -0
  95. data/test/unit/schemacop/v3/object_node_test.rb +170 -0
  96. data/test/unit/schemacop/v3/one_of_node_test.rb +187 -0
  97. data/test/unit/schemacop/v3/reference_node_test.rb +351 -0
  98. data/test/unit/schemacop/v3/string_node_test.rb +334 -0
  99. data/test/unit/schemacop/v3/symbol_node_test.rb +75 -0
  100. metadata +152 -145
  101. data/doc/Schemacop.html +0 -146
  102. data/doc/Schemacop/ArrayValidator.html +0 -329
  103. data/doc/Schemacop/BooleanValidator.html +0 -145
  104. data/doc/Schemacop/Caster.html +0 -379
  105. data/doc/Schemacop/Collector.html +0 -787
  106. data/doc/Schemacop/Dupper.html +0 -214
  107. data/doc/Schemacop/Exceptions.html +0 -115
  108. data/doc/Schemacop/Exceptions/InvalidSchemaError.html +0 -124
  109. data/doc/Schemacop/Exceptions/ValidationError.html +0 -124
  110. data/doc/Schemacop/FieldNode.html +0 -421
  111. data/doc/Schemacop/FloatValidator.html +0 -158
  112. data/doc/Schemacop/HashValidator.html +0 -293
  113. data/doc/Schemacop/IntegerValidator.html +0 -158
  114. data/doc/Schemacop/NilValidator.html +0 -145
  115. data/doc/Schemacop/Node.html +0 -1438
  116. data/doc/Schemacop/NodeResolver.html +0 -258
  117. data/doc/Schemacop/NodeSupportingField.html +0 -590
  118. data/doc/Schemacop/NodeSupportingType.html +0 -612
  119. data/doc/Schemacop/NodeWithBlock.html +0 -289
  120. data/doc/Schemacop/NumberValidator.html +0 -232
  121. data/doc/Schemacop/ObjectValidator.html +0 -298
  122. data/doc/Schemacop/RootNode.html +0 -171
  123. data/doc/Schemacop/Schema.html +0 -699
  124. data/doc/Schemacop/StringValidator.html +0 -295
  125. data/doc/Schemacop/SymbolValidator.html +0 -145
  126. data/doc/ScopedEnv.html +0 -351
  127. data/doc/_index.html +0 -379
  128. data/doc/class_list.html +0 -51
  129. data/doc/css/common.css +0 -1
  130. data/doc/css/full_list.css +0 -58
  131. data/doc/css/style.css +0 -496
  132. data/doc/file.README.html +0 -833
  133. data/doc/file_list.html +0 -56
  134. data/doc/frames.html +0 -17
  135. data/doc/index.html +0 -833
  136. data/doc/inheritance.graphml +0 -524
  137. data/doc/inheritance.pdf +0 -825
  138. data/doc/js/app.js +0 -303
  139. data/doc/js/full_list.js +0 -216
  140. data/doc/js/jquery.js +0 -4
  141. data/doc/method_list.html +0 -587
  142. data/doc/top-level-namespace.html +0 -112
  143. data/lib/schemacop/node.rb +0 -139
  144. data/lib/schemacop/root_node.rb +0 -4
  145. data/lib/schemacop/validator/array_validator.rb +0 -30
  146. data/lib/schemacop/validator/float_validator.rb +0 -5
  147. data/lib/schemacop/validator/hash_validator.rb +0 -35
  148. data/lib/schemacop/validator/integer_validator.rb +0 -5
  149. data/lib/schemacop/validator/number_validator.rb +0 -19
  150. data/lib/schemacop/validator/object_validator.rb +0 -27
  151. data/lib/schemacop/validator/string_validator.rb +0 -37
  152. data/test/casting_test.rb +0 -118
  153. data/test/collector_test.rb +0 -45
  154. data/test/custom_check_test.rb +0 -93
  155. data/test/custom_if_test.rb +0 -95
  156. data/test/defaults_test.rb +0 -93
  157. data/test/empty_test.rb +0 -14
  158. data/test/nil_dis_allow_test.rb +0 -41
  159. data/test/node_resolver_test.rb +0 -26
  160. data/test/short_forms_test.rb +0 -349
  161. data/test/test_helper.rb +0 -13
  162. data/test/types_test.rb +0 -84
  163. data/test/validator_array_test.rb +0 -97
  164. data/test/validator_boolean_test.rb +0 -15
  165. data/test/validator_float_test.rb +0 -57
  166. data/test/validator_hash_test.rb +0 -93
  167. data/test/validator_integer_test.rb +0 -46
  168. data/test/validator_nil_test.rb +0 -13
  169. data/test/validator_number_test.rb +0 -60
  170. data/test/validator_object_test.rb +0 -139
  171. data/test/validator_string_test.rb +0 -76
  172. data/test/validator_symbol_test.rb +0 -16
@@ -0,0 +1,683 @@
1
+ # Schemacop schema V3
2
+
3
+ Please note that Schemacop v3 is still a work in progress, especially the documentation.
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)
13
+ 1. [String](#string)
14
+ 2. [Integer](#integer)
15
+ 3. [Number](#number)
16
+ 4. [Symbol](#symbol)
17
+ 5. [Boolean](#boolean)
18
+ 6. [Array](#array)
19
+ 7. [Hash](#hash)
20
+ 8. [Object](#object)
21
+ 9. [AllOf](#allOf)
22
+ 10. [AnyOf](#anyOf)
23
+ 11. [OneOf](#oneOf)
24
+ 12. [IsNot](#isNot)
25
+ 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
32
+
33
+ ## Validation
34
+
35
+ Using schemacop, you can either choose to validate the data either using the
36
+ graceful `validate` method, or the bang variant, `validate!`.
37
+
38
+ The `validate` method on a schema with some supplied data will return a
39
+ `Schemacop::Result` object, which has some useful methods to work with the
40
+ data you validated.
41
+
42
+ ```ruby
43
+ schema = Schemacop::Schema3.new :string, format: :date
44
+ result = schema.validate('2020-01-01')
45
+ result.class # => Schemacop::Result
46
+ ```
47
+
48
+ With the `data` method, you can access the casted version of your data:
49
+
50
+ ```ruby
51
+ schema = Schemacop::Schema3.new :string, format: :date
52
+ result = schema.validate('2020-01-01')
53
+ result.data # => Wed, 01 Jan 2020
54
+ ```
55
+
56
+ And with the `valid?` method, you can check if the supplied data validates
57
+ against the schema:
58
+
59
+ ```ruby
60
+ schema = Schemacop::Schema3.new :string, format: :date
61
+ result = schema.validate('2020-01-01')
62
+ result.valid? # => true
63
+ ```
64
+
65
+ On the other hand, the `validate!` method either returns the casted data if the
66
+ validation was successful, or if the validation failed, raises a
67
+ `Schemacop::Exceptions::ValidationError` exception:
68
+
69
+ ```ruby
70
+ schema = Schemacop::Schema3.new :string, format: :date
71
+ schema.validate!('2020-01-01') # => Wed, 01 Jan 2020
72
+ schema.validate!('Foo') # => Schemacop::Exceptions::ValidationError: /: String does not match format "date".
73
+ ```
74
+
75
+ ## Exceptions
76
+
77
+ TODO: Describe the exceptions raised by schemacop
78
+
79
+ `Schemacop::Exceptions::ValidationError`
80
+ `Schemacop::Exceptions::InvalidSchemaError`
81
+
82
+ ## Generic Keywords
83
+
84
+ TODO: Complete this
85
+
86
+ * enum
87
+ * title
88
+ * description
89
+ * examples
90
+
91
+ ## Nodes
92
+
93
+ ### String
94
+
95
+ Type: `:string`\
96
+ DSL: `str`
97
+
98
+ The string type is used for strings of text and must be a ruby `String` object
99
+ or a subclass. Using the option `format`, strings can be validated against and
100
+ transformed into various types.
101
+
102
+ #### Options
103
+
104
+ * `min_length`
105
+ Defines the minimum required string length
106
+ * `max_length`
107
+ Defines the maximum required string length
108
+ * `pattern`
109
+ Defines a (ruby) regex pattern the value will be matched against. Must be a
110
+ string and should generally start with `^` and end with `$` so as to evaluate
111
+ the entire string. It should not be enclosed in `/` characters.
112
+ * `format`
113
+ The `format` option allows for basic semantic validation on certain kinds of
114
+ string values that are commonly used. See section *formats* for more
115
+ information on the available formats. Note that strings with a format are also
116
+ **casted** into that format.
117
+
118
+ #### Formats
119
+
120
+ * `date`
121
+ A date according to [ RFC 3339, section
122
+ 5.6.](https://json-schema.org/latest/json-schema-validation.html#RFC3339) date
123
+ format, i.e. `2018-11-13`. Strings with this format will be
124
+ casted to a ruby `Date` object.
125
+
126
+ * `date_time`
127
+ A date time according to [RFC 3339, section
128
+ 5.6.](https://json-schema.org/latest/json-schema-validation.html#RFC3339) date
129
+ format, i.e. `2018-11-13T20:20:39+00:00`. Strings with this format will be
130
+ casted to a ruby `DateTime` object. The time zones will be inferred by the
131
+ string.
132
+
133
+ * `email`
134
+ Validates for a valid email address. There is no casting involved since email
135
+ addresses do not have their own ruby type.
136
+
137
+ * `boolean`
138
+ The string must be either `true` or `false`. This value will be casted to
139
+ ruby's `TrueClass` or `FalseClass`.
140
+
141
+ * `binary`
142
+ The string is expected to contain binary contents. No casting or additional
143
+ validation is performed.
144
+
145
+ * `integer`
146
+ The string must be an integer and will be casted to a ruby `Integer` object.
147
+
148
+ * `number`
149
+ The string must be a number and will be casted to a ruby `Float` object.
150
+
151
+ #### Examples
152
+
153
+ ```ruby
154
+ # By using a format, string values are casted to that respective format
155
+ schema = Schemacop::Schema3.new(:string, format: :date)
156
+ result = schema.validate('1980-01-13')
157
+ result.data # => Date<"Sun, 13 Jan 1980">
158
+ ```
159
+
160
+ ### Integer
161
+
162
+ Type: `:integer`\
163
+ DSL: `int`
164
+
165
+ The integer type is used for whole numbers and must be a ruby `Integer` or a
166
+ subclass. With the various available options, validations on the value of the
167
+ integer can be done.
168
+
169
+ #### Options
170
+
171
+ * `minimum`
172
+ Defines an (inclusive) minimum, i.e. the number has to be equal or larger than the
173
+ given number
174
+ * `exclusive_minimum`
175
+ Defines an exclusive minimum, i.e. the number has to larger than the given number
176
+ * `maximum`
177
+ Defines an (inclusive) maximum, i.e. the number has to be equal or smaller than the
178
+ given number
179
+ * `exclusive_maximum`
180
+ Defines an exclusive maximum, i.e. the number has to smaller than the given number
181
+ * `multiple_of`
182
+ The received number has to be a multiple of the given number for the validation to
183
+ pass.
184
+
185
+ #### Examples
186
+
187
+ ```ruby
188
+ # Validates that the input is an even number between 0 and 100 (inclusive)
189
+ schema = Schemacop::Schema3.new(:integer, minimum: 0, maximum: 100, multiple_of: 2)
190
+ schema.validate!(42) # => 42
191
+ schema.validate!(43) # => Schemacop::Exceptions::ValidationError: /: Value must be a multiple of 2.
192
+ schema.validate!(-2) # => Schemacop::Exceptions::ValidationError: /: Value must have a minimum of 0.
193
+ schema.validate!(102) # => Schemacop::Exceptions::ValidationError: /: Value must have a maximum of 100.
194
+ schema.validate!(42.1) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "integer".
195
+ schema.validate!(4r) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "integer".
196
+ schema.validate!((4 + 0i)) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "integer".
197
+ schema.validate!(BigDecimal(5)) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "integer".
198
+ ```
199
+
200
+ ### Number
201
+
202
+ Type: `:number`\
203
+ DSL: `num`
204
+
205
+ The number type is used to validate various number classes. The following ruby classes
206
+ and subclasses are valid:
207
+
208
+ * `Integer`
209
+ * `Float`
210
+ * `Rational`
211
+ * `BigDecimal`
212
+
213
+ As some subclasses of `Numeric`, such as `Complex` don't support all required oeprations,
214
+ only the above list is supported. If you need support for additional number classes, please
215
+ contact the Gem maintainers.
216
+
217
+ With the various available options, validations on the value of the number can be done.
218
+
219
+ #### Options
220
+
221
+ * `minimum`
222
+ Defines an (inclusive) minimum, i.e. the number has to be equal or larger than the
223
+ given number
224
+ * `exclusive_minimum`
225
+ Defines an exclusive minimum, i.e. the number has to larger than the given number
226
+ * `maximum`
227
+ Defines an (inclusive) maximum, i.e. the number has to be equal or smaller than the
228
+ given number
229
+ * `exclusive_maximum`
230
+ Defines an exclusive maximum, i.e. the number has to smaller than the given number
231
+ * `multiple_of`
232
+ The received number has to be a multiple of the given number for the validation to
233
+ pass.
234
+
235
+ #### Examples
236
+
237
+ ```ruby
238
+ # Validates that the input is a number between 0 and 50 (inclusive) and a multiple of 0.5
239
+ schema = Schemacop::Schema3.new(:number, minimum: 0.0, maximum: (50r), multiple_of: BigDecimal('0.5'))
240
+ schema.validate!(42) # => 42
241
+ schema.validate!(42.2) # => Schemacop::Exceptions::ValidationError: /: Value must be a multiple of 0.5.
242
+ schema.validate!(-2) # => Schemacop::Exceptions::ValidationError: /: Value must have a minimum of 0.0.
243
+ schema.validate!(51) # => Schemacop::Exceptions::ValidationError: /: Value must have a maximum of 50/1.
244
+ schema.validate!(42.5) # => 42.5
245
+ schema.validate!(1.5r) # => (3/2)
246
+ schema.validate!(BigDecimal(5)) # => 0.5e1
247
+ schema.validate!((4 + 0i)) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "big_decimal" or "float" or "integer" or "rational".
248
+ ```
249
+
250
+ ### Symbol
251
+
252
+ Type: `:symbol`\
253
+ DSL: `sym`
254
+
255
+ The symbol type is used to validate elements for the Ruby `Symbol` class.
256
+
257
+ #### Examples
258
+
259
+ ```ruby
260
+ # Validates that the input is a symbol
261
+ schema = Schemacop::Schema3.new(:symbol)
262
+ schema.validate!(:foo) # => :foo
263
+ schema.validate!('foo') # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "Symbol".
264
+ schema.validate!(123) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "Symbol".
265
+ schema.validate!(false) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "Symbol".
266
+ ```
267
+
268
+ ### Boolean
269
+
270
+ Type: `:boolean`\
271
+ DSL: `boo`
272
+
273
+ The boolean type is used to validate Ruby booleans, i.e. the `TrueClass` and `FalseClass`
274
+
275
+ #### Examples
276
+
277
+ ```ruby
278
+ # Validates that the input is a boolean
279
+ schema = Schemacop::Schema3.new(:boolean)
280
+ schema.validate!(true) # => true
281
+ schema.validate!(false) # => false
282
+ schema.validate!(:false) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "boolean".
283
+ schema.validate!('false') # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "boolean".
284
+ schema.validate!(1234) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "boolean".
285
+ ```
286
+
287
+ ### Array
288
+
289
+ Type: `:array`\
290
+ DSL: `arr`
291
+
292
+ The array type represents a ruby `Array`.
293
+ It consists of one or multiple values, which can be validated using arbitrary nodes.
294
+
295
+ #### Options
296
+
297
+ * `min_items`
298
+ This option specifies the (inclusive) minimum number of elements the array
299
+ must contain to pass the validation.
300
+
301
+ * `max_items`
302
+ This option specifies the (inclusive) maximum number of elements the array
303
+ must contain to pass the validation.
304
+
305
+ * `unique_items`
306
+ This option specifies wether the items in the array must all be distinct from
307
+ each other, or if there may be duplicate values. By default, this is false,
308
+ i.e. duplicate values are allowed
309
+
310
+ #### Specifying properties
311
+
312
+ Array nodes support a block in which you can specify the required array contents.
313
+ The array nodes support either list validation, or tuple validation, depending on
314
+ how you specify your array contents.
315
+
316
+ ##### List validation
317
+
318
+ List validation validates a sequence of arbitrary length where each item matches
319
+ 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`).
323
+
324
+ For example, you can specify that you want an array with only integers between 1 and 5:
325
+
326
+ ```ruby
327
+ schema = Schemacop::Schema3.new :array do
328
+ list :integer, minimum: 1, maximum: 5
329
+ end
330
+
331
+ schema.validate!([]) # => []
332
+ schema.validate!([1, 3]) # => [1, 3]
333
+ schema.validate!([0, 6]) # => Schemacop::Exceptions::ValidationError: /[0]: Value must have a minimum of 1. /[1]: Value must have a maximum of 5.
334
+ schema.validate! ['foo'] # => Schemacop::Exceptions::ValidationError: /[0]: Invalid type, expected "integer".
335
+ ```
336
+
337
+ You can also build more complex structures, e.g. an array containing an arbitrary
338
+ number of integer arrays:
339
+
340
+ ```ruby
341
+ schema = Schemacop::Schema3.new :array do
342
+ list :array do
343
+ list :integer
344
+ end
345
+ end
346
+
347
+ schema.validate!([]) # => []
348
+ schema.validate!([[1], [2, 3]]) # => [[1], [2, 3]]
349
+ schema.validate!([['foo'], [2, 3]]) # => Schemacop::Exceptions::ValidationError: /[0]/[0]: Invalid type, expected "integer".
350
+ ```
351
+
352
+ Please note that you can only specify *one* `list` item:
353
+
354
+ ```ruby
355
+ schema = Schemacop::Schema3.new :array do
356
+ list :integer
357
+ list :string
358
+ end
359
+
360
+ # => Schemacop::Exceptions::InvalidSchemaError: You can only use "list" once.
361
+ ```
362
+
363
+ ##### Tuple validation
364
+
365
+ On the other hand, tuple validation validates a sequence of fixed length, where
366
+ each item has its own schema that it has to match. Here, the order of the items
367
+ is relevant for the validation.
368
+
369
+ For example, we want a tuple with an int, followed by a string:
370
+
371
+ ```ruby
372
+ schema = Schemacop::Schema3.new :array do
373
+ int
374
+ str
375
+ end
376
+
377
+ schema.validate!([]) # => Schemacop::Exceptions::ValidationError: /: Array has 0 items but must have exactly 2.
378
+ schema.validate!([1, 'foo']) # => [1, "foo"]
379
+ schema.validate!([1, 'foo', 'bar']) # => Schemacop::Exceptions::ValidationError: /: Array has 3 items but must have exactly 2.
380
+ ```
381
+
382
+ When using tuple validation, you can also allow additional items in the array
383
+ *after* the specified items, either with the option `additional_items` or the
384
+ DSL method `add`. With the option `additional_items` set to `true`, you can
385
+ allow any additional items:
386
+
387
+ ```ruby
388
+ schema = Schemacop::Schema3.new :array, additional_items: true do
389
+ int
390
+ str
391
+ end
392
+
393
+ schema.validate!([]) # => Schemacop::Exceptions::ValidationError: /: Array has 0 items but must have exactly 2.
394
+ schema.validate!([1, 'foo']) # => [1, "foo"]
395
+ schema.validate!([1, 'foo', 'bar']) # => [1, "foo", "bar"]
396
+ ```
397
+
398
+ You can also use the dsl method `add` to specify more exactly what type the
399
+ of the additional items may be. As with any other dsl method, you may specify
400
+ and valid schema which the additional items will be validated against:
401
+
402
+ ```ruby
403
+ schema = Schemacop::Schema3.new :array do
404
+ int
405
+ str
406
+ add :integer
407
+ end
408
+
409
+ schema.validate!([]) # => Schemacop::Exceptions::ValidationError: /: Array has 0 items but must have exactly 2.
410
+ schema.validate!([1, 'foo']) # => [1, "foo"]
411
+ schema.validate!([1, 'foo', 'bar']) # => Schemacop::Exceptions::ValidationError: /[2]: Invalid type, expected "integer".
412
+ schema.validate!([1, 'foo', 2, 3]) # => [1, "foo", 2, 3]
413
+ ```
414
+
415
+ Please note, that you cannot use multiple `add` in the same array schema, this will result in
416
+ an exception:
417
+
418
+ ```ruby
419
+ schema = Schemacop::Schema3.new :array do
420
+ int
421
+ add :integer
422
+ add :string
423
+ end
424
+
425
+ # => Schemacop::Exceptions::InvalidSchemaError: You can only use "add" once to specify additional items.
426
+ ```
427
+
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:
431
+
432
+ ```ruby
433
+ schema = Schemacop::Schema3.new :array do
434
+ int
435
+ add :one_of do
436
+ int
437
+ str
438
+ end
439
+ end
440
+ ```
441
+
442
+ #### Contains
443
+
444
+ TODO: Describe `cont` DSL method
445
+
446
+ ### Hash
447
+
448
+ Type: `:hash`\
449
+ DSL: `hsh`
450
+
451
+ The hash type represents a ruby `Hash` or an `object` in JSON schema language.
452
+ It consists of key-value-pairs that can be validated using arbitrary nodes.
453
+
454
+ #### Options
455
+
456
+ * `additional_properties` TODO: Check this
457
+ 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.
460
+
461
+ * `property_names`
462
+ This option allows to specify a regexp pattern (as string) which validates the
463
+ keys of any properties that are not specified in the hash. This option only
464
+ makes sense if `additional_properties` is enabled.
465
+
466
+ * `min_properties`
467
+ Specifies the (inclusive) minimum number of properties a hash must contain.
468
+
469
+ * `max_properties`
470
+ Specifies the (inclusive) maximum number of properties a hash must contain.
471
+
472
+ #### Specifying properties
473
+
474
+ Hash nodes support a block in which you can specify the required hash contents.
475
+
476
+ ##### Standard properties
477
+
478
+ It supports all type nodes, but requires the suffix `?` or `!` for each
479
+ property, which specifies whether a property is required (`!`) or optional
480
+ (`?`).
481
+
482
+ ```ruby
483
+ str! :my_required_property
484
+ int! :my_optional_property
485
+ ```
486
+
487
+ ##### Pattern properties
488
+
489
+ In addition to symbols, property keys can also be a regular expression:
490
+
491
+ ```ruby
492
+ Schemacop::Schema3.new do
493
+ str! :name
494
+
495
+ # The following statement allows any number of integer properties of which the
496
+ # name starts with `id_`.
497
+ int! /^id_.*$/
498
+ end
499
+ ```
500
+
501
+ For example, the above example would successfully validate the following hash:
502
+
503
+ ```ruby
504
+ { name: 'John Doe', id_a: 42, id_b: 42 }
505
+ ```
506
+
507
+ ##### Additional properties & property names
508
+
509
+ In addition to standard properties, you can allow the hash to contain
510
+ additional, unspecified properties. By default, this is turned off if you have
511
+ defined at least one standard property.
512
+
513
+ 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:
517
+
518
+ ```ruby
519
+ Schemacop::Schema3.new do
520
+ int! :id
521
+
522
+ # 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
526
+ end
527
+ ```
528
+
529
+ Using the option `property_names`, you can additionaly specify a pattern that
530
+ any additional property **keys** must adhere to:
531
+
532
+ ```ruby
533
+ # The following schema allows any number of properties, but all keys must
534
+ # consist of downcase letters from a-z.
535
+ Schemacop::Schema3.new additional_properties: :true, property_names: '^[a-z]+$'
536
+
537
+ # The following schema allows any number of properties, but all keys must
538
+ # 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
540
+ add :array
541
+ end
542
+ ```
543
+
544
+ ##### Dependencies
545
+
546
+ Using the DSL method `dep`, you can specifiy (non-nested) property dependencies:
547
+
548
+ ```ruby
549
+ # In this example, `billing_address` and `phone_number` are required if
550
+ # `credit_card` is given, and `credit_card` is required if `billing_address` is
551
+ # given.
552
+ Schemacop::Schema3.new do
553
+ str! :name
554
+ str? :credit_card
555
+ str? :billing_address
556
+ str? :phone_number
557
+
558
+ dep :credit_card, :billing_address, :phone_number
559
+ dep :billing_address, :credit_card
560
+ end
561
+ ```
562
+
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
572
+
573
+ int? :id
574
+ str! :name
575
+
576
+ # Reference above defined schema 'address' and use it for key 'address'
577
+ ref! :address, :address
578
+
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 }
585
+
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
592
+
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
611
+ ```
612
+
613
+ ```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
623
+
624
+ # Allow any hash with any contents.
625
+ Schemacop::Schema3.new(additional_properties: true)
626
+
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
632
+
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
638
+
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
645
+
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
653
+ ```
654
+
655
+ ### Object
656
+
657
+ Type: `:object`\
658
+ DSL: `obj`
659
+
660
+ ### AllOf
661
+
662
+ Type: `:all_of`\
663
+ DSL: `all_of`
664
+
665
+ ### AnyOf
666
+
667
+ Type: `:any_of`\
668
+ DSL: `any_of`
669
+
670
+ ### OneOf
671
+
672
+ Type: `:one_of`\
673
+ DSL: `one_of`
674
+
675
+ ### IsNot
676
+
677
+ Type: `:is_not`\
678
+ DSL: `is_not`
679
+
680
+ ### Reference
681
+
682
+ DSL: `ref`
683
+