schemacop 3.0.12 → 3.0.16

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b89073617fde4588d3cdf44b86c76be5b07c23cf9036c2f44c8b9599dda73779
4
- data.tar.gz: 5d3860807fc84a14043dda84a2bdf7fc5696668171b2bc5560607f3de14be242
3
+ metadata.gz: 3c6c1009f3a4a23a39f58dd1aef99c63136f8d362963d14a7513f08f0d705c0c
4
+ data.tar.gz: 58a4e7ace82f8f5b1a69ac70ec39dc44a0b4766a167920e3f6de497a7ebe3ee9
5
5
  SHA512:
6
- metadata.gz: 63a492f2523c049f3a720ca9525d72ddf15e76a3e092dcb3b295af118fe2a1cd1e0cc92c8dffb4c20f1e5e7b98c466efde3d96dd26180279ffad9ab27157948f
7
- data.tar.gz: f06fd83b902c3fa67ef554fd47930b39dbdfa77f57e753d14b74b88b23fe32da5043cdebc563d4296e80af53118505420f3f0d6d88f122554891fa8e2e3ca048
6
+ metadata.gz: 7086af3afd13d6cabe140cd550a53b9fed5117b496fb01e67ea4fc9a468d0e5e9a8c5f563fe330fae88a3c4a61fd9c98cbe6317ac1cf6478ab159b66afca9391
7
+ data.tar.gz: 438129e855a0da9ba74fd7a03c9de3abf3bd206cca4cfe5c70a5ae5ad21d88a927d3cc25738934a3a51f72c32781d48ea1da47c0f7db427a94945792a892641b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Change log
2
2
 
3
+ ## 3.0.17 (2021-12-06)
4
+
5
+ * `#64545`: Fix an issue where `cast_str` in conjunction with `number` notes
6
+ lead to parsing errors when the given number had a leading zero, e.g. parsing
7
+ the string `08` lead to an error, as the number was interpreted as an octal
8
+ string. Numbers are now always being treated as decimal with base 10.
9
+
10
+ ## 3.0.16 (2021-11-23)
11
+
12
+ * Add setting `Schemacop.v3_default_options` which allows to set default node
13
+ options vor V3 schemas. This is particularly useful for the option `cast_str`
14
+ to allow string casting globally.
15
+
16
+ ## 3.0.15 (2021-10-11)
17
+
18
+ * Add support for custom string formatters
19
+
20
+ ## 3.0.14 (2021-10-11)
21
+
22
+ * Add string format `integer_list`
23
+
24
+ * Improve handling for booleans
25
+
26
+ ## 3.0.13 (2021-10-04)
27
+
28
+ * When using `boolean` with `cast_str: true`, `"0"` is now casted to `false` and
29
+ `"1"` to `true`. This in addition to already casting `"true", "false"`.
30
+
3
31
  ## 3.0.12 (2021-09-14)
4
32
 
5
33
  * Fix compatibility issue with `ruby <= 2.5`
data/README_V3.md CHANGED
@@ -21,6 +21,7 @@
21
21
  13. [Reference](#reference)
22
22
  5. [Context](#context)
23
23
  6. [External schemas](#external-schemas)
24
+ 7. [Default options](#default-options)
24
25
 
25
26
  ## Validation
26
27
 
@@ -233,8 +234,8 @@ transformed into various types.
233
234
  addresses do not have their own ruby type.
234
235
 
235
236
  * `boolean`
236
- The string must be either `true` or `false`. This value will be casted to
237
- Ruby's `TrueClass` or `FalseClass`.
237
+ The string must be either `true`, `false`, `0` or `1`. This value will be
238
+ casted to Ruby's `TrueClass` or `FalseClass`.
238
239
 
239
240
  * `binary`
240
241
  The string is expected to contain binary contents. No casting or additional
@@ -246,9 +247,30 @@ transformed into various types.
246
247
  * `number`
247
248
  The string must be a number and will be casted to a ruby `Float` object.
248
249
 
250
+ * `integer_list`
251
+ The string must consist of comma-separated integers casted to a ruby `Array<Integer>` object
252
+
249
253
  * `symbol`
250
254
  The string can be anything and will be casted to a ruby `Symbol` object.
251
255
 
256
+ #### Custom Formats
257
+
258
+ You can also implement your custom formats or override the behavior of the
259
+ standard formats. This can be done in the initializer configuration (in case of
260
+ a Rails appliation):
261
+
262
+ ```ruby
263
+ # config/initializers/schemacop.rb
264
+ Schemacop.register_string_formatter(
265
+ :character_array, # Formatter name
266
+ pattern: /^[a-zA-Z](,[a-zA-Z])*/, # Regex pattern for validation
267
+ handler: ->(value) { value.split(',') } # Casting callback
268
+ )
269
+
270
+ # In your schema
271
+ str! :my_list, format: :character_array
272
+ ```
273
+
252
274
  #### Examples
253
275
 
254
276
  ```ruby
@@ -318,6 +340,8 @@ integer can be done.
318
340
  When set to `true`, this node also accepts strings that can be casted to an integer, e.g.
319
341
  the values `'-5'` or `'42'`. Please note that you can only validate numbers which
320
342
  are in the `Integer` format. Blank strings will be treated equally as `nil`.
343
+ Strings will be parsed with base 10, so only decimal numbers are allowed.
344
+ Leading zeroes will be ignored.
321
345
 
322
346
  #### Examples
323
347
 
@@ -399,7 +423,9 @@ With the various available options, validations on the value of the number can b
399
423
  When set to `true`, this node also accepts strings that can be casted to a number, e.g.
400
424
  the values `'0.1'` or `'3.1415'`. Please note that you can only validate numbers which
401
425
  are in the `Integer` or `Float` format, i.e. values like `'1.5r'` or `'(4 + 0i)'` will
402
- not work. Blank strings will be treated equally as `nil`.
426
+ not work. Blank strings will be treated equally as `nil`. Strings will be
427
+ parsed with base 10, so only decimal numbers are allowed. Leading zeroes will
428
+ be ignored.
403
429
 
404
430
  #### Examples
405
431
 
@@ -501,8 +527,9 @@ The boolean type is used to validate Ruby booleans, i.e. the `TrueClass` and `Fa
501
527
  #### Options
502
528
 
503
529
  * `cast_str`
504
- When set to `true`, this node also accepts strings that can be casted to a boolean, i.e.
505
- the values `'true'` and `'false'`. Blank strings will be treated equally as `nil`.
530
+ When set to `true`, this node also accepts strings that can be casted to a
531
+ boolean, namely the values `'true'`, `'false'`, `'1'` and `'0'`. Blank strings
532
+ will be treated equally as `nil`.
506
533
 
507
534
  #### Examples
508
535
 
@@ -514,6 +541,11 @@ schema.validate!(false) # => false
514
541
  schema.validate!(:false) # => Schemacop::Exceptions::ValidationError: /: Invalid type, got type "Symbol", expected "boolean".
515
542
  schema.validate!('false') # => Schemacop::Exceptions::ValidationError: /: Invalid type, got type "String", expected "boolean".
516
543
  schema.validate!(1234) # => Schemacop::Exceptions::ValidationError: /: Invalid type, got type "Integer", expected "boolean".
544
+
545
+ schema.validate!('0', cast_str: true) # => false
546
+ schema.validate!('1', cast_str: true) # => true
547
+ schema.validate!('false', cast_str: true) # => false
548
+ schema.validate!('true', cast_str: true) # => true
517
549
  ```
518
550
 
519
551
  With `cast_str` enabled:
@@ -1422,3 +1454,21 @@ Schemacop::V3::GlobalContext.eager_load!
1422
1454
  As mentioned before, you can also use the external schemas without having to
1423
1455
  eager-load them, but if you use the schemas multiple times, it might be better
1424
1456
  to eager-load them on start of your application / script.
1457
+
1458
+ ## Default options
1459
+
1460
+ Using the setting `Schemacop.v3_default_options`, you can specify a hash
1461
+ containing default options that will be used for every schemacop node (options
1462
+ not supported by a particular node are automatically ignored). Options passed
1463
+ directly to a node still take precedence. The setting can be set in an
1464
+ initializer:
1465
+
1466
+ ```ruby
1467
+ # config/initializers/schemacop.rb
1468
+ Schemacop.v3_default_options = { cast_str: true }.freeze
1469
+
1470
+ # Example schema: As cast_str is enabled in the default options, strings will
1471
+ # automatically be casted where supported.
1472
+ schema = Schemacop::Schema3.new(:integer)
1473
+ schema.validate!('42') # => 42
1474
+ ```
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.12
1
+ 3.0.16
@@ -187,7 +187,7 @@ module Schemacop
187
187
 
188
188
  casted_data = prop.cast(data_hash[prop.name])
189
189
 
190
- if casted_data.present? || data_hash.include?(prop.name)
190
+ if !casted_data.nil? || data_hash.include?(prop.name)
191
191
  result[prop_name] = casted_data
192
192
  end
193
193
 
@@ -30,6 +30,8 @@ module Schemacop
30
30
 
31
31
  node = klass.new(**options, &block)
32
32
 
33
+ options = Schemacop.v3_default_options.slice(*klass.allowed_options).merge(options)
34
+
33
35
  if options.delete(:cast_str)
34
36
  format = NodeRegistry.name(klass)
35
37
  one_of_options = {
@@ -178,7 +180,7 @@ module Schemacop
178
180
  json[:title] = @title if @title
179
181
  json[context.swagger_json? ? :example : :examples] = @examples if @examples
180
182
  json[:description] = @description if @description
181
- json[:default] = @default if @default
183
+ json[:default] = @default unless @default.nil?
182
184
  json[:enum] = @enum.to_a if @enum
183
185
 
184
186
  return json.as_json
@@ -197,7 +199,7 @@ module Schemacop
197
199
 
198
200
  # Apply default #
199
201
  if data.nil?
200
- if default
202
+ if !default.nil?
201
203
  data = default
202
204
  else
203
205
  return nil
@@ -7,20 +7,6 @@ module Schemacop
7
7
  format
8
8
  ].freeze
9
9
 
10
- # rubocop:disable Layout/LineLength
11
- FORMAT_PATTERNS = {
12
- date: /^([0-9]{4})-?(1[0-2]|0[1-9])-?(3[01]|0[1-9]|[12][0-9])$/,
13
- 'date-time': /^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$/,
14
- time: /^(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$/,
15
- email: URI::MailTo::EMAIL_REGEXP,
16
- boolean: /^(true|false)$/,
17
- binary: nil,
18
- symbol: nil,
19
- integer: /^-?[0-9]+$/,
20
- number: /^-?[0-9]+(\.[0-9]+)?$/
21
- }.freeze
22
- # rubocop:enable Layout/LineLength
23
-
24
10
  def self.allowed_options
25
11
  super + ATTRIBUTES + %i[format_options pattern allow_blank]
26
12
  end
@@ -70,8 +56,9 @@ module Schemacop
70
56
  end
71
57
 
72
58
  # Validate format #
73
- if options[:format] && FORMAT_PATTERNS.include?(options[:format])
74
- pattern = FORMAT_PATTERNS[options[:format]]
59
+ if options[:format] && Schemacop.string_formatters.include?(options[:format])
60
+ pattern = Schemacop.string_formatters[options[:format]][:pattern]
61
+
75
62
  if pattern && !super_data.match?(pattern)
76
63
  result.error "String does not match format #{options[:format].to_s.inspect}."
77
64
  elsif options[:format_options] && Node.resolve_class(options[:format])
@@ -90,21 +77,8 @@ module Schemacop
90
77
  return nil
91
78
  end
92
79
 
93
- case options[:format]
94
- when :boolean
95
- return to_cast == 'true'
96
- when :date
97
- return Date.parse(to_cast)
98
- when :'date-time'
99
- return DateTime.parse(to_cast)
100
- when :time
101
- Time.parse(to_cast)
102
- when :integer
103
- return Integer(to_cast)
104
- when :number
105
- return Float(to_cast)
106
- when :symbol
107
- return to_cast.to_sym
80
+ if (handler = Schemacop.string_formatters.dig(options[:format], :handler))
81
+ return handler.call(to_cast)
108
82
  else
109
83
  return to_cast
110
84
  end
@@ -119,7 +93,7 @@ module Schemacop
119
93
  end
120
94
 
121
95
  def validate_self
122
- if options.include?(:format) && !FORMAT_PATTERNS.include?(options[:format])
96
+ if options.include?(:format) && !Schemacop.string_formatters.include?(options[:format])
123
97
  fail "Format #{options[:format].to_s.inspect} is not supported."
124
98
  end
125
99
 
data/lib/schemacop.rb CHANGED
@@ -13,6 +13,83 @@ module Schemacop
13
13
  mattr_accessor :default_schema_version
14
14
  self.default_schema_version = 3
15
15
 
16
+ mattr_accessor :string_formatters
17
+ self.string_formatters = {}
18
+
19
+ mattr_accessor :v3_default_options
20
+ self.v3_default_options = {}
21
+
22
+ def self.register_string_formatter(name, pattern:, handler:)
23
+ name = name.to_s.dasherize.to_sym
24
+
25
+ string_formatters[name] = {
26
+ pattern: pattern,
27
+ handler: handler
28
+ }
29
+ end
30
+
31
+ register_string_formatter(
32
+ :date,
33
+ pattern: /^([0-9]{4})-?(1[0-2]|0[1-9])-?(3[01]|0[1-9]|[12][0-9])$/,
34
+ handler: ->(value) { Date.parse(value) }
35
+ )
36
+
37
+ # rubocop: disable Layout/LineLength
38
+ register_string_formatter(
39
+ :'date-time',
40
+ pattern: /^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$/,
41
+ handler: ->(value) { DateTime.parse(value) }
42
+ )
43
+ # rubocop: enable Layout/LineLength
44
+
45
+ register_string_formatter(
46
+ :time,
47
+ pattern: /^(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$/,
48
+ handler: ->(value) { Time.parse(value) }
49
+ )
50
+
51
+ register_string_formatter(
52
+ :email,
53
+ pattern: URI::MailTo::EMAIL_REGEXP,
54
+ handler: ->(value) { value }
55
+ )
56
+
57
+ register_string_formatter(
58
+ :boolean,
59
+ pattern: /^(true|false|0|1)$/,
60
+ handler: ->(value) { %w[true 1].include?(value) }
61
+ )
62
+
63
+ register_string_formatter(
64
+ :binary,
65
+ pattern: nil,
66
+ handler: ->(value) { value }
67
+ )
68
+
69
+ register_string_formatter(
70
+ :symbol,
71
+ pattern: nil,
72
+ handler: ->(value) { value.to_sym }
73
+ )
74
+
75
+ register_string_formatter(
76
+ :integer,
77
+ pattern: /^-?[0-9]+$/,
78
+ handler: ->(value) { Integer(value, 10) }
79
+ )
80
+
81
+ register_string_formatter(
82
+ :number,
83
+ pattern: /^-?[0-9]+(\.[0-9]+)?$/,
84
+ handler: ->(value) { Float(value) }
85
+ )
86
+
87
+ register_string_formatter(
88
+ :'integer-list',
89
+ pattern: /^(-?[0-9]+)(,-?[0-9]+)*$/,
90
+ handler: ->(value) { value.split(',').map { |i| Integer(i, 10) } }
91
+ )
92
+
16
93
  def self.with_context(context)
17
94
  prev_context = Thread.current[CONTEXT_THREAD_KEY]
18
95
  Thread.current[CONTEXT_THREAD_KEY] = context
data/schemacop.gemspec CHANGED
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: schemacop 3.0.12 ruby lib
2
+ # stub: schemacop 3.0.16 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "schemacop".freeze
6
- s.version = "3.0.12"
6
+ s.version = "3.0.16"
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-09-14"
11
+ s.date = "2021-12-06"
12
12
  s.files = [".github/workflows/ruby.yml".freeze, ".gitignore".freeze, ".releaser_config".freeze, ".rubocop.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]
@@ -18,6 +18,38 @@ module Schemacop
18
18
  assert_json(type: :boolean)
19
19
  end
20
20
 
21
+ def test_required_default
22
+ schema do
23
+ boo? :enabled, default: true
24
+ end
25
+
26
+ assert_validation(enabled: true)
27
+ assert_validation(enabled: false)
28
+
29
+ assert_cast({}, { 'enabled' => true })
30
+
31
+ schema do
32
+ boo? :enabled, default: false
33
+ end
34
+
35
+ assert_validation(enabled: true)
36
+ assert_validation(enabled: false)
37
+
38
+ assert_cast({}, { 'enabled' => false })
39
+ end
40
+
41
+ def test_default_bug
42
+ schema do
43
+ str! :send_message
44
+ boo? :always_show_successful, default: true
45
+ end
46
+
47
+ assert_cast(
48
+ { 'send_message' => 'foo' },
49
+ { 'send_message' => 'foo', 'always_show_successful' => true }
50
+ )
51
+ end
52
+
21
53
  def test_required
22
54
  schema :boolean, required: true
23
55
 
@@ -146,10 +178,13 @@ module Schemacop
146
178
  assert_cast('true', true)
147
179
  assert_cast('false', false)
148
180
 
181
+ assert_cast('1', true)
182
+ assert_cast('0', false)
183
+
149
184
  assert_cast(true, true)
150
185
  assert_cast(false, false)
151
186
 
152
- assert_validation('1') do
187
+ assert_validation('5') do
153
188
  error '/', 'Matches 0 definitions but should match exactly 1.'
154
189
  end
155
190
 
@@ -171,7 +206,11 @@ module Schemacop
171
206
  assert_cast(true, true)
172
207
  assert_cast(false, false)
173
208
 
174
- assert_validation('1') do
209
+ assert_validation('4') do
210
+ error '/', 'Matches 0 definitions but should match exactly 1.'
211
+ end
212
+
213
+ assert_validation('foo') do
175
214
  error '/', 'Matches 0 definitions but should match exactly 1.'
176
215
  end
177
216
 
@@ -339,6 +339,11 @@ module Schemacop
339
339
  assert_cast('1', 1)
340
340
  assert_cast(1, 1)
341
341
 
342
+ assert_cast('08', 8)
343
+ assert_cast('09', 9)
344
+ assert_cast('050', 50)
345
+ assert_cast('01', 1)
346
+
342
347
  assert_cast(nil, nil)
343
348
  assert_cast('', nil)
344
349
 
@@ -181,6 +181,14 @@ module Schemacop
181
181
 
182
182
  assert_equal(@schema.root.children, [])
183
183
  end
184
+
185
+ def test_default_options
186
+ Schemacop.v3_default_options = { cast_str: true }.freeze
187
+ schema :number
188
+ assert_cast('1', 1)
189
+ ensure
190
+ Schemacop.v3_default_options = {}
191
+ end
184
192
  end
185
193
  end
186
194
  end
@@ -308,6 +308,11 @@ module Schemacop
308
308
  assert_cast('1', 1)
309
309
  assert_cast(1, 1)
310
310
 
311
+ assert_cast('08', 8)
312
+ assert_cast('09', 9)
313
+ assert_cast('050', 50)
314
+ assert_cast('01', 1)
315
+
311
316
  assert_validation(nil)
312
317
  assert_validation('')
313
318
 
@@ -158,6 +158,14 @@ module Schemacop
158
158
  assert_cast('2018-11-13T20:20:39+00:00', DateTime.new(2018, 11, 13, 20, 20, 39))
159
159
  end
160
160
 
161
+ def test_format_time
162
+ schema :string, format: :time
163
+ assert_json(type: :string, format: :time)
164
+ assert_cast '20:30:39+00:00', Time.strptime('20:30:39+00:00', '%H:%M:%S%z')
165
+
166
+ assert_cast nil, nil
167
+ end
168
+
161
169
  def test_format_email
162
170
  schema :string, format: :email
163
171
 
@@ -183,6 +191,17 @@ module Schemacop
183
191
  assert_cast('john.doe@example.com', 'john.doe@example.com')
184
192
  end
185
193
 
194
+ def test_format_boolean
195
+ schema :string, format: :boolean
196
+
197
+ assert_json(type: :string, format: :boolean)
198
+
199
+ assert_cast 'true', true
200
+ assert_cast 'false', false
201
+
202
+ assert_cast nil, nil
203
+ end
204
+
186
205
  def test_format_symbol
187
206
  schema :string, format: :symbol
188
207
 
@@ -200,6 +219,84 @@ module Schemacop
200
219
  assert_cast('039n23$g- sfk3/', :'039n23$g- sfk3/')
201
220
  end
202
221
 
222
+ def test_format_integer
223
+ schema :string, format: :integer
224
+
225
+ assert_json(type: :string, format: :integer)
226
+
227
+ assert_validation '23425'
228
+ assert_validation '-23425'
229
+
230
+ assert_validation 12_312 do
231
+ error '/', StringNodeTest.invalid_type_error(Integer)
232
+ end
233
+
234
+ assert_validation '24.32' do
235
+ error '/', 'String does not match format "integer".'
236
+ end
237
+
238
+ assert_cast(nil, nil)
239
+ assert_cast('2234', 2234)
240
+ assert_cast('-1', -1)
241
+ assert_cast('-0', 0)
242
+ end
243
+
244
+ def test_format_integer_list
245
+ schema :string, format: :integer_list
246
+
247
+ assert_json(type: :string, format: :'integer-list')
248
+
249
+ assert_validation '1,2,3,4'
250
+ assert_validation '1,2,-3,-54'
251
+ assert_validation '2'
252
+ assert_validation '-2'
253
+
254
+ assert_validation 234 do
255
+ error '/', StringNodeTest.invalid_type_error(Integer)
256
+ end
257
+
258
+ assert_validation 'sd sfdij soidf' do
259
+ error '/', 'String does not match format "integer-list".'
260
+ end
261
+
262
+ assert_cast nil, nil
263
+ assert_cast '1,-2,3', [1, -2, 3]
264
+ assert_cast '1', [1]
265
+ assert_cast '-1', [-1]
266
+ assert_cast '08', [8]
267
+ assert_cast '09', [9]
268
+ assert_cast '050', [50]
269
+ assert_cast '01,032', [1, 32]
270
+ end
271
+
272
+ def test_format_custom
273
+ Schemacop.register_string_formatter(
274
+ :integer_tuple_list,
275
+ pattern: /^(-?[0-9]+):(-?[0-9]+)(,(-?[0-9]+):(-?[0-9]+))*$/,
276
+ handler: proc do |value|
277
+ value.split(',').map { |t| t.split(':').map(&:to_i) }
278
+ end
279
+ )
280
+
281
+ schema :string, format: :integer_tuple_list
282
+
283
+ assert_json(type: :string, format: :'integer-tuple-list')
284
+
285
+ assert_validation '1:5,4:2,-4:4,4:-1,0:0'
286
+ assert_validation '-1:5'
287
+
288
+ assert_validation 234 do
289
+ error '/', StringNodeTest.invalid_type_error(Integer)
290
+ end
291
+
292
+ assert_validation 'sd sfdij soidf' do
293
+ error '/', 'String does not match format "integer-tuple-list".'
294
+ end
295
+
296
+ assert_cast nil, nil
297
+ assert_cast '1:2,3:4,5:-6', [[1, 2], [3, 4], [5, -6]]
298
+ end
299
+
203
300
  def test_enum
204
301
  schema :string, enum: ['foo', 'some string', 'some other string', 42]
205
302
 
@@ -224,33 +321,6 @@ module Schemacop
224
321
  end
225
322
  end
226
323
 
227
- def test_boolean_casting
228
- schema :string, format: :boolean
229
-
230
- assert_json(type: :string, format: :boolean)
231
-
232
- assert_cast 'true', true
233
- assert_cast 'false', false
234
-
235
- assert_cast nil, nil
236
- end
237
-
238
- def test_time_casting
239
- schema :string, format: :time
240
- assert_json(type: :string, format: :time)
241
- assert_cast '20:30:39+00:00', Time.strptime('20:30:39+00:00', '%H:%M:%S%z')
242
-
243
- assert_cast nil, nil
244
- end
245
-
246
- def test_date_casting
247
- schema :string, format: :date
248
- assert_json(type: :string, format: :date)
249
- assert_cast '2018-11-13', Date.new(2018, 11, 13)
250
-
251
- assert_cast nil, nil
252
- end
253
-
254
324
  def test_date_time_casting
255
325
  schema :string, format: :date_time
256
326
  assert_json(type: :string, format: :'date-time')
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.12
4
+ version: 3.0.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sitrox
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-14 00:00:00.000000000 Z
11
+ date: 2021-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -164,8 +164,8 @@ dependencies:
164
164
  - - '='
165
165
  - !ruby/object:Gem::Version
166
166
  version: 0.21.2
167
- description:
168
- email:
167
+ description:
168
+ email:
169
169
  executables: []
170
170
  extensions: []
171
171
  extra_rdoc_files: []
@@ -277,7 +277,7 @@ homepage: https://github.com/sitrox/schemacop
277
277
  licenses:
278
278
  - MIT
279
279
  metadata: {}
280
- post_install_message:
280
+ post_install_message:
281
281
  rdoc_options: []
282
282
  require_paths:
283
283
  - lib
@@ -292,8 +292,8 @@ 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
296
- signing_key:
295
+ rubygems_version: 3.2.22
296
+ signing_key:
297
297
  specification_version: 4
298
298
  summary: Schemacop validates ruby structures consisting of nested hashes and arrays
299
299
  against simple schema definitions.