json-schema-serializer 1.5.1 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +0 -0
- data/.gitignore +0 -0
- data/.prettierrc +0 -0
- data/.rspec +0 -0
- data/.rubocop.yml +0 -0
- data/.rubocop_airbnb.yml +0 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +0 -0
- data/LICENSE +0 -0
- data/README.md +191 -5
- data/Rakefile +0 -0
- data/bin/console +0 -0
- data/bin/fmt +0 -0
- data/bin/setup +0 -0
- data/json-schema-serializer.gemspec +2 -1
- data/lib/json/schema/serializer.rb +55 -12
- data/lib/json/schema/serializer/version.rb +1 -1
- metadata +20 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98a8247eb1adc250801738b4056a8cb48af71a3b58f47636993a46aab2593951
|
4
|
+
data.tar.gz: 6eaab852b30a1b1ad23d3ced5a55fb17a010ca5a97f259e23f61ebe8589eedf6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4271739806fd52a9363a68459a760f3e5753fe7ea293fe9dd2ccc722b3204cb4c1673937de900891d013dcd7bc5e5177c4f2893c41aaecf81ad6358fe37cd430
|
7
|
+
data.tar.gz: 496676d7b7a47a46ecadb2ef6b55dad7fb26417821ac54737991d2d7e5254f903fc57310a30c51930e40e0da73e61c4caa0c74e9382be43345e0d866b4579588
|
data/.github/workflows/ruby.yml
CHANGED
File without changes
|
data/.gitignore
CHANGED
File without changes
|
data/.prettierrc
CHANGED
File without changes
|
data/.rspec
CHANGED
File without changes
|
data/.rubocop.yml
CHANGED
File without changes
|
data/.rubocop_airbnb.yml
CHANGED
File without changes
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 2.0.0
|
4
|
+
|
5
|
+
- fix: Non-primitive (arrays, objects, etc.) "default" schemas and injections have strange results.
|
6
|
+
- If you were using a non-primitive (array, object, etc.) "default" schema with injection, it could be a breaking change!
|
7
|
+
|
8
|
+
## 1.7.0
|
9
|
+
|
10
|
+
- add: `with_context!` api
|
11
|
+
- add: `:inject_by_keyword` option
|
12
|
+
|
13
|
+
## 1.6.0
|
14
|
+
|
15
|
+
- add: inject context
|
16
|
+
|
3
17
|
## 1.5.0
|
4
18
|
|
5
19
|
- add: many options
|
data/Gemfile
CHANGED
File without changes
|
data/LICENSE
CHANGED
File without changes
|
data/README.md
CHANGED
@@ -112,6 +112,178 @@ serializer_injected = JSON::Schema::Serializer.new(
|
|
112
112
|
|
113
113
|
serializer_injected.serialize([1, 2, 3])
|
114
114
|
# => {"first"=>1, "count"=>3}
|
115
|
+
|
116
|
+
#
|
117
|
+
# object injector with context
|
118
|
+
#
|
119
|
+
|
120
|
+
class BarSerializer
|
121
|
+
def initialize(model, context = nil)
|
122
|
+
@model = model
|
123
|
+
@context = context
|
124
|
+
end
|
125
|
+
|
126
|
+
def id
|
127
|
+
@model[:id]
|
128
|
+
end
|
129
|
+
|
130
|
+
def score
|
131
|
+
@context[@model[:id]]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
inject_context = {
|
136
|
+
1 => 100,
|
137
|
+
2 => 200,
|
138
|
+
}
|
139
|
+
|
140
|
+
serializer_injected_with_context = JSON::Schema::Serializer.new(
|
141
|
+
{
|
142
|
+
type: :object,
|
143
|
+
inject: :Bar,
|
144
|
+
properties: {
|
145
|
+
id: { type: :integer },
|
146
|
+
score: { type: :integer },
|
147
|
+
},
|
148
|
+
},
|
149
|
+
{
|
150
|
+
inject_key: :inject,
|
151
|
+
injectors: {
|
152
|
+
Bar: BarSerializer,
|
153
|
+
},
|
154
|
+
inject_context: inject_context,
|
155
|
+
},
|
156
|
+
)
|
157
|
+
|
158
|
+
serializer_injected_with_context.serialize({ id: 1 })
|
159
|
+
# => { "id" => 1, "score" => 100 }
|
160
|
+
|
161
|
+
#
|
162
|
+
# inject in serializer
|
163
|
+
#
|
164
|
+
|
165
|
+
class ParentSerializer
|
166
|
+
include JSON::Schema::Serializer::WithContext
|
167
|
+
|
168
|
+
def initialize(model, context = nil)
|
169
|
+
@model = model
|
170
|
+
@context = context
|
171
|
+
end
|
172
|
+
|
173
|
+
def id
|
174
|
+
@model[:id]
|
175
|
+
end
|
176
|
+
|
177
|
+
def score
|
178
|
+
@context[:parent_scores][@model[:id]]
|
179
|
+
end
|
180
|
+
|
181
|
+
def child
|
182
|
+
# it can be
|
183
|
+
# with_context(context) { data }
|
184
|
+
# with_context(data, context)
|
185
|
+
# with_context(data: data, context: context)
|
186
|
+
with_context(@context.merge(child_scores: { 1 => 100, 2 => 200 })) do
|
187
|
+
@model[:child]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
class ChildSerializer
|
193
|
+
def initialize(model, context = nil)
|
194
|
+
@model = model
|
195
|
+
@context = context
|
196
|
+
end
|
197
|
+
|
198
|
+
def id
|
199
|
+
@model[:id]
|
200
|
+
end
|
201
|
+
|
202
|
+
def score
|
203
|
+
@context[:child_scores][@model[:id]]
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
serializer_injected_with_context_in_serializer = JSON::Schema::Serializer.new(
|
208
|
+
{
|
209
|
+
type: :object,
|
210
|
+
inject: :Parent,
|
211
|
+
properties: {
|
212
|
+
id: { type: :integer },
|
213
|
+
score: { type: :integer },
|
214
|
+
child: {
|
215
|
+
type: :object,
|
216
|
+
inject: :Child,
|
217
|
+
properties: {
|
218
|
+
id: { type: :integer },
|
219
|
+
score: { type: :integer },
|
220
|
+
},
|
221
|
+
},
|
222
|
+
},
|
223
|
+
},
|
224
|
+
{
|
225
|
+
inject_key: :inject,
|
226
|
+
injectors: {
|
227
|
+
Parent: ParentSerializer,
|
228
|
+
Child: ChildSerializer,
|
229
|
+
},
|
230
|
+
inject_context: { 1 => 10, 2 => 20 },
|
231
|
+
},
|
232
|
+
)
|
233
|
+
|
234
|
+
serializer_injected_with_context_in_serializer.serialize({ id: 1, child: { id: 2 } })
|
235
|
+
# => { "id" => 1, "score" => 10, "child" => { "id" => 2, "score" => 200 } }
|
236
|
+
|
237
|
+
#
|
238
|
+
# also you can inject context with arraylike data
|
239
|
+
#
|
240
|
+
|
241
|
+
class ItemsSerializer
|
242
|
+
include JSON::Schema::Serializer::WithContext
|
243
|
+
|
244
|
+
def initialize(models, context = nil)
|
245
|
+
@models = models
|
246
|
+
@context = context
|
247
|
+
end
|
248
|
+
|
249
|
+
def map(&block)
|
250
|
+
context = (@context || {}).merge(scores: {...})
|
251
|
+
@models.map { |model| block.call(with_context(model, context)) }
|
252
|
+
# CAUTION!
|
253
|
+
# not like below!
|
254
|
+
# with_context(@models.map(&block), context)
|
255
|
+
# with_context(context) { @models.map(&block) }
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
#
|
260
|
+
# inject model can initialize by keywords
|
261
|
+
#
|
262
|
+
|
263
|
+
class KeywordSerializer
|
264
|
+
def initialize(data:, context: nil)
|
265
|
+
@data = data
|
266
|
+
@context = context
|
267
|
+
end
|
268
|
+
|
269
|
+
...
|
270
|
+
end
|
271
|
+
|
272
|
+
serializer_with_keyword_init_inject = JSON::Schema::Serializer.new(
|
273
|
+
{
|
274
|
+
type: :object,
|
275
|
+
inject: :Keyword,
|
276
|
+
properties: { ... },
|
277
|
+
},
|
278
|
+
{
|
279
|
+
inject_key: :inject,
|
280
|
+
injectors: {
|
281
|
+
Keyword: KeywordSerializer,
|
282
|
+
Child: ChildSerializer,
|
283
|
+
},
|
284
|
+
inject_by_keyword: true, # <- keyword_init!
|
285
|
+
},
|
286
|
+
)
|
115
287
|
```
|
116
288
|
|
117
289
|
### "additionalProperties"
|
@@ -185,7 +357,7 @@ options
|
|
185
357
|
|
186
358
|
schema object `$ref` resolver
|
187
359
|
|
188
|
-
#### options[:
|
360
|
+
#### options[:schema_key_transform_for_input] [Proc]
|
189
361
|
|
190
362
|
input key transform
|
191
363
|
|
@@ -195,10 +367,10 @@ new({
|
|
195
367
|
properties: {
|
196
368
|
userCount: { type: :integer },
|
197
369
|
},
|
198
|
-
}, {
|
370
|
+
}, { schema_key_transform_for_input: ->(name) { name.underscore } }).serialize({ user_count: 1 }) == { "userCount" => 1 }
|
199
371
|
```
|
200
372
|
|
201
|
-
#### options[:
|
373
|
+
#### options[:schema_key_transform_for_output] [Proc]
|
202
374
|
|
203
375
|
output key transform
|
204
376
|
|
@@ -208,15 +380,21 @@ new({
|
|
208
380
|
properties: {
|
209
381
|
userCount: { type: :integer },
|
210
382
|
},
|
211
|
-
}, {
|
383
|
+
}, { schema_key_transform_for_output: ->(name) { name.underscore } }).serialize({ userCount: 1 }) == { "user_count" => 1 }
|
212
384
|
```
|
213
385
|
|
214
|
-
#### options[:injectors] [Hashlike<String, Class>, Class], options[:inject_key] [String, Symbol]
|
386
|
+
#### options[:injectors] [Hashlike<String, Class>, Class], options[:inject_key] [String, Symbol], options[:inject_context] [any], options[:inject_by_keyword] [Boolean]
|
215
387
|
|
216
388
|
If schema has inject key, the serializer treats data by `injectors[inject_key].new(data)` (or `injectors.send(inject_key).new(data)`).
|
217
389
|
|
390
|
+
And if `inject_context` is present, `injectors[inject_key].new(data, inject_context)` (or `injectors.send(inject_key).new(data, inject_context)`).
|
391
|
+
|
392
|
+
And if `inject_by_keyword` is true, `new(data, inject_context)` will be `new(data: data, context: inject_context)`.
|
393
|
+
|
218
394
|
See examples in [Usage](#usage).
|
219
395
|
|
396
|
+
CAUTION: In many case you should define the `nil?` method in the injector class because Injector always initialized by `Injector.new(obj)` even if obj == nil.
|
397
|
+
|
220
398
|
#### options[:null_through] [Boolean]
|
221
399
|
|
222
400
|
If data is null, always serialize null.
|
@@ -275,6 +453,14 @@ Serialize the object data by the schema.
|
|
275
453
|
|
276
454
|
Serialize target object. The serializer tries data["foo"], data[:foo] and data.foo!
|
277
455
|
|
456
|
+
## JSON::Schema::Serializer::WithContext API
|
457
|
+
|
458
|
+
### #with_context!(data, context), #with_context!(data: data, context: context), #with_context!(context) { data }
|
459
|
+
|
460
|
+
If you use `with_context!(data, context)` as the return value of the serializer, then "child" serializer can use that context.
|
461
|
+
|
462
|
+
See examples in [Usage](#usage).
|
463
|
+
|
278
464
|
## License
|
279
465
|
|
280
466
|
Zlib License
|
data/Rakefile
CHANGED
File without changes
|
data/bin/console
CHANGED
File without changes
|
data/bin/fmt
CHANGED
File without changes
|
data/bin/setup
CHANGED
File without changes
|
@@ -28,9 +28,10 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.require_paths = %w[lib]
|
29
29
|
|
30
30
|
spec.add_development_dependency "bundler", "~> 2.0"
|
31
|
-
spec.add_development_dependency "rake", "~>
|
31
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
32
32
|
spec.add_development_dependency "rspec", "~> 3.9"
|
33
33
|
spec.add_development_dependency "rspec-power_assert", "~> 1.1"
|
34
|
+
spec.add_development_dependency "simplecov", ">= 0.18"
|
34
35
|
spec.add_development_dependency "rubocop", "~> 0.76"
|
35
36
|
spec.add_development_dependency "rubocop-airbnb", "~> 3"
|
36
37
|
spec.add_development_dependency "prettier", ">= 0.16"
|
@@ -5,31 +5,74 @@ require "set"
|
|
5
5
|
module JSON
|
6
6
|
class Schema
|
7
7
|
class Serializer
|
8
|
-
def initialize(schema, options = nil)
|
8
|
+
def initialize(schema, options = nil) # rubocop:disable Airbnb/OptArgParameters
|
9
9
|
@schema = options && options[:resolver] ? options[:resolver].call(schema) : schema
|
10
10
|
@options = options || {}
|
11
11
|
end
|
12
12
|
|
13
13
|
def serialize(data)
|
14
|
-
Walker.walk(@schema, data, true, @options)
|
14
|
+
Walker.walk(@schema, data, true, false, @options)
|
15
|
+
end
|
16
|
+
|
17
|
+
DataWithContext = Struct.new(:data, :context, keyword_init: true)
|
18
|
+
|
19
|
+
module WithContext
|
20
|
+
ARG2_NOT_GIVEN = :__json_schema_serializer_arg2_not_given__
|
21
|
+
|
22
|
+
def with_context!(arg1, arg2 = ARG2_NOT_GIVEN) # rubocop:disable Airbnb/OptArgParameters
|
23
|
+
if block_given?
|
24
|
+
DataWithContext.new(data: yield, context: arg1)
|
25
|
+
elsif arg2 == ARG2_NOT_GIVEN
|
26
|
+
DataWithContext.new(arg1)
|
27
|
+
else
|
28
|
+
DataWithContext.new(data: arg1, context: arg2)
|
29
|
+
end
|
30
|
+
end
|
15
31
|
end
|
16
32
|
|
17
33
|
class Walker
|
18
34
|
class << self
|
19
35
|
TimeWithZone = defined?(ActiveSupport::TimeWithZone) ? ActiveSupport::TimeWithZone : nil
|
20
36
|
|
21
|
-
def walk(schema, obj, required, options)
|
37
|
+
def walk(schema, obj, required, using_default, options)
|
22
38
|
type = try_hash(schema, :type)
|
23
39
|
default = try_hash(schema, :default)
|
24
40
|
format = try_hash(schema, :format)
|
25
|
-
|
41
|
+
if obj.nil?
|
42
|
+
using_default = true
|
43
|
+
obj = default
|
44
|
+
end
|
26
45
|
|
27
46
|
if options[:inject_key]
|
28
47
|
inject_key = try_hash(schema, options[:inject_key])
|
29
48
|
injector = try_hash(options[:injectors], inject_key) if inject_key
|
30
|
-
obj
|
49
|
+
if obj.instance_of?(JSON::Schema::Serializer::DataWithContext)
|
50
|
+
options = options.merge(inject_context: obj.context)
|
51
|
+
obj = obj.data
|
52
|
+
if obj.nil?
|
53
|
+
using_default = true
|
54
|
+
obj = default
|
55
|
+
end
|
56
|
+
end
|
57
|
+
if injector && !using_default
|
58
|
+
if options[:inject_context]
|
59
|
+
obj =
|
60
|
+
if options[:inject_by_keyword]
|
61
|
+
injector.new(data: obj, context: options[:inject_context])
|
62
|
+
else
|
63
|
+
injector.new(obj, options[:inject_context])
|
64
|
+
end
|
65
|
+
else
|
66
|
+
obj =
|
67
|
+
if options[:inject_by_keyword]
|
68
|
+
injector.new(data: obj)
|
69
|
+
else
|
70
|
+
injector.new(obj)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
31
74
|
end
|
32
|
-
type_coerce(schema, detect_type(type, obj), format, obj, required, options)
|
75
|
+
type_coerce(schema, detect_type(type, obj), format, obj, required, using_default, options)
|
33
76
|
end
|
34
77
|
|
35
78
|
def detect_type(type, obj)
|
@@ -112,7 +155,7 @@ module JSON
|
|
112
155
|
end
|
113
156
|
end
|
114
157
|
|
115
|
-
def type_coerce(schema, type, format, obj, required, options)
|
158
|
+
def type_coerce(schema, type, format, obj, required, using_default, options)
|
116
159
|
return nil if !required && obj.nil?
|
117
160
|
|
118
161
|
case type.to_s
|
@@ -181,7 +224,7 @@ module JSON
|
|
181
224
|
return options[:null_through] ? nil : [] if obj.nil? || !obj.respond_to?(:map)
|
182
225
|
return options[:null_through] ? nil : [] if options[:guard_primitive_in_structure] && is_primitive?(obj)
|
183
226
|
|
184
|
-
obj.map { |item| walk(items_schema, item, true, options) }
|
227
|
+
obj.map { |item| walk(items_schema, item, true, using_default, options) }
|
185
228
|
when "object"
|
186
229
|
return nil if obj.nil? && options[:null_through]
|
187
230
|
return options[:null_through] ? nil : {} if options[:guard_primitive_in_structure] && is_primitive?(obj)
|
@@ -189,13 +232,13 @@ module JSON
|
|
189
232
|
properties_schema = try_hash(schema, :properties)
|
190
233
|
additional_properties_schema = try_hash(schema, :additionalProperties)
|
191
234
|
required_schema = Set.new(try_hash(schema, :required)&.map(&:to_s))
|
192
|
-
input_key_transform = options[:
|
193
|
-
output_key_transform = options[:
|
235
|
+
input_key_transform = options[:schema_key_transform_for_input] # schema key -> input obj key
|
236
|
+
output_key_transform = options[:schema_key_transform_for_output] # schema key -> out
|
194
237
|
ret =
|
195
238
|
properties_schema.map do |name, property_schema|
|
196
239
|
input_key = input_key_transform ? input_key_transform.call(name.to_s) : name
|
197
240
|
output_key = output_key_transform ? output_key_transform.call(name.to_s) : name.to_s
|
198
|
-
[output_key, walk(property_schema, try_hash(obj, input_key), required_schema.include?(name.to_s), options)]
|
241
|
+
[output_key, walk(property_schema, try_hash(obj, input_key), required_schema.include?(name.to_s), using_default, options)]
|
199
242
|
end.to_h
|
200
243
|
if additional_properties_schema
|
201
244
|
not_additional_keys_array = properties_schema.keys.map(&:to_s)
|
@@ -204,7 +247,7 @@ module JSON
|
|
204
247
|
ret.merge(
|
205
248
|
additional_keys.map do |name|
|
206
249
|
output_key = output_key_transform ? output_key_transform.call(name.to_s) : name.to_s
|
207
|
-
[output_key, walk(additional_properties_schema, try_hash(obj, name), false, options)]
|
250
|
+
[output_key, walk(additional_properties_schema, try_hash(obj, name), false, using_default, options)]
|
208
251
|
end.to_h,
|
209
252
|
)
|
210
253
|
else
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json-schema-serializer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Narazaka
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-11-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '13.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '13.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.18'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.18'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rubocop
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -181,7 +195,7 @@ metadata:
|
|
181
195
|
homepage_uri: https://github.com/Narazaka/json-schema-serializer
|
182
196
|
source_code_uri: https://github.com/Narazaka/json-schema-serializer.git
|
183
197
|
changelog_uri: https://github.com/Narazaka/json-schema-serializer/blob/master/CHANGELOG.md
|
184
|
-
documentation_uri: https://www.rubydoc.info/gems/json-schema-serializer/
|
198
|
+
documentation_uri: https://www.rubydoc.info/gems/json-schema-serializer/2.0.1
|
185
199
|
post_install_message:
|
186
200
|
rdoc_options: []
|
187
201
|
require_paths:
|
@@ -197,8 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
197
211
|
- !ruby/object:Gem::Version
|
198
212
|
version: '0'
|
199
213
|
requirements: []
|
200
|
-
|
201
|
-
rubygems_version: 2.7.6
|
214
|
+
rubygems_version: 3.0.3
|
202
215
|
signing_key:
|
203
216
|
specification_version: 4
|
204
217
|
summary: JSON Schema based serializer
|