schemacop 3.0.12 → 3.0.16

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: 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.