json-schema-serializer 1.5.0 → 2.0.0

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: 0efb6d3beb44452ee9a2aa14ac89bd465e8c23ecbaf7cb650ff39faeaf22f19d
4
- data.tar.gz: f9d35967622b23c02a1a09cfad3c33c3af0f1bf38de295d365732231d0926011
3
+ metadata.gz: 301107414cad9b1f2e8845d86633a36354e32b9ca7a45bb6611a1b42c4ece2ce
4
+ data.tar.gz: 7d2c5f7bb39e5d59278073a779abf70979d86870009c6195f764ee37da5c6c5f
5
5
  SHA512:
6
- metadata.gz: c1905cf229d6fd7c484fb3703eb507a4fb7641c28b840ee2e045b250fd688502b8c09dcb36bb28d191b1d36a7c5772040c0bd10297f6ba533e4d676d191c02a1
7
- data.tar.gz: c24cd2d21e573339dd9b861b4f6936753f78ed63d6f7988316608d9315d1322689c3bac080873ee4e54a0327073d89545c77d51576ebd4bc6ebe842ce6fb2b19
6
+ metadata.gz: 4305c335b4a52abd9631bc11fb93b7268b7d0a235939f86be68dff2f3d8569df3b7908a33e4b9b45417c5f7b7b928a28b334d8feaad91e012079c3670ee512bd
7
+ data.tar.gz: f7a3ac83d661e4ddd546fae884600e61c1dce9119347ed0a93e3ee574c66c38bb4647a40f0c6f84e295804b3c620864e65c549e1b38e5f69429805fcc9a675a8
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"
@@ -173,13 +345,6 @@ serializer2 = JSON::Schema::Serializer.new(schema["properties"]["bar"], {
173
345
 
174
346
  The initializer.
175
347
 
176
- # @param schema [any] JSON schema object. The serializer tries schema["type"], schema[:type] and schema.type!
177
- # @param options [Hash] options
178
- # @option options [Proc] :resolver schema object resolver
179
- # @option options [Hashlike<String, Class>] :injectors If schema has inject key, the serializer treats injectors[inject_key].new(data).
180
- # @option options [String, Symbol] :inject_key inject key
181
- # @option
182
-
183
348
  #### schema [any]
184
349
 
185
350
  JSON schema object. The serializer tries schema["type"], schema[:type] and schema.type!
@@ -192,7 +357,7 @@ options
192
357
 
193
358
  schema object `$ref` resolver
194
359
 
195
- #### options[:input_key_transform] [Proc]
360
+ #### options[:schema_key_transform_for_input] [Proc]
196
361
 
197
362
  input key transform
198
363
 
@@ -202,10 +367,10 @@ new({
202
367
  properties: {
203
368
  userCount: { type: :integer },
204
369
  },
205
- }, { 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 }
206
371
  ```
207
372
 
208
- #### options[:output_key_transform] [Proc]
373
+ #### options[:schema_key_transform_for_output] [Proc]
209
374
 
210
375
  output key transform
211
376
 
@@ -215,15 +380,21 @@ new({
215
380
  properties: {
216
381
  userCount: { type: :integer },
217
382
  },
218
- }, { 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 }
219
384
  ```
220
385
 
221
- #### 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]
222
387
 
223
388
  If schema has inject key, the serializer treats data by `injectors[inject_key].new(data)` (or `injectors.send(inject_key).new(data)`).
224
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
+
225
394
  See examples in [Usage](#usage).
226
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
+
227
398
  #### options[:null_through] [Boolean]
228
399
 
229
400
  If data is null, always serialize null.
@@ -282,6 +453,14 @@ Serialize the object data by the schema.
282
453
 
283
454
  Serialize target object. The serializer tries data["foo"], data[:foo] and data.foo!
284
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
+
285
464
  ## License
286
465
 
287
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
@@ -221,6 +264,9 @@ module JSON
221
264
  elsif obj.respond_to?(name)
222
265
  obj.send(name)
223
266
  end
267
+ rescue
268
+ p [name, obj]
269
+ raise
224
270
  end
225
271
 
226
272
  def is_primitive?(obj)
@@ -1,7 +1,7 @@
1
1
  module JSON
2
2
  class Schema
3
3
  class Serializer
4
- VERSION = "1.5.0".freeze
4
+ VERSION = "2.0.0".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.0
4
+ version: 2.0.0
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.0
198
+ documentation_uri: https://www.rubydoc.info/gems/json-schema-serializer/2.0.0
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