schemacop 3.0.14 → 3.0.15
Sign up to get free protection for your applications and to get access to all the features.
- 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')
|