json-schema-serializer 1.6.0 → 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54b6ef10587ab0aaeb6bb6aa85ae56daef39f714c356ace19352336c04864ae8
4
- data.tar.gz: 360d4fef03c36d567ae2e229c2632bca7af26ce9c4e19ec036590917ecffdd93
3
+ metadata.gz: 1f891febd1f289cd33579bb3045a776978fce4efe25e1971b563a618fe5522f8
4
+ data.tar.gz: e9f6317e62a8a57d1f999d10977dd61e9b570ccc71a59182780a2ca78f4e5283
5
5
  SHA512:
6
- metadata.gz: 4a1fe23e623221c1651c681562fedaa146578f6e495fb23989e4358e75e63d78b63b8d18443e3a52db0ff0f65a3bca58b263177cac8f616ceabe6b9bb964b2ae
7
- data.tar.gz: 929372326ff9c370c1d04df9d36e3da7d2183a05354cb34cbaee7fe334b7e609eec75267371108c3953db7efa8edfc8208f40155bc79496e8f0632dec539df43
6
+ metadata.gz: f56d91ec30edc66a16ca515ea2876427099e9ae452a7ca601208fd52d0b6f89cd312302e6f99429a9288cf5eee22ff54fd1abc06133b41bb07d7b771dafe7c3a
7
+ data.tar.gz: 8b00053eb322dd58488d9895afe5179d3dc9a7d3560c92cb865897276d372a5c692e992c79df1a25aeafb109c53cc2ae9b3ab1b38dc8447678c58a7235f8601b
@@ -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/README.md CHANGED
@@ -157,6 +157,133 @@ serializer_injected_with_context = JSON::Schema::Serializer.new(
157
157
 
158
158
  serializer_injected_with_context.serialize({ id: 1 })
159
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
+ )
160
287
  ```
161
288
 
162
289
  ### "additionalProperties"
@@ -256,12 +383,14 @@ new({
256
383
  }, { schema_key_transform_for_output: ->(name) { name.underscore } }).serialize({ userCount: 1 }) == { "user_count" => 1 }
257
384
  ```
258
385
 
259
- #### options[:injectors] [Hashlike<String, Class>, Class], options[:inject_key] [String, Symbol], options[:inject_context] [any]
386
+ #### options[:injectors] [Hashlike<String, Class>, Class], options[:inject_key] [String, Symbol], options[:inject_context] [any], options[:inject_by_keyword] [Boolean]
260
387
 
261
388
  If schema has inject key, the serializer treats data by `injectors[inject_key].new(data)` (or `injectors.send(inject_key).new(data)`).
262
389
 
263
390
  And if `inject_context` is present, `injectors[inject_key].new(data, inject_context)` (or `injectors.send(inject_key).new(data, inject_context)`).
264
391
 
392
+ And if `inject_by_keyword` is true, `new(data, inject_context)` will be `new(data: data, context: inject_context)`.
393
+
265
394
  See examples in [Usage](#usage).
266
395
 
267
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.
@@ -324,6 +453,14 @@ Serialize the object data by the schema.
324
453
 
325
454
  Serialize target object. The serializer tries data["foo"], data[:foo] and data.foo!
326
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
+
327
464
  ## License
328
465
 
329
466
  Zlib License
@@ -0,0 +1,5 @@
1
+ target :lib do
2
+ signature "sig"
3
+
4
+ check "lib"
5
+ end
@@ -38,4 +38,5 @@ Gem::Specification.new do |spec|
38
38
  spec.add_development_dependency "rubocop-config-prettier", "~> 0.1"
39
39
  spec.add_development_dependency "pry-byebug", "~> 3.7"
40
40
  spec.add_development_dependency "yard", "~> 0.9"
41
+ spec.add_development_dependency "steep", ">= 0.39"
41
42
  end
@@ -6,36 +6,78 @@ module JSON
6
6
  class Schema
7
7
  class Serializer
8
8
  def initialize(schema, options = nil) # rubocop:disable Airbnb/OptArgParameters
9
- @schema = options && options[:resolver] ? options[:resolver].call(schema) : schema
9
+ @schema =
10
+ if options && (resolver = options[:resolver])
11
+ resolver.call(schema)
12
+ else
13
+ schema
14
+ end
10
15
  @options = options || {}
11
16
  end
12
17
 
13
18
  def serialize(data)
14
- Walker.walk(@schema, data, true, @options)
19
+ Walker.walk(@schema, data, true, false, @options)
20
+ end
21
+
22
+ DataWithContext = Struct.new(:data, :context, keyword_init: true)
23
+
24
+ module WithContext
25
+ ARG2_NOT_GIVEN = :__json_schema_serializer_arg2_not_given__
26
+
27
+ def with_context!(arg1, arg2 = ARG2_NOT_GIVEN) # rubocop:disable Airbnb/OptArgParameters
28
+ if block_given?
29
+ DataWithContext.new(data: yield, context: arg1)
30
+ elsif arg2 == ARG2_NOT_GIVEN
31
+ DataWithContext.new(arg1)
32
+ else
33
+ DataWithContext.new(data: arg1, context: arg2)
34
+ end
35
+ end
15
36
  end
16
37
 
17
38
  class Walker
18
39
  class << self
19
40
  TimeWithZone = defined?(ActiveSupport::TimeWithZone) ? ActiveSupport::TimeWithZone : nil
20
41
 
21
- def walk(schema, obj, required, options)
42
+ def walk(schema, obj, required, using_default, options)
22
43
  type = try_hash(schema, :type)
23
44
  default = try_hash(schema, :default)
24
45
  format = try_hash(schema, :format)
25
- obj = default if obj.nil?
46
+ if obj.nil?
47
+ using_default = true
48
+ obj = default
49
+ end
26
50
 
27
51
  if options[:inject_key]
28
52
  inject_key = try_hash(schema, options[:inject_key])
29
53
  injector = try_hash(options[:injectors], inject_key) if inject_key
30
- if injector
54
+ if obj.instance_of?(JSON::Schema::Serializer::DataWithContext)
55
+ options = options.merge(inject_context: obj.context)
56
+ obj = obj.data
57
+ if obj.nil?
58
+ using_default = true
59
+ obj = default
60
+ end
61
+ end
62
+ if injector && !using_default
31
63
  if options[:inject_context]
32
- obj = injector.new(obj, options[:inject_context])
64
+ obj =
65
+ if options[:inject_by_keyword]
66
+ injector.new(data: obj, context: options[:inject_context])
67
+ else
68
+ injector.new(obj, options[:inject_context])
69
+ end
33
70
  else
34
- obj = injector.new(obj)
71
+ obj =
72
+ if options[:inject_by_keyword]
73
+ injector.new(data: obj)
74
+ else
75
+ injector.new(obj)
76
+ end
35
77
  end
36
78
  end
37
79
  end
38
- type_coerce(schema, detect_type(type, obj), format, obj, required, options)
80
+ type_coerce(schema, detect_type(type, obj), format, obj, required, using_default, options)
39
81
  end
40
82
 
41
83
  def detect_type(type, obj)
@@ -118,7 +160,7 @@ module JSON
118
160
  end
119
161
  end
120
162
 
121
- def type_coerce(schema, type, format, obj, required, options)
163
+ def type_coerce(schema, type, format, obj, required, using_default, options)
122
164
  return nil if !required && obj.nil?
123
165
 
124
166
  case type.to_s
@@ -175,8 +217,8 @@ module JSON
175
217
  nil
176
218
  elsif options[:empty_string_boolean_coerce_null] && obj == ""
177
219
  nil
178
- elsif options[:false_values]
179
- !options[:false_values].include?(obj)
220
+ elsif (false_values = options[:false_values])
221
+ !false_values.include?(obj)
180
222
  elsif options[:no_boolean_coerce]
181
223
  obj == true
182
224
  else
@@ -187,7 +229,7 @@ module JSON
187
229
  return options[:null_through] ? nil : [] if obj.nil? || !obj.respond_to?(:map)
188
230
  return options[:null_through] ? nil : [] if options[:guard_primitive_in_structure] && is_primitive?(obj)
189
231
 
190
- obj.map { |item| walk(items_schema, item, true, options) }
232
+ obj.map { |item| walk(items_schema, item, true, using_default, options) }
191
233
  when "object"
192
234
  return nil if obj.nil? && options[:null_through]
193
235
  return options[:null_through] ? nil : {} if options[:guard_primitive_in_structure] && is_primitive?(obj)
@@ -201,7 +243,7 @@ module JSON
201
243
  properties_schema.map do |name, property_schema|
202
244
  input_key = input_key_transform ? input_key_transform.call(name.to_s) : name
203
245
  output_key = output_key_transform ? output_key_transform.call(name.to_s) : name.to_s
204
- [output_key, walk(property_schema, try_hash(obj, input_key), required_schema.include?(name.to_s), options)]
246
+ [output_key, walk(property_schema, try_hash(obj, input_key), required_schema.include?(name.to_s), using_default, options)]
205
247
  end.to_h
206
248
  if additional_properties_schema
207
249
  not_additional_keys_array = properties_schema.keys.map(&:to_s)
@@ -210,7 +252,7 @@ module JSON
210
252
  ret.merge(
211
253
  additional_keys.map do |name|
212
254
  output_key = output_key_transform ? output_key_transform.call(name.to_s) : name.to_s
213
- [output_key, walk(additional_properties_schema, try_hash(obj, name), false, options)]
255
+ [output_key, walk(additional_properties_schema, try_hash(obj, name), false, using_default, options)]
214
256
  end.to_h,
215
257
  )
216
258
  else
@@ -1,7 +1,7 @@
1
1
  module JSON
2
2
  class Schema
3
3
  class Serializer
4
- VERSION = "1.6.0".freeze
4
+ VERSION = "2.1.1".freeze
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,59 @@
1
+ type jsonSchema = untyped
2
+ type jsonData = untyped
3
+ type jsonSchemaContext = untyped
4
+ type jsonSingleType = "null" | "string" | "number" | "integer" | "boolean" | "array" | "object"
5
+ type jsonType = jsonSingleType | Array[jsonSingleType]
6
+
7
+ # Classes
8
+ module JSON
9
+ class Schema
10
+ class Serializer
11
+ VERSION: String
12
+
13
+ type serializerOptions = {
14
+ inject_key: String | Symbol?,
15
+ inject_context: jsonSchemaContext?,
16
+ injectors: Hash[String | Symbol, Class] | Class?,
17
+ inject_by_keyword: bool?,
18
+ resolver: (^(jsonData data) -> jsonData)?,
19
+ null_through: bool?,
20
+ empty_string_number_coerce_null: bool?,
21
+ empty_string_boolean_coerce_null: bool?,
22
+ false_values: Enumerable[untyped]?,
23
+ no_boolean_coerce: bool?,
24
+ guard_primitive_in_structure: bool?,
25
+ schema_key_transform_for_input: (^(String name) -> String)?,
26
+ schema_key_transform_for_output: (^(String name) -> String)?
27
+ }
28
+ @schema: jsonSchema
29
+ @options: serializerOptions
30
+
31
+ def initialize: (jsonSchema schema, ?serializerOptions options) -> void
32
+ def serialize: (jsonData data) -> untyped
33
+
34
+ class DataWithContext < Struct[untyped]
35
+ attr_accessor data(): jsonData
36
+ attr_accessor context(): jsonSchemaContext
37
+ def initialize: (data: jsonData, context: jsonSchemaContext) -> void
38
+ end
39
+
40
+ module WithContext
41
+ ARG2_NOT_GIVEN: :__json_schema_serializer_arg2_not_given__
42
+
43
+ def with_context!: (jsonSchemaContext context) { () -> jsonData } -> DataWithContext
44
+ | (jsonData data, jsonSchemaContext context) -> DataWithContext
45
+ | ({ data: jsonData, context: jsonSchemaContext } arg) -> DataWithContext
46
+ end
47
+
48
+ class Walker
49
+ TimeWithZone: nil
50
+
51
+ def self.walk: (jsonSchema schema, jsonData obj, bool required, bool using_default, serializerOptions options) -> untyped
52
+ def self.detect_type: (jsonType type_, jsonData obj) -> jsonSingleType
53
+ def self.type_coerce: (jsonSchema schema, jsonType type_, String format, jsonData obj, bool required, bool using_default, serializerOptions options) -> untyped
54
+ def self.try_hash: (untyped obj, String | Symbol? name) -> untyped
55
+ def self.is_primitive?: (untyped obj) -> bool
56
+ end
57
+ end
58
+ end
59
+ 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.6.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Narazaka
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-10 00:00:00.000000000 Z
11
+ date: 2020-12-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -164,7 +164,21 @@ dependencies:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0.9'
167
- description:
167
+ - !ruby/object:Gem::Dependency
168
+ name: steep
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0.39'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0.39'
181
+ description:
168
182
  email:
169
183
  - info@narazaka.net
170
184
  executables: []
@@ -182,12 +196,14 @@ files:
182
196
  - LICENSE
183
197
  - README.md
184
198
  - Rakefile
199
+ - Steepfile
185
200
  - bin/console
186
201
  - bin/fmt
187
202
  - bin/setup
188
203
  - json-schema-serializer.gemspec
189
204
  - lib/json/schema/serializer.rb
190
205
  - lib/json/schema/serializer/version.rb
206
+ - sig/json/schema/serializer.rbs
191
207
  homepage: https://github.com/Narazaka/json-schema-serializer
192
208
  licenses:
193
209
  - Zlib
@@ -195,8 +211,8 @@ metadata:
195
211
  homepage_uri: https://github.com/Narazaka/json-schema-serializer
196
212
  source_code_uri: https://github.com/Narazaka/json-schema-serializer.git
197
213
  changelog_uri: https://github.com/Narazaka/json-schema-serializer/blob/master/CHANGELOG.md
198
- documentation_uri: https://www.rubydoc.info/gems/json-schema-serializer/1.6.0
199
- post_install_message:
214
+ documentation_uri: https://www.rubydoc.info/gems/json-schema-serializer/2.1.1
215
+ post_install_message:
200
216
  rdoc_options: []
201
217
  require_paths:
202
218
  - lib
@@ -211,9 +227,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
227
  - !ruby/object:Gem::Version
212
228
  version: '0'
213
229
  requirements: []
214
- rubyforge_project:
215
- rubygems_version: 2.7.6
216
- signing_key:
230
+ rubygems_version: 3.2.3
231
+ signing_key:
217
232
  specification_version: 4
218
233
  summary: JSON Schema based serializer
219
234
  test_files: []