schemacop 3.0.14 → 3.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README_V3.md +18 -0
- data/VERSION +1 -1
- data/lib/schemacop/v3/string_node.rb +6 -35
- data/lib/schemacop.rb +74 -0
- data/schemacop.gemspec +2 -2
- data/test/unit/schemacop/v3/string_node_test.rb +69 -27
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e43238e69ebe95beaac85536a9dadbf3233bd4fa5751c7e019ca6d07aa05860
|
4
|
+
data.tar.gz: 8bafd412f0572e0c12a7c163cba48b6f6f69900ec903684dc3c9495b4913cf52
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9da291f938673bf76f55f4f4fddbf5a3355fe9c72ae30f8be8c9e224b9bea2f1a89dbcb2da8312ddbaca09dcd25da5511e904963400633d9ef193014da9ee0ec
|
7
|
+
data.tar.gz: 21793a6a7f3fc730a123f7ed8ceacde1e930620b77fef63c7e30c919a9e9ebf3372a8a5208dbdf177880e011322f529d04558bd68d363cbfd85b023a1f2ed265
|
data/CHANGELOG.md
CHANGED
data/README_V3.md
CHANGED
@@ -252,6 +252,24 @@ transformed into various types.
|
|
252
252
|
* `symbol`
|
253
253
|
The string can be anything and will be casted to a ruby `Symbol` object.
|
254
254
|
|
255
|
+
#### Custom Formats
|
256
|
+
|
257
|
+
You can also implement your custom formats or override the behavior of the
|
258
|
+
standard formats. This can be done in the initializer configuration (in case of
|
259
|
+
a Rails appliation):
|
260
|
+
|
261
|
+
```ruby
|
262
|
+
# config/initializers/schemacop.rb
|
263
|
+
Schemacop.register_string_formatter(
|
264
|
+
:character_array, # Formatter name
|
265
|
+
pattern: /^[a-zA-Z](,[a-zA-Z])*/, # Regex pattern for validation
|
266
|
+
handler: ->(value) { value.split(',') } # Casting callback
|
267
|
+
)
|
268
|
+
|
269
|
+
# In your schema
|
270
|
+
str! :my_list, format: :character_array
|
271
|
+
```
|
272
|
+
|
255
273
|
#### Examples
|
256
274
|
|
257
275
|
```ruby
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.0.
|
1
|
+
3.0.15
|
@@ -7,21 +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|0|1)$/,
|
17
|
-
binary: nil,
|
18
|
-
symbol: nil,
|
19
|
-
integer: /^-?[0-9]+$/,
|
20
|
-
number: /^-?[0-9]+(\.[0-9]+)?$/,
|
21
|
-
'integer-list': /^(-?[0-9]+)(,-?[0-9]+)*$/
|
22
|
-
}.freeze
|
23
|
-
# rubocop:enable Layout/LineLength
|
24
|
-
|
25
10
|
def self.allowed_options
|
26
11
|
super + ATTRIBUTES + %i[format_options pattern allow_blank]
|
27
12
|
end
|
@@ -71,8 +56,9 @@ module Schemacop
|
|
71
56
|
end
|
72
57
|
|
73
58
|
# Validate format #
|
74
|
-
if options[:format] &&
|
75
|
-
pattern =
|
59
|
+
if options[:format] && Schemacop.string_formatters.include?(options[:format])
|
60
|
+
pattern = Schemacop.string_formatters[options[:format]][:pattern]
|
61
|
+
|
76
62
|
if pattern && !super_data.match?(pattern)
|
77
63
|
result.error "String does not match format #{options[:format].to_s.inspect}."
|
78
64
|
elsif options[:format_options] && Node.resolve_class(options[:format])
|
@@ -91,23 +77,8 @@ module Schemacop
|
|
91
77
|
return nil
|
92
78
|
end
|
93
79
|
|
94
|
-
|
95
|
-
|
96
|
-
%w[true 1].include?(to_cast)
|
97
|
-
when :date
|
98
|
-
return Date.parse(to_cast)
|
99
|
-
when :'date-time'
|
100
|
-
return DateTime.parse(to_cast)
|
101
|
-
when :time
|
102
|
-
Time.parse(to_cast)
|
103
|
-
when :integer
|
104
|
-
return Integer(to_cast)
|
105
|
-
when :number
|
106
|
-
return Float(to_cast)
|
107
|
-
when :'integer-list'
|
108
|
-
return to_cast.split(',').map(&:to_i)
|
109
|
-
when :symbol
|
110
|
-
return to_cast.to_sym
|
80
|
+
if (handler = Schemacop.string_formatters.dig(options[:format], :handler))
|
81
|
+
return handler.call(to_cast)
|
111
82
|
else
|
112
83
|
return to_cast
|
113
84
|
end
|
@@ -122,7 +93,7 @@ module Schemacop
|
|
122
93
|
end
|
123
94
|
|
124
95
|
def validate_self
|
125
|
-
if options.include?(:format) && !
|
96
|
+
if options.include?(:format) && !Schemacop.string_formatters.include?(options[:format])
|
126
97
|
fail "Format #{options[:format].to_s.inspect} is not supported."
|
127
98
|
end
|
128
99
|
|
data/lib/schemacop.rb
CHANGED
@@ -13,6 +13,80 @@ 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
|
+
def self.register_string_formatter(name, pattern:, handler:)
|
20
|
+
name = name.to_s.dasherize.to_sym
|
21
|
+
|
22
|
+
string_formatters[name] = {
|
23
|
+
pattern: pattern,
|
24
|
+
handler: handler
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
register_string_formatter(
|
29
|
+
:date,
|
30
|
+
pattern: /^([0-9]{4})-?(1[0-2]|0[1-9])-?(3[01]|0[1-9]|[12][0-9])$/,
|
31
|
+
handler: ->(value) { Date.parse(value) }
|
32
|
+
)
|
33
|
+
|
34
|
+
# rubocop: disable Layout/LineLength
|
35
|
+
register_string_formatter(
|
36
|
+
:'date-time',
|
37
|
+
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])?$/,
|
38
|
+
handler: ->(value) { DateTime.parse(value) }
|
39
|
+
)
|
40
|
+
# rubocop: enable Layout/LineLength
|
41
|
+
|
42
|
+
register_string_formatter(
|
43
|
+
:time,
|
44
|
+
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])?$/,
|
45
|
+
handler: ->(value) { Time.parse(value) }
|
46
|
+
)
|
47
|
+
|
48
|
+
register_string_formatter(
|
49
|
+
:email,
|
50
|
+
pattern: URI::MailTo::EMAIL_REGEXP,
|
51
|
+
handler: ->(value) { value }
|
52
|
+
)
|
53
|
+
|
54
|
+
register_string_formatter(
|
55
|
+
:boolean,
|
56
|
+
pattern: /^(true|false|0|1)$/,
|
57
|
+
handler: ->(value) { %w[true 1].include?(value) }
|
58
|
+
)
|
59
|
+
|
60
|
+
register_string_formatter(
|
61
|
+
:binary,
|
62
|
+
pattern: nil,
|
63
|
+
handler: ->(value) { value }
|
64
|
+
)
|
65
|
+
|
66
|
+
register_string_formatter(
|
67
|
+
:symbol,
|
68
|
+
pattern: nil,
|
69
|
+
handler: ->(value) { value.to_sym }
|
70
|
+
)
|
71
|
+
|
72
|
+
register_string_formatter(
|
73
|
+
:integer,
|
74
|
+
pattern: /^-?[0-9]+$/,
|
75
|
+
handler: ->(value) { Integer(value) }
|
76
|
+
)
|
77
|
+
|
78
|
+
register_string_formatter(
|
79
|
+
:number,
|
80
|
+
pattern: /^-?[0-9]+(\.[0-9]+)?$/,
|
81
|
+
handler: ->(value) { Float(value) }
|
82
|
+
)
|
83
|
+
|
84
|
+
register_string_formatter(
|
85
|
+
:'integer-list',
|
86
|
+
pattern: /^(-?[0-9]+)(,-?[0-9]+)*$/,
|
87
|
+
handler: ->(value) { value.split(',').map(&:to_i) }
|
88
|
+
)
|
89
|
+
|
16
90
|
def self.with_context(context)
|
17
91
|
prev_context = Thread.current[CONTEXT_THREAD_KEY]
|
18
92
|
Thread.current[CONTEXT_THREAD_KEY] = context
|
data/schemacop.gemspec
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: schemacop 3.0.
|
2
|
+
# stub: schemacop 3.0.15 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "schemacop".freeze
|
6
|
-
s.version = "3.0.
|
6
|
+
s.version = "3.0.15"
|
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]
|
@@ -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,28 @@ 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
|
+
|
203
244
|
def test_format_integer_list
|
204
245
|
schema :string, format: :integer_list
|
205
246
|
|
@@ -224,6 +265,34 @@ module Schemacop
|
|
224
265
|
assert_cast '-1', [-1]
|
225
266
|
end
|
226
267
|
|
268
|
+
def test_format_custom
|
269
|
+
Schemacop.register_string_formatter(
|
270
|
+
:integer_tuple_list,
|
271
|
+
pattern: /^(-?[0-9]+):(-?[0-9]+)(,(-?[0-9]+):(-?[0-9]+))*$/,
|
272
|
+
handler: proc do |value|
|
273
|
+
value.split(',').map { |t| t.split(':').map(&:to_i) }
|
274
|
+
end
|
275
|
+
)
|
276
|
+
|
277
|
+
schema :string, format: :integer_tuple_list
|
278
|
+
|
279
|
+
assert_json(type: :string, format: :'integer-tuple-list')
|
280
|
+
|
281
|
+
assert_validation '1:5,4:2,-4:4,4:-1,0:0'
|
282
|
+
assert_validation '-1:5'
|
283
|
+
|
284
|
+
assert_validation 234 do
|
285
|
+
error '/', StringNodeTest.invalid_type_error(Integer)
|
286
|
+
end
|
287
|
+
|
288
|
+
assert_validation 'sd sfdij soidf' do
|
289
|
+
error '/', 'String does not match format "integer-tuple-list".'
|
290
|
+
end
|
291
|
+
|
292
|
+
assert_cast nil, nil
|
293
|
+
assert_cast '1:2,3:4,5:-6', [[1, 2], [3, 4], [5, -6]]
|
294
|
+
end
|
295
|
+
|
227
296
|
def test_enum
|
228
297
|
schema :string, enum: ['foo', 'some string', 'some other string', 42]
|
229
298
|
|
@@ -248,33 +317,6 @@ module Schemacop
|
|
248
317
|
end
|
249
318
|
end
|
250
319
|
|
251
|
-
def test_boolean_casting
|
252
|
-
schema :string, format: :boolean
|
253
|
-
|
254
|
-
assert_json(type: :string, format: :boolean)
|
255
|
-
|
256
|
-
assert_cast 'true', true
|
257
|
-
assert_cast 'false', false
|
258
|
-
|
259
|
-
assert_cast nil, nil
|
260
|
-
end
|
261
|
-
|
262
|
-
def test_time_casting
|
263
|
-
schema :string, format: :time
|
264
|
-
assert_json(type: :string, format: :time)
|
265
|
-
assert_cast '20:30:39+00:00', Time.strptime('20:30:39+00:00', '%H:%M:%S%z')
|
266
|
-
|
267
|
-
assert_cast nil, nil
|
268
|
-
end
|
269
|
-
|
270
|
-
def test_date_casting
|
271
|
-
schema :string, format: :date
|
272
|
-
assert_json(type: :string, format: :date)
|
273
|
-
assert_cast '2018-11-13', Date.new(2018, 11, 13)
|
274
|
-
|
275
|
-
assert_cast nil, nil
|
276
|
-
end
|
277
|
-
|
278
320
|
def test_date_time_casting
|
279
321
|
schema :string, format: :date_time
|
280
322
|
assert_json(type: :string, format: :'date-time')
|