json-schema-serializer 1.5.1 → 2.0.1
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/.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
|