schemacop 3.0.3 → 3.0.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8beb01b4d3fc6d20f2179d2e44086b534d50b673248635d19782fba609737ce3
4
- data.tar.gz: e905b06d0f7bed58cf5a1247a4ec4a201fe053241516aa6269275b87ef41ba31
3
+ metadata.gz: f11e7ce866105fc0749471f503ec88accb8307fdbef31ed417b675e29fa1141e
4
+ data.tar.gz: 400dfe76003e347560eaab180a6df3df073bc8ec1930edad3395331c494ce6e8
5
5
  SHA512:
6
- metadata.gz: 2418e8eacb3854f85b8fa4689d3a4819d4b6ff76aedb0910c5e7b2f41566d15339347e5890e46588f4d8859f79594bd049988d669e9c3486d4bef4db06733fa7
7
- data.tar.gz: 26e0d958b4509fa5376703d17bc00ca05d28fc39fc631a26e2444356065e3c2f80982aa8411b89d197bccafa4a18023aaf3933221be347e1030973e8f64af5e4
6
+ metadata.gz: 5bd90d0c7de2ca4c48626b6410eb8f7711a8ad6e179e1a4f96ac92890da8f2cac113ec495ff1af7335365a0e32ea7f528ce7f141a7973f5c7779615ab84929b7
7
+ data.tar.gz: f6dee225eecc7ae469ac1162f08b2a6108bc5625629077b317e0b378bd6dd953417d6d5b463fdb62ad1ee8a61275a8cca7eabad4862abfff27503b5d998328f5
data/.releaser_config CHANGED
@@ -1,3 +1,4 @@
1
1
  version_file: VERSION
2
2
  always_from_master: true
3
3
  gem_style: github
4
+ ruby_command: ruby -S
data/CHANGELOG.md CHANGED
@@ -1,14 +1,40 @@
1
1
  # Change log
2
2
 
3
- <!--
4
- ## master (unreleased)
3
+ ## 3.0.8 (2021-02-23)
5
4
 
6
- ### New features
5
+ * Fix `object` nodes in hashes with no classes
7
6
 
8
- ### Bug fixes
7
+ * Document `cast_str` option
9
8
 
10
- ### Changes
11
- -->
9
+ ## 3.0.7 (2021-02-22)
10
+
11
+ * Adapt schema definitions handling when using Swagger-standard JSON
12
+
13
+ ## 3.0.6 (2021-02-14)
14
+
15
+ * Remove option `json_format` from {Schemacop::Schema3.as_json as_json} again.
16
+ If you need to use the swagger format, use
17
+ {Schemacop::V3::Context.with_json_format} instead.
18
+
19
+ * Rename `Schemacop::V3::Context.spawn_with` to
20
+ {Schemacop::V3::Context.with_json_format} and make keyword argument
21
+ `json_format` a positional argument.
22
+
23
+ ## 3.0.5 (2021-02-14)
24
+
25
+ * Allow option `pattern` to be a `Regexp` for `string` (`str`) nodes
26
+
27
+ * Remove `examples_keyword` from context again
28
+
29
+ * Add option `json_format` to {Schemacop::Schema3.as_json as_json}. This allows
30
+ generating a JSON schema that is [specific to
31
+ swagger](https://swagger.io/docs/specification/data-models/keywords/) by
32
+ passing `:swagger` to it.
33
+
34
+ ## 3.0.4 (2021-02-15)
35
+
36
+ * Add `examples_keyword` to context which allows to customize the name of the
37
+ `examples` attribute in JSON output
12
38
 
13
39
  ## 3.0.3 (2021-02-15)
14
40
 
data/README_V3.md CHANGED
@@ -199,9 +199,10 @@ transformed into various types.
199
199
  * `max_length`
200
200
  Defines the (inclusive) maximum required string length
201
201
  * `pattern`
202
- Defines a (ruby) regex pattern the value will be matched against. Must be a
203
- string and should generally start with `^` and end with `$` so as to evaluate
204
- the entire string. It should not be enclosed in `/` characters.
202
+ Defines a (ruby) regex pattern the value will be matched against. Must be either
203
+ a string which should not be enclosed in `/` characters, or a Ruby Regexp.
204
+ The pattern should generally start with `^` and end with `$` so as to evaluate
205
+ the entire string.
205
206
  * `format`
206
207
  The `format` option allows for basic semantic validation on certain kinds of
207
208
  string values that are commonly used. See section *formats* for more
@@ -277,6 +278,10 @@ integer can be done.
277
278
  * `multiple_of`
278
279
  The received number has to be a multiple of the given number for the validation to
279
280
  pass.
281
+ * `cast_str`
282
+ When set to `true`, this node also accepts strings that can be casted to an integer, e.g.
283
+ the values `'-5'` or `'42'`. Please note that you can only validate numbers which
284
+ are in the `Integer` format.
280
285
 
281
286
  #### Examples
282
287
 
@@ -293,6 +298,20 @@ schema.validate!((4 + 0i)) # => Schemacop::Exceptions::ValidationError: /:
293
298
  schema.validate!(BigDecimal(5)) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "integer".
294
299
  ```
295
300
 
301
+ With `cast_str` enabled:
302
+
303
+ ```ruby
304
+ # Validates that the input is an even number between 0 and 100 (inclusive)
305
+ schema = Schemacop::Schema3.new(:integer, minimum: 0, maximum: 100, multiple_of: 2, cast_str: true)
306
+ schema.validate!('42') # => 42
307
+ schema.validate!('43') # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
308
+ schema.validate!('-2') # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
309
+ schema.validate!('102') # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
310
+ schema.validate!('42.1') # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
311
+ schema.validate!('4r') # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
312
+ schema.validate!('(4 + 0i)') # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
313
+ ```
314
+
296
315
  ### Number
297
316
 
298
317
  Type: `:number`\
@@ -327,6 +346,11 @@ With the various available options, validations on the value of the number can b
327
346
  * `multiple_of`
328
347
  The received number has to be a multiple of the given number for the validation to
329
348
  pass.
349
+ * `cast_str`
350
+ When set to `true`, this node also accepts strings that can be casted to a number, e.g.
351
+ the values `'0.1'` or `'3.1415'`. Please note that you can only validate numbers which
352
+ are in the `Integer` or `Float` format, i.e. values like `'1.5r'` or `'(4 + 0i)'` will
353
+ not work.
330
354
 
331
355
  #### Examples
332
356
 
@@ -343,6 +367,19 @@ schema.validate!(BigDecimal(5)) # => 0.5e1
343
367
  schema.validate!((4 + 0i)) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "big_decimal" or "float" or "integer" or "rational".
344
368
  ```
345
369
 
370
+ With `cast_str` enabled:
371
+
372
+ ```ruby
373
+ schema = Schemacop::Schema3.new(:number, cast_str: true, minimum: 0.0, maximum: (50r), multiple_of: BigDecimal('0.5'))
374
+ schema.validate!('42') # => 42
375
+ schema.validate!('42.2') # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
376
+ schema.validate!('-2') # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
377
+ schema.validate!('51') # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
378
+ schema.validate!('42.5') # => 42.5
379
+ schema.validate!('1.5r') # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
380
+ schema.validate!('(4 + 0i)') # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
381
+ ```
382
+
346
383
  ### Symbol
347
384
 
348
385
  Type: `:symbol`\
@@ -350,15 +387,33 @@ DSL: `sym`
350
387
 
351
388
  The symbol type is used to validate elements for the Ruby `Symbol` class.
352
389
 
390
+ #### Options
391
+
392
+ * `cast_str`
393
+ When set to `true`, this node also accepts strings that can be casted to a symbol.
394
+
353
395
  #### Examples
354
396
 
355
397
  ```ruby
356
398
  # Validates that the input is a symbol
357
399
  schema = Schemacop::Schema3.new(:symbol)
358
- schema.validate!(:foo) # => :foo
359
- schema.validate!('foo') # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "Symbol".
360
- schema.validate!(123) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "Symbol".
361
- schema.validate!(false) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "Symbol".
400
+ schema.validate!(:foo) # => :foo
401
+ schema.validate!('foo') # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "Symbol".
402
+ schema.validate!(123) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "Symbol".
403
+ schema.validate!(false) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "Symbol".
404
+ schema.validate!(:false) # => :false
405
+ ```
406
+
407
+ With `cast_str` enabled:
408
+
409
+ ```ruby
410
+ # Validates that the input is a symbol
411
+ schema = Schemacop::Schema3.new(:symbol, cast_str: true)
412
+ schema.validate!(':foo') # => :":foo"
413
+ schema.validate!('foo') # => :foo
414
+ schema.validate!('123') # => :"123"
415
+ schema.validate!('false') # => :false
416
+ schema.validate!(':false') # => :":false"
362
417
  ```
363
418
 
364
419
  ### Boolean
@@ -368,6 +423,12 @@ DSL: `boo`
368
423
 
369
424
  The boolean type is used to validate Ruby booleans, i.e. the `TrueClass` and `FalseClass`
370
425
 
426
+ #### Options
427
+
428
+ * `cast_str`
429
+ When set to `true`, this node also accepts strings that can be casted to a boolean, i.e.
430
+ the values `'true'` and `'false'`
431
+
371
432
  #### Examples
372
433
 
373
434
  ```ruby
@@ -380,6 +441,17 @@ schema.validate!('false') # => Schemacop::Exceptions::ValidationError: /: Invali
380
441
  schema.validate!(1234) # => Schemacop::Exceptions::ValidationError: /: Invalid type, expected "boolean".
381
442
  ```
382
443
 
444
+ With `cast_str` enabled:
445
+
446
+ ```ruby
447
+ schema = Schemacop::Schema3.new(:boolean, cast_str: true)
448
+ schema.validate!(true) # => true
449
+ schema.validate!(false) # => false
450
+ schema.validate!(:false) # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
451
+ schema.validate!('false') # => false
452
+ schema.validate!(1234) # => Schemacop::Exceptions::ValidationError: /: Matches 0 definitions but should match exactly 1.
453
+ ```
454
+
383
455
  ### Array
384
456
 
385
457
  Type: `:array`\
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.3
1
+ 3.0.8
data/lib/schemacop/v3.rb CHANGED
@@ -3,6 +3,24 @@ module Schemacop
3
3
  def self.register(*args)
4
4
  NodeRegistry.register(*args)
5
5
  end
6
+
7
+ # @private
8
+ def self.sanitize_exp(exp)
9
+ return exp if exp.is_a?(String)
10
+
11
+ _start_slash, caret, exp, dollar, _end_slash, flags = exp.inspect.match(%r{^(/?)(\^)?(.*?)(\$)?(/?)([ixm]*)?$}).captures
12
+ flags = flags.split('')
13
+
14
+ if flags.delete('i')
15
+ exp = "(?i)(#{exp})"
16
+ end
17
+
18
+ if flags.any?
19
+ fail "Flags #{flags.inspect} are not supported by Schemacop."
20
+ end
21
+
22
+ return "#{caret}#{exp}#{dollar}"
23
+ end
6
24
  end
7
25
  end
8
26
 
@@ -19,6 +19,10 @@ module Schemacop
19
19
  default
20
20
  end
21
21
  end
22
+
23
+ def self.allowed_options
24
+ super + %i[cast_str]
25
+ end
22
26
  end
23
27
  end
24
28
  end
@@ -2,9 +2,13 @@ module Schemacop
2
2
  module V3
3
3
  class Context
4
4
  attr_accessor :schemas
5
+ attr_accessor :json_format
5
6
 
6
- def initialize
7
+ DEFAULT_JSON_FORMAT = :default
8
+
9
+ def initialize(json_format: DEFAULT_JSON_FORMAT)
7
10
  @schemas = {}.with_indifferent_access.freeze
11
+ @json_format = json_format
8
12
  end
9
13
 
10
14
  def schema(name, type = :hash, **options, &block)
@@ -12,6 +16,18 @@ module Schemacop
12
16
  name => Node.create(type, **options, &block)
13
17
  ).freeze
14
18
  end
19
+
20
+ def with_json_format(json_format)
21
+ prev_json_format = @json_format
22
+ @json_format = json_format
23
+ return yield
24
+ ensure
25
+ @json_format = prev_json_format
26
+ end
27
+
28
+ def swagger_json?
29
+ @json_format == :swagger
30
+ end
15
31
  end
16
32
  end
17
33
  end
@@ -21,14 +21,6 @@ module Schemacop
21
21
  super + NodeRegistry.dsl_methods(true) + %i[dsl_dep dsl_add]
22
22
  end
23
23
 
24
- def self.sanitize_exp(exp)
25
- exp = exp.to_s
26
- if exp.start_with?('(?-mix:')
27
- exp = exp.to_s.gsub(/^\(\?-mix:/, '').gsub(/\)$/, '')
28
- end
29
- return exp
30
- end
31
-
32
24
  def add_child(node)
33
25
  unless node.name
34
26
  fail Exceptions::InvalidSchemaError, 'Child nodes must have a name.'
@@ -64,7 +56,7 @@ module Schemacop
64
56
 
65
57
  json = {}
66
58
  json[:properties] = Hash[properties.values.map { |p| [p.name, p.as_json] }] if properties.any?
67
- json[:patternProperties] = Hash[pattern_properties.values.map { |p| [self.class.sanitize_exp(p.name), p.as_json] }] if pattern_properties.any?
59
+ json[:patternProperties] = Hash[pattern_properties.values.map { |p| [V3.sanitize_exp(p.name), p.as_json] }] if pattern_properties.any?
68
60
 
69
61
  # In schemacop, by default, additional properties are not allowed,
70
62
  # the users explicitly need to enable additional properties
@@ -48,7 +48,7 @@ module Schemacop
48
48
  end
49
49
 
50
50
  def self.allowed_options
51
- %i[name required default description examples enum parent options cast_str title as]
51
+ %i[name required default description examples enum parent options title as]
52
52
  end
53
53
 
54
54
  def self.dsl_methods
@@ -150,6 +150,10 @@ module Schemacop
150
150
 
151
151
  protected
152
152
 
153
+ def context
154
+ Schemacop.context
155
+ end
156
+
153
157
  def item_matches?(item, data)
154
158
  item_result = Result.new(self)
155
159
  item._validate(data, result: item_result)
@@ -157,12 +161,13 @@ module Schemacop
157
161
  end
158
162
 
159
163
  def process_json(attrs, json)
160
- if @schemas.any?
164
+ if !context.swagger_json? && @schemas.any?
161
165
  json[:definitions] = {}
162
166
  @schemas.each do |name, subschema|
163
167
  json[:definitions][name] = subschema.as_json
164
168
  end
165
169
  end
170
+
166
171
  attrs.each do |attr|
167
172
  if options.include?(attr)
168
173
  json[attr.to_s.camelize(:lower).to_sym] = options[attr]
@@ -170,7 +175,7 @@ module Schemacop
170
175
  end
171
176
 
172
177
  json[:title] = @title if @title
173
- json[:examples] = @examples if @examples
178
+ json[context.swagger_json? ? :example : :examples] = @examples if @examples
174
179
  json[:description] = @description if @description
175
180
  json[:default] = @default if @default
176
181
  json[:enum] = @enum.to_a if @enum
@@ -4,14 +4,32 @@ module Schemacop
4
4
  class NumericNode < Node
5
5
  ATTRIBUTES = %i[
6
6
  minimum
7
- exclusive_minimum
8
7
  maximum
9
- exclusive_maximum
10
8
  multiple_of
9
+ exclusive_minimum
10
+ exclusive_maximum
11
11
  ].freeze
12
12
 
13
13
  def self.allowed_options
14
- super + ATTRIBUTES
14
+ super + ATTRIBUTES + %i[cast_str]
15
+ end
16
+
17
+ def process_json(attrs, json)
18
+ if context.swagger_json?
19
+ if options[:exclusive_minimum]
20
+ json[:minimum] = options[:exclusive_minimum]
21
+ json[:exclusiveMinimum] = true
22
+ end
23
+
24
+ if options[:exclusive_maximum]
25
+ json[:maximum] = options[:exclusive_maximum]
26
+ json[:exclusiveMaximum] = true
27
+ end
28
+
29
+ attrs -= %i[exclusive_minimum exclusive_maximum]
30
+ end
31
+
32
+ super attrs, json
15
33
  end
16
34
 
17
35
  def _validate(data, result:)
@@ -5,11 +5,6 @@ module Schemacop
5
5
  super + %i[classes strict]
6
6
  end
7
7
 
8
- def self.create(classes, **options, &block)
9
- options[:classes] = classes
10
- super(**options, &block)
11
- end
12
-
13
8
  def as_json
14
9
  {} # Not supported by Json Schema
15
10
  end
@@ -11,7 +11,11 @@ module Schemacop
11
11
  end
12
12
 
13
13
  def as_json
14
- process_json([], '$ref': "#/definitions/#{@path}")
14
+ if context.swagger_json?
15
+ process_json([], '$ref': "#/components/schemas/#{@path}")
16
+ else
17
+ process_json([], '$ref': "#/definitions/#{@path}")
18
+ end
15
19
  end
16
20
 
17
21
  def _validate(data, result:)
@@ -4,7 +4,6 @@ module Schemacop
4
4
  ATTRIBUTES = %i[
5
5
  min_length
6
6
  max_length
7
- pattern
8
7
  format
9
8
  ].freeze
10
9
 
@@ -23,7 +22,7 @@ module Schemacop
23
22
  # rubocop:enable Layout/LineLength
24
23
 
25
24
  def self.allowed_options
26
- super + ATTRIBUTES - %i[cast_str] + %i[format_options]
25
+ super + ATTRIBUTES + %i[format_options pattern]
27
26
  end
28
27
 
29
28
  def allowed_types
@@ -31,7 +30,11 @@ module Schemacop
31
30
  end
32
31
 
33
32
  def as_json
34
- process_json(ATTRIBUTES, type: :string)
33
+ json = { type: :string }
34
+ if options[:pattern]
35
+ json[:pattern] = V3.sanitize_exp(Regexp.compile(options[:pattern]))
36
+ end
37
+ process_json(ATTRIBUTES, json)
35
38
  end
36
39
 
37
40
  def _validate(data, result:)
@@ -50,8 +53,14 @@ module Schemacop
50
53
  end
51
54
 
52
55
  # Validate pattern #
53
- if options[:pattern] && !super_data.match?(Regexp.compile(options[:pattern]))
54
- result.error "String does not match pattern #{options[:pattern].inspect}."
56
+ if (pattern = options[:pattern])
57
+ unless options[:pattern].is_a?(Regexp)
58
+ pattern = Regexp.compile(pattern)
59
+ end
60
+
61
+ unless super_data.match?(pattern)
62
+ result.error "String does not match pattern #{V3.sanitize_exp(pattern).inspect}."
63
+ end
55
64
  end
56
65
 
57
66
  # Validate format #
@@ -121,7 +130,9 @@ module Schemacop
121
130
  end
122
131
 
123
132
  if options[:pattern]
124
- fail 'Option "pattern" must be a string.' unless options[:pattern].is_a?(String)
133
+ unless options[:pattern].is_a?(String) || options[:pattern].is_a?(Regexp)
134
+ fail 'Option "pattern" must be a string or Regexp.'
135
+ end
125
136
 
126
137
  begin
127
138
  Regexp.compile(options[:pattern])
@@ -8,6 +8,10 @@ module Schemacop
8
8
  def allowed_types
9
9
  { Symbol => 'Symbol' }
10
10
  end
11
+
12
+ def self.allowed_options
13
+ super + %i[cast_str]
14
+ end
11
15
  end
12
16
  end
13
17
  end
data/schemacop.gemspec CHANGED
@@ -1,49 +1,37 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: schemacop 3.0.3 ruby lib
2
+ # stub: schemacop 3.0.8 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "schemacop".freeze
6
- s.version = "3.0.3"
6
+ s.version = "3.0.8"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Sitrox".freeze]
11
- s.date = "2021-02-15"
11
+ s.date = "2021-02-23"
12
12
  s.files = [".gitignore".freeze, ".releaser_config".freeze, ".rubocop.yml".freeze, ".travis.yml".freeze, ".yardopts".freeze, "CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "README_V2.md".freeze, "README_V3.md".freeze, "RUBY_VERSION".freeze, "Rakefile".freeze, "VERSION".freeze, "lib/schemacop.rb".freeze, "lib/schemacop/base_schema.rb".freeze, "lib/schemacop/exceptions.rb".freeze, "lib/schemacop/railtie.rb".freeze, "lib/schemacop/schema.rb".freeze, "lib/schemacop/schema2.rb".freeze, "lib/schemacop/schema3.rb".freeze, "lib/schemacop/scoped_env.rb".freeze, "lib/schemacop/v2.rb".freeze, "lib/schemacop/v2/caster.rb".freeze, "lib/schemacop/v2/collector.rb".freeze, "lib/schemacop/v2/dupper.rb".freeze, "lib/schemacop/v2/field_node.rb".freeze, "lib/schemacop/v2/node.rb".freeze, "lib/schemacop/v2/node_resolver.rb".freeze, "lib/schemacop/v2/node_supporting_field.rb".freeze, "lib/schemacop/v2/node_supporting_type.rb".freeze, "lib/schemacop/v2/node_with_block.rb".freeze, "lib/schemacop/v2/validator/array_validator.rb".freeze, "lib/schemacop/v2/validator/boolean_validator.rb".freeze, "lib/schemacop/v2/validator/float_validator.rb".freeze, "lib/schemacop/v2/validator/hash_validator.rb".freeze, "lib/schemacop/v2/validator/integer_validator.rb".freeze, "lib/schemacop/v2/validator/nil_validator.rb".freeze, "lib/schemacop/v2/validator/number_validator.rb".freeze, "lib/schemacop/v2/validator/object_validator.rb".freeze, "lib/schemacop/v2/validator/string_validator.rb".freeze, "lib/schemacop/v2/validator/symbol_validator.rb".freeze, "lib/schemacop/v3.rb".freeze, "lib/schemacop/v3/all_of_node.rb".freeze, "lib/schemacop/v3/any_of_node.rb".freeze, "lib/schemacop/v3/array_node.rb".freeze, "lib/schemacop/v3/boolean_node.rb".freeze, "lib/schemacop/v3/combination_node.rb".freeze, "lib/schemacop/v3/context.rb".freeze, "lib/schemacop/v3/dsl_scope.rb".freeze, "lib/schemacop/v3/global_context.rb".freeze, "lib/schemacop/v3/hash_node.rb".freeze, "lib/schemacop/v3/integer_node.rb".freeze, "lib/schemacop/v3/is_not_node.rb".freeze, "lib/schemacop/v3/node.rb".freeze, "lib/schemacop/v3/node_registry.rb".freeze, "lib/schemacop/v3/number_node.rb".freeze, "lib/schemacop/v3/numeric_node.rb".freeze, "lib/schemacop/v3/object_node.rb".freeze, "lib/schemacop/v3/one_of_node.rb".freeze, "lib/schemacop/v3/reference_node.rb".freeze, "lib/schemacop/v3/result.rb".freeze, "lib/schemacop/v3/string_node.rb".freeze, "lib/schemacop/v3/symbol_node.rb".freeze, "schemacop.gemspec".freeze, "test/lib/test_helper.rb".freeze, "test/schemas/nested/group.rb".freeze, "test/schemas/user.rb".freeze, "test/unit/schemacop/v2/casting_test.rb".freeze, "test/unit/schemacop/v2/collector_test.rb".freeze, "test/unit/schemacop/v2/custom_check_test.rb".freeze, "test/unit/schemacop/v2/custom_if_test.rb".freeze, "test/unit/schemacop/v2/defaults_test.rb".freeze, "test/unit/schemacop/v2/empty_test.rb".freeze, "test/unit/schemacop/v2/nil_dis_allow_test.rb".freeze, "test/unit/schemacop/v2/node_resolver_test.rb".freeze, "test/unit/schemacop/v2/short_forms_test.rb".freeze, "test/unit/schemacop/v2/types_test.rb".freeze, "test/unit/schemacop/v2/validator_array_test.rb".freeze, "test/unit/schemacop/v2/validator_boolean_test.rb".freeze, "test/unit/schemacop/v2/validator_float_test.rb".freeze, "test/unit/schemacop/v2/validator_hash_test.rb".freeze, "test/unit/schemacop/v2/validator_integer_test.rb".freeze, "test/unit/schemacop/v2/validator_nil_test.rb".freeze, "test/unit/schemacop/v2/validator_number_test.rb".freeze, "test/unit/schemacop/v2/validator_object_test.rb".freeze, "test/unit/schemacop/v2/validator_string_test.rb".freeze, "test/unit/schemacop/v2/validator_symbol_test.rb".freeze, "test/unit/schemacop/v3/all_of_node_test.rb".freeze, "test/unit/schemacop/v3/any_of_node_test.rb".freeze, "test/unit/schemacop/v3/array_node_test.rb".freeze, "test/unit/schemacop/v3/boolean_node_test.rb".freeze, "test/unit/schemacop/v3/global_context_test.rb".freeze, "test/unit/schemacop/v3/hash_node_test.rb".freeze, "test/unit/schemacop/v3/integer_node_test.rb".freeze, "test/unit/schemacop/v3/is_not_node_test.rb".freeze, "test/unit/schemacop/v3/node_test.rb".freeze, "test/unit/schemacop/v3/number_node_test.rb".freeze, "test/unit/schemacop/v3/object_node_test.rb".freeze, "test/unit/schemacop/v3/one_of_node_test.rb".freeze, "test/unit/schemacop/v3/reference_node_test.rb".freeze, "test/unit/schemacop/v3/string_node_test.rb".freeze, "test/unit/schemacop/v3/symbol_node_test.rb".freeze]
13
13
  s.homepage = "https://github.com/sitrox/schemacop".freeze
14
14
  s.licenses = ["MIT".freeze]
15
- s.rubygems_version = "3.0.3".freeze
15
+ s.rubygems_version = "3.1.2".freeze
16
16
  s.summary = "Schemacop validates ruby structures consisting of nested hashes and arrays against simple schema definitions.".freeze
17
17
  s.test_files = ["test/lib/test_helper.rb".freeze, "test/schemas/nested/group.rb".freeze, "test/schemas/user.rb".freeze, "test/unit/schemacop/v2/casting_test.rb".freeze, "test/unit/schemacop/v2/collector_test.rb".freeze, "test/unit/schemacop/v2/custom_check_test.rb".freeze, "test/unit/schemacop/v2/custom_if_test.rb".freeze, "test/unit/schemacop/v2/defaults_test.rb".freeze, "test/unit/schemacop/v2/empty_test.rb".freeze, "test/unit/schemacop/v2/nil_dis_allow_test.rb".freeze, "test/unit/schemacop/v2/node_resolver_test.rb".freeze, "test/unit/schemacop/v2/short_forms_test.rb".freeze, "test/unit/schemacop/v2/types_test.rb".freeze, "test/unit/schemacop/v2/validator_array_test.rb".freeze, "test/unit/schemacop/v2/validator_boolean_test.rb".freeze, "test/unit/schemacop/v2/validator_float_test.rb".freeze, "test/unit/schemacop/v2/validator_hash_test.rb".freeze, "test/unit/schemacop/v2/validator_integer_test.rb".freeze, "test/unit/schemacop/v2/validator_nil_test.rb".freeze, "test/unit/schemacop/v2/validator_number_test.rb".freeze, "test/unit/schemacop/v2/validator_object_test.rb".freeze, "test/unit/schemacop/v2/validator_string_test.rb".freeze, "test/unit/schemacop/v2/validator_symbol_test.rb".freeze, "test/unit/schemacop/v3/all_of_node_test.rb".freeze, "test/unit/schemacop/v3/any_of_node_test.rb".freeze, "test/unit/schemacop/v3/array_node_test.rb".freeze, "test/unit/schemacop/v3/boolean_node_test.rb".freeze, "test/unit/schemacop/v3/global_context_test.rb".freeze, "test/unit/schemacop/v3/hash_node_test.rb".freeze, "test/unit/schemacop/v3/integer_node_test.rb".freeze, "test/unit/schemacop/v3/is_not_node_test.rb".freeze, "test/unit/schemacop/v3/node_test.rb".freeze, "test/unit/schemacop/v3/number_node_test.rb".freeze, "test/unit/schemacop/v3/object_node_test.rb".freeze, "test/unit/schemacop/v3/one_of_node_test.rb".freeze, "test/unit/schemacop/v3/reference_node_test.rb".freeze, "test/unit/schemacop/v3/string_node_test.rb".freeze, "test/unit/schemacop/v3/symbol_node_test.rb".freeze]
18
18
 
19
19
  if s.respond_to? :specification_version then
20
20
  s.specification_version = 4
21
+ end
21
22
 
22
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
23
- s.add_runtime_dependency(%q<activesupport>.freeze, [">= 4.0"])
24
- s.add_runtime_dependency(%q<ruby2_keywords>.freeze, ["= 0.0.4"])
25
- s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
26
- s.add_development_dependency(%q<rake>.freeze, [">= 0"])
27
- s.add_development_dependency(%q<minitest>.freeze, [">= 0"])
28
- s.add_development_dependency(%q<minitest-reporters>.freeze, [">= 0"])
29
- s.add_development_dependency(%q<colorize>.freeze, [">= 0"])
30
- s.add_development_dependency(%q<rubocop>.freeze, ["= 0.92.0"])
31
- s.add_development_dependency(%q<pry>.freeze, [">= 0"])
32
- s.add_development_dependency(%q<byebug>.freeze, [">= 0"])
33
- s.add_development_dependency(%q<simplecov>.freeze, ["= 0.21.2"])
34
- else
35
- s.add_dependency(%q<activesupport>.freeze, [">= 4.0"])
36
- s.add_dependency(%q<ruby2_keywords>.freeze, ["= 0.0.4"])
37
- s.add_dependency(%q<bundler>.freeze, [">= 0"])
38
- s.add_dependency(%q<rake>.freeze, [">= 0"])
39
- s.add_dependency(%q<minitest>.freeze, [">= 0"])
40
- s.add_dependency(%q<minitest-reporters>.freeze, [">= 0"])
41
- s.add_dependency(%q<colorize>.freeze, [">= 0"])
42
- s.add_dependency(%q<rubocop>.freeze, ["= 0.92.0"])
43
- s.add_dependency(%q<pry>.freeze, [">= 0"])
44
- s.add_dependency(%q<byebug>.freeze, [">= 0"])
45
- s.add_dependency(%q<simplecov>.freeze, ["= 0.21.2"])
46
- end
23
+ if s.respond_to? :add_runtime_dependency then
24
+ s.add_runtime_dependency(%q<activesupport>.freeze, [">= 4.0"])
25
+ s.add_runtime_dependency(%q<ruby2_keywords>.freeze, ["= 0.0.4"])
26
+ s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
27
+ s.add_development_dependency(%q<rake>.freeze, [">= 0"])
28
+ s.add_development_dependency(%q<minitest>.freeze, [">= 0"])
29
+ s.add_development_dependency(%q<minitest-reporters>.freeze, [">= 0"])
30
+ s.add_development_dependency(%q<colorize>.freeze, [">= 0"])
31
+ s.add_development_dependency(%q<rubocop>.freeze, ["= 0.92.0"])
32
+ s.add_development_dependency(%q<pry>.freeze, [">= 0"])
33
+ s.add_development_dependency(%q<byebug>.freeze, [">= 0"])
34
+ s.add_development_dependency(%q<simplecov>.freeze, ["= 0.21.2"])
47
35
  else
48
36
  s.add_dependency(%q<activesupport>.freeze, [">= 4.0"])
49
37
  s.add_dependency(%q<ruby2_keywords>.freeze, ["= 0.0.4"])
@@ -142,6 +142,13 @@ class V3Test < SchemacopTest
142
142
  assert_equal expected_json.as_json, @schema.as_json.as_json
143
143
  end
144
144
 
145
+ def assert_swagger_json(expected_json)
146
+ # TODO: Double "as_json" should not be necessary
147
+ Schemacop.context.with_json_format(:swagger) do
148
+ assert_equal expected_json.as_json, @schema.as_json.as_json
149
+ end
150
+ end
151
+
145
152
  def assert_match_any(array, exp)
146
153
  assert array.any? { |element| element.match?(exp) },
147
154
  "Expected any of #{array.inspect} to match #{exp}."
@@ -73,8 +73,8 @@ module Schemacop
73
73
  hsh { str! :foo }
74
74
  end
75
75
  any_of do
76
- obj(Date)
77
- obj(Time)
76
+ obj classes: Date
77
+ obj classes: Time
78
78
  end
79
79
  ary
80
80
  boo
@@ -136,6 +136,20 @@ module Schemacop
136
136
  assert_cast(false, false)
137
137
  assert_cast(nil, true)
138
138
  end
139
+
140
+ def test_cast_str
141
+ schema :boolean, cast_str: true
142
+
143
+ assert_cast('true', true)
144
+ assert_cast('false', false)
145
+
146
+ assert_cast(true, true)
147
+ assert_cast(false, false)
148
+
149
+ assert_validation('1') do
150
+ error '/', 'Matches 0 definitions but should match exactly 1.'
151
+ end
152
+ end
139
153
  end
140
154
  end
141
155
  end
@@ -125,6 +125,12 @@ module Schemacop
125
125
  exclusiveMinimum: 0
126
126
  )
127
127
 
128
+ assert_swagger_json(
129
+ type: :integer,
130
+ minimum: 0,
131
+ exclusiveMinimum: true
132
+ )
133
+
128
134
  assert_validation 5
129
135
  assert_validation 1
130
136
  assert_validation(0) do
@@ -158,6 +164,12 @@ module Schemacop
158
164
  exclusiveMaximum: 5
159
165
  )
160
166
 
167
+ assert_swagger_json(
168
+ type: :integer,
169
+ maximum: 5,
170
+ exclusiveMaximum: true
171
+ )
172
+
161
173
  assert_validation 4
162
174
  assert_validation 1
163
175
  assert_validation(5) do
@@ -318,6 +330,17 @@ module Schemacop
318
330
  ]
319
331
  })
320
332
  end
333
+
334
+ def test_cast_str
335
+ schema :integer, cast_str: true
336
+
337
+ assert_cast('1', 1)
338
+ assert_cast(1, 1)
339
+
340
+ assert_validation('true') do
341
+ error '/', 'Matches 0 definitions but should match exactly 1.'
342
+ end
343
+ end
321
344
  end
322
345
  end
323
346
  end
@@ -63,6 +63,20 @@ module Schemacop
63
63
  })
64
64
  end
65
65
 
66
+ def test_swagger_example
67
+ schema :string, examples: ['Foo', 'Foo bar']
68
+
69
+ assert_json(
70
+ type: :string,
71
+ examples: ['Foo', 'Foo bar']
72
+ )
73
+
74
+ assert_swagger_json(
75
+ type: :string,
76
+ example: ['Foo', 'Foo bar']
77
+ )
78
+ end
79
+
66
80
  def test_cast_in_root
67
81
  schema :integer, cast_str: true, required: true
68
82
 
@@ -101,6 +101,12 @@ module Schemacop
101
101
  exclusiveMinimum: 0
102
102
  )
103
103
 
104
+ assert_swagger_json(
105
+ type: :number,
106
+ minimum: 0,
107
+ exclusiveMinimum: true
108
+ )
109
+
104
110
  assert_validation 5
105
111
  assert_validation 1
106
112
  assert_validation(0) do
@@ -134,6 +140,12 @@ module Schemacop
134
140
  exclusiveMaximum: 5
135
141
  )
136
142
 
143
+ assert_swagger_json(
144
+ type: :number,
145
+ maximum: 5,
146
+ exclusiveMaximum: true
147
+ )
148
+
137
149
  assert_validation 4
138
150
  assert_validation 1
139
151
  assert_validation(5) do
@@ -287,6 +299,35 @@ module Schemacop
287
299
  ]
288
300
  })
289
301
  end
302
+
303
+ def test_cast_str
304
+ schema :number, cast_str: true, minimum: 0.0, maximum: 50r, multiple_of: BigDecimal('0.5')
305
+
306
+ assert_cast('1', 1)
307
+ assert_cast(1, 1)
308
+
309
+ assert_cast('1.0', 1.0)
310
+ assert_cast(1.0, 1.0)
311
+
312
+ assert_validation('42')
313
+ assert_validation('0.5')
314
+
315
+ assert_validation('true') do
316
+ error '/', 'Matches 0 definitions but should match exactly 1.'
317
+ end
318
+
319
+ assert_validation('51') do
320
+ error '/', 'Matches 0 definitions but should match exactly 1.'
321
+ end
322
+
323
+ assert_validation('-2') do
324
+ error '/', 'Matches 0 definitions but should match exactly 1.'
325
+ end
326
+
327
+ assert_validation('3.1415') do
328
+ error '/', 'Matches 0 definitions but should match exactly 1.'
329
+ end
330
+ end
290
331
  end
291
332
  end
292
333
  end
@@ -59,7 +59,10 @@ module Schemacop
59
59
  end
60
60
 
61
61
  def test_hash
62
- schema { obj! :myobj, String }
62
+ schema do
63
+ obj! :myobj, classes: String
64
+ end
65
+
63
66
  assert_json(
64
67
  type: :object,
65
68
  properties: {
@@ -78,6 +81,16 @@ module Schemacop
78
81
  end
79
82
  end
80
83
 
84
+ def test_hash_no_class
85
+ schema do
86
+ obj! :myobj
87
+ end
88
+
89
+ assert_validation(myobj: 'str')
90
+ assert_validation(myobj: 123)
91
+ assert_validation(myobj: Object.new)
92
+ end
93
+
81
94
  def test_enum_schema
82
95
  schema :object, enum: [true, 'foo', :baz, [], { qux: '123' }]
83
96
 
@@ -80,7 +80,7 @@ module Schemacop
80
80
  end
81
81
  end
82
82
 
83
- def test_pattern
83
+ def test_pattern_as_string
84
84
  schema :string, pattern: '^a_.*_z$'
85
85
 
86
86
  assert_json(type: :string, pattern: '^a_.*_z$')
@@ -95,6 +95,22 @@ module Schemacop
95
95
  end
96
96
  end
97
97
 
98
+ def test_pattern_as_regexp
99
+ schema :string, pattern: /^a_.*_z$/i
100
+
101
+ assert_json(type: :string, pattern: '^(?i)(a_.*_z)$')
102
+
103
+ assert_validation 'a__z'
104
+ assert_validation 'a__Z'
105
+ assert_validation 'a_ foo bar _Z'
106
+ assert_validation '' do
107
+ error '/', 'String does not match pattern "^(?i)(a_.*_z)$".'
108
+ end
109
+ assert_validation 'a_ _zfoo' do
110
+ error '/', 'String does not match pattern "^(?i)(a_.*_z)$".'
111
+ end
112
+ end
113
+
98
114
  def test_format_date
99
115
  schema :string, format: :date
100
116
 
@@ -314,8 +330,8 @@ module Schemacop
314
330
  end
315
331
 
316
332
  assert_raises_with_message Exceptions::InvalidSchemaError,
317
- 'Option "pattern" must be a string.' do
318
- schema :string, pattern: //
333
+ 'Option "pattern" must be a string or Regexp.' do
334
+ schema :string, pattern: 42
319
335
  end
320
336
 
321
337
  assert_raises_with_message Exceptions::InvalidSchemaError,
@@ -70,6 +70,20 @@ module Schemacop
70
70
  error '/', 'Value not included in enum [1, 2, "foo", :bar, {:qux=>42}].'
71
71
  end
72
72
  end
73
+
74
+ # rubocop:disable Lint/BooleanSymbol
75
+ def test_cast_str
76
+ schema :symbol, cast_str: true
77
+
78
+ assert_cast('true', :true)
79
+ assert_cast('foo', :foo)
80
+ assert_cast('1', :'1')
81
+
82
+ assert_cast(:true, :true)
83
+ assert_cast(:foo, :foo)
84
+ assert_cast(:'1', :'1')
85
+ end
86
+ # rubocop:enable Lint/BooleanSymbol
73
87
  end
74
88
  end
75
89
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: schemacop
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3
4
+ version: 3.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sitrox
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-15 00:00:00.000000000 Z
11
+ date: 2021-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -292,7 +292,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
292
292
  - !ruby/object:Gem::Version
293
293
  version: '0'
294
294
  requirements: []
295
- rubygems_version: 3.0.3
295
+ rubygems_version: 3.1.2
296
296
  signing_key:
297
297
  specification_version: 4
298
298
  summary: Schemacop validates ruby structures consisting of nested hashes and arrays