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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37e694cb4884a1ca5064e0d0ec1ec8e8c71b4033f802c60eda6c409cbc47eae2
4
- data.tar.gz: abbc2a9dae69d938498280fcd70b27ee2b0d4d575271112b3196b9655b1a0686
3
+ metadata.gz: 98a8247eb1adc250801738b4056a8cb48af71a3b58f47636993a46aab2593951
4
+ data.tar.gz: 6eaab852b30a1b1ad23d3ced5a55fb17a010ca5a97f259e23f61ebe8589eedf6
5
5
  SHA512:
6
- metadata.gz: 20ccc5691d1928f7869be012a310096f4e8c1ae0a879a954126cd1c478e7596a2d7f523e22f1efba91e8c2735bea6c32960da6db9d0c2b973f49feec6d8e6c5f
7
- data.tar.gz: b9c86efa2961c16b00c9ba072277e7d98e12a8c6f6d4e86dbef6c366785bdcd054c35766a227586907e4e5ea3a05eb5a2fdcd59265dfa15b89ad629fea1e580e
6
+ metadata.gz: 4271739806fd52a9363a68459a760f3e5753fe7ea293fe9dd2ccc722b3204cb4c1673937de900891d013dcd7bc5e5177c4f2893c41aaecf81ad6358fe37cd430
7
+ data.tar.gz: 496676d7b7a47a46ecadb2ef6b55dad7fb26417821ac54737991d2d7e5254f903fc57310a30c51930e40e0da73e61c4caa0c74e9382be43345e0d866b4579588
File without changes
data/.gitignore CHANGED
File without changes
File without changes
data/.rspec CHANGED
File without changes
File without changes
File without changes
@@ -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[:input_key_transform] [Proc]
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
- }, { input_key_transform: ->(name) { name.underscore } }).serialize({ user_count: 1 }) == { "userCount" => 1 }
370
+ }, { schema_key_transform_for_input: ->(name) { name.underscore } }).serialize({ user_count: 1 }) == { "userCount" => 1 }
199
371
  ```
200
372
 
201
- #### options[:output_key_transform] [Proc]
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
- }, { output_key_transform: ->(name) { name.underscore } }).serialize({ userCount: 1 }) == { "user_count" => 1 }
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
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", "~> 10.5"
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
- obj = default if obj.nil?
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 = injector.new(obj) if injector
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[:input_key_transform] # schema key -> input obj key
193
- output_key_transform = options[:output_key_transform] # schema key -> out
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
@@ -1,7 +1,7 @@
1
1
  module JSON
2
2
  class Schema
3
3
  class Serializer
4
- VERSION = "1.5.1".freeze
4
+ VERSION = "2.0.1".freeze
5
5
  end
6
6
  end
7
7
  end
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: 1.5.1
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: 2019-12-03 00:00:00.000000000 Z
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: '10.5'
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: '10.5'
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/1.5.1
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
- rubyforge_project:
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