serega 0.12.0 → 0.14.0

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: 52535c7fab3897f65aec4e156ab5681e8595b4519df1e79a777688cee486a480
4
- data.tar.gz: 16adbd9f036b0e23928049df873966f264db1004d2c4c1bc9e28422d687efd12
3
+ metadata.gz: f11821b5953500ef9f895ad8c96e97951734615363f3147c623b70519b6199a5
4
+ data.tar.gz: 8b03241a9def2e5a8777a75e61062f8b81544e497a1a1e490e085d52f14a326c
5
5
  SHA512:
6
- metadata.gz: 93a6aaefdf954556e31bd604ead1e376d5ffbb74225251e635bf5133af53da26f47e924f1f88349fa4656e228ddca573347d9f8fa15cc30bc6052f7e5dfec3bd
7
- data.tar.gz: c84135d04c79aae1ccd03a3f3ac7dbed53dbf75165575afbb61ad6e32a558318cac2a8311c31b76df90fb74823facdf4677821d8f7ae8284f04782d33b04ad41
6
+ metadata.gz: eb5cb48e74c0e9c8307c6ceb6c47b918eb46ef3c160de90d0eb976239bbc036f1d3fb78219abd5567977f348e3e03d7e492e29140e6d85223fcf14289d794d89
7
+ data.tar.gz: acb7623ea317aab640aae70d0a5dfa0c436b706529741b36b15d938ab6af7523576f72ab4633b591b61dcdc38df768818eab3811005c248c3a00d2872cdccc46
data/README.md CHANGED
@@ -888,6 +888,107 @@ Look at [select serialized fields](#selecting-fields) for `:hide` usage examples
888
888
  end
889
889
  ```
890
890
 
891
+ ### Plugin :openapi
892
+
893
+ Helps to build OpenAPI schemas
894
+
895
+ This schemas can be easily used with [rswag](https://github.com/rswag/rswag#referenced-parameters-and-schema-definitions)"
896
+ gem by adding them to "config.swagger_docs"
897
+
898
+ Schemas properties will have no any "type" or other limits specified by default,
899
+ you should provide them as new attribute `:openapi` option.
900
+
901
+ This plugin adds type "object" or "array" only for relationships and marks
902
+ attributes as **required** if they have no `:hide` option set
903
+ (manually or automatically).
904
+
905
+ After enabling this plugin attributes with :serializer option will have
906
+ to have `:many` option set to construct "object" or "array" openapi
907
+ property type.
908
+
909
+ - constructing all serializers schemas:
910
+ `Serega::OpenAPI.schemas`
911
+ - constructing specific serializers schemas:
912
+ `Serega::OpenAPI.schemas(Serega::OpenAPI.serializers - [MyBaseSerializer])`
913
+ - constructing one serializer schema:
914
+ `SomeSerializer.openapi_schema`
915
+
916
+ ```ruby
917
+ class BaseSerializer < Serega
918
+ plugin :openapi
919
+ end
920
+
921
+ class UserSerializer < BaseSerializer
922
+ attribute :name, openapi: { type: "string" }
923
+
924
+ openapi_properties(
925
+ name: { type: :string }
926
+ )
927
+ end
928
+
929
+ class PostSerializer < BaseSerializer
930
+ attribute :text, openapi: { type: "string" }
931
+ attribute :user, serializer: UserSerializer, many: false
932
+ attribute :comments, serializer: PostSerializer, many: true, hide: true
933
+
934
+ openapi_properties(
935
+ text: { type: :string },
936
+ user: { type: 'object' }, # `$ref` added automatically
937
+ comments: { type: 'array' } # `items` option with `$ref` added automatically
938
+ )
939
+ end
940
+
941
+ puts Serega::OpenAPI.schemas
942
+ # =>
943
+ # {
944
+ # "PostSerializer" => {
945
+ # type: "object",
946
+ # properties: {
947
+ # text: {type: "string"},
948
+ # user: {:$ref => "#/components/schemas/UserSerializer"},
949
+ # comments: {type: "array", items: {:$ref => "#/components/schemas/PostSerializer"}}
950
+ # },
951
+ # required: [:text, :comments],
952
+ # additionalProperties: false
953
+ # },
954
+ # "UserSerializer" => {
955
+ # type: "object",
956
+ # properties: {
957
+ # name: {type: "string"}
958
+ # },
959
+ # required: [:name],
960
+ # additionalProperties: false
961
+ # }
962
+ # }
963
+ ```
964
+
965
+ ### Plugin :explicit_many_option
966
+
967
+ Plugin requires to add :many option when adding relationships
968
+ (relationships are attributes with :serializer option specified)
969
+
970
+ Adding this plugin makes clearer to find if relationship returns array or single
971
+ object
972
+
973
+ Also plugin `:openapi` load this plugin automatically as it need to know if
974
+ relationship is array
975
+
976
+ ```ruby
977
+ class BaseSerializer < Serega
978
+ plugin :explicit_many_option
979
+ end
980
+
981
+ class UserSerializer < BaseSerializer
982
+ attribute :name
983
+ end
984
+
985
+ class PostSerializer < BaseSerializer
986
+ attribute :text
987
+ attribute :user, serializer: UserSerializer, many: false
988
+ attribute :comments, serializer: PostSerializer, many: true
989
+ end
990
+ ```
991
+
891
992
  ## Errors
892
993
 
893
994
  - `Serega::SeregaError` is a base error raised by this gem.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.12.0
1
+ 0.14.0
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module SeregaPlugins
5
+ #
6
+ # Plugin :explicit_many_option
7
+ #
8
+ # Plugin requires to add :many option when adding relationships
9
+ # (relationships are attributes with :serializer option specified)
10
+ #
11
+ # Adding this plugin makes clearer to find if relationship returns array or single object
12
+ #
13
+ # Also some plugins like :openapi load this plugin automatically as they need to know if
14
+ # relationship is array
15
+ #
16
+ # @example
17
+ # class BaseSerializer < Serega
18
+ # plugin :explicit_many_option
19
+ # end
20
+ #
21
+ # class UserSerializer < BaseSerializer
22
+ # attribute :name
23
+ # end
24
+ #
25
+ # class PostSerializer < BaseSerializer
26
+ # attribute :text
27
+ # attribute :user, serializer: UserSerializer, many: false
28
+ # attribute :comments, serializer: PostSerializer, many: true
29
+ # end
30
+ #
31
+ module ExplicitManyOption
32
+ # @return [Symbol] Plugin name
33
+ def self.plugin_name
34
+ :explicit_many_option
35
+ end
36
+
37
+ #
38
+ # Applies plugin code to specific serializer
39
+ #
40
+ # @param serializer_class [Class<Serega>] Current serializer class
41
+ # @param _opts [Hash] Loaded plugins options
42
+ #
43
+ # @return [void]
44
+ #
45
+ def self.load_plugin(serializer_class, **_opts)
46
+ require_relative "./validations/check_opt_many"
47
+
48
+ serializer_class::CheckAttributeParams.include(CheckAttributeParamsInstanceMethods)
49
+ end
50
+
51
+ #
52
+ # Serega::SeregaValidations::CheckAttributeParams additional/patched class methods
53
+ #
54
+ # @see Serega::SeregaValidations::CheckAttributeParams
55
+ #
56
+ module CheckAttributeParamsInstanceMethods
57
+ private
58
+
59
+ def check_opts
60
+ super
61
+
62
+ CheckOptMany.call(opts)
63
+ end
64
+ end
65
+ end
66
+
67
+ register_plugin(ExplicitManyOption.plugin_name, ExplicitManyOption)
68
+ end
69
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module SeregaPlugins
5
+ module ExplicitManyOption
6
+ #
7
+ # Validator for attribute :many option
8
+ #
9
+ class CheckOptMany
10
+ class << self
11
+ #
12
+ # Checks attribute :many option must be provided with relations
13
+ #
14
+ # @param opts [Hash] Attribute options
15
+ #
16
+ # @raise [SeregaError] Attribute validation error
17
+ #
18
+ # @return [void]
19
+ #
20
+ def call(opts)
21
+ serializer = opts[:serializer]
22
+ return unless serializer
23
+
24
+ many_option_exists = opts.key?(:many)
25
+ return if many_option_exists
26
+
27
+ raise SeregaError,
28
+ "Attribute option :many [Boolean] must be provided" \
29
+ " for attributes with :serializer option"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module SeregaPlugins
5
+ module OpenAPI
6
+ #
7
+ # Config class additional/patched instance methods
8
+ #
9
+ # @see Serega::SeregaConfig
10
+ #
11
+ module ConfigInstanceMethods
12
+ #
13
+ # Returns openapi plugin config
14
+ #
15
+ # @return [Serega::SeregaPlugins::OpenAPI::OpenAPIConfig] configuration for openapi plugin
16
+ #
17
+ def openapi
18
+ @openapi ||= OpenAPIConfig.new(self.class.serializer_class, opts.fetch(:openapi))
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module SeregaPlugins
5
+ module OpenAPI
6
+ #
7
+ # OpenAPI plugin config
8
+ #
9
+ class OpenAPIConfig
10
+ attr_reader :serializer_class, :opts
11
+
12
+ def initialize(serializer_class, opts)
13
+ @serializer_class = serializer_class
14
+ @opts = opts
15
+ end
16
+
17
+ #
18
+ # Saves new properties
19
+ #
20
+ # @param new_properties [Hash] new properties
21
+ #
22
+ # @return [Hash] OpenAPI properties
23
+ #
24
+ def properties(new_properties = FROZEN_EMPTY_HASH)
25
+ properties = opts[:properties]
26
+ return properties if new_properties.empty?
27
+
28
+ new_properties = SeregaUtils::EnumDeepDup.call(new_properties)
29
+ symbolize_keys!(new_properties)
30
+
31
+ new_properties.each do |attribute_name, new_attribute_properties|
32
+ check_attribute_exists(attribute_name)
33
+ check_properties_is_a_hash(attribute_name, new_attribute_properties)
34
+
35
+ properties[attribute_name] = symbolize_keys!(new_attribute_properties)
36
+ end
37
+ end
38
+
39
+ #
40
+ # @return [#call] builder of `$ref` attribute
41
+ #
42
+ def ref_builder
43
+ opts[:ref_builder]
44
+ end
45
+
46
+ #
47
+ # Sets new $ref option builder
48
+ #
49
+ # @param builder [#call] Callable object that accepts serializer_class and constructs $ref option string
50
+ #
51
+ # @return Specified new builder
52
+ #
53
+ def ref_builder=(builder)
54
+ raise SeregaError, "ref_builder must respond to #call" unless builder.respond_to?(:call)
55
+ opts[:ref_builder] = builder
56
+ end
57
+
58
+ #
59
+ # @return [#call] builder of schema name
60
+ #
61
+ def schema_name_builder
62
+ opts[:schema_name_builder]
63
+ end
64
+
65
+ #
66
+ # Sets new schema_name_builder
67
+ #
68
+ # @param builder [#call] Callable object that accepts serializer_class and
69
+ # constructs schema name to use in schemas list and in $ref option
70
+ #
71
+ # @return Specified new builder
72
+ #
73
+ def schema_name_builder=(builder)
74
+ raise SeregaError, "schema_name_builder must respond to #call" unless builder.respond_to?(:call)
75
+ opts[:schema_name_builder] = builder
76
+ end
77
+
78
+ private
79
+
80
+ def check_attribute_exists(attribute_name)
81
+ return if serializer_class.attributes.key?(attribute_name)
82
+
83
+ raise SeregaError, "No attribute with name :#{attribute_name}"
84
+ end
85
+
86
+ def check_properties_is_a_hash(attribute_name, new_attribute_properties)
87
+ return if new_attribute_properties.is_a?(Hash)
88
+
89
+ raise SeregaError, "Property #{attribute_name} value must be a Hash," \
90
+ " but #{new_attribute_properties.inspect} was provided"
91
+ end
92
+
93
+ def symbolize_keys!(opts)
94
+ opts.transform_keys! do |key|
95
+ key.to_sym
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,245 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ #
5
+ # Utility class to build OpenAPI schemas
6
+ #
7
+ class OpenAPI
8
+ #
9
+ # Constructs OpenAPI schemas for multiple serializers
10
+ #
11
+ # @params serializers [Class<Serega>] Serializers tobuild schemas,
12
+ # by default it is all serializers with :openapi plugin enabled
13
+ #
14
+ # @return [Hash] Schemas hash
15
+ #
16
+ def self.schemas(serializers = self.serializers)
17
+ serializers.each_with_object({}) do |serializer_class, schemas|
18
+ schema = serializer_class.openapi_schema
19
+ schema_name = serializer_class.openapi_schema_name
20
+ schemas[schema_name] = schema
21
+ end
22
+ end
23
+
24
+ #
25
+ # Returns list of serializers with :openapi plugin
26
+ #
27
+ def self.serializers
28
+ @serializers ||= []
29
+ end
30
+ end
31
+
32
+ module SeregaPlugins
33
+ #
34
+ # Plugin :openapi
35
+ #
36
+ # Helps to build OpenAPI schemas
37
+ #
38
+ # This schemas can be easielty used with "rswag" gem by adding them to "config.swagger_docs"
39
+ # https://github.com/rswag/rswag#referenced-parameters-and-schema-definitions
40
+ #
41
+ # This plugin only adds type "object" or "array" for relationships and marks
42
+ # attributes as **required** if they have no :hide option set.
43
+ #
44
+ # OpenAPI properties will have no any "type" or other options specified by default,
45
+ # you should provide them in 'YourSerializer.openapi_properties' method.
46
+ # `openapi_properties` can be specified multiple time, in this case they wil be merged.
47
+ #
48
+ # After enabling this plugin attributes with :serializer option will have
49
+ # to have :many option set to construct "object" or "array" openapi type for relationships.
50
+ #
51
+ # OpenAPI `$ref` property will be added automatically for all relationships.
52
+ #
53
+ # Example constructing all serializers schemas:
54
+ # `Serega::OpenAPI.schemas`
55
+ #
56
+ # Example constructing specific serializers schemas:
57
+ # `Serega::OpenAPI.schemas(Serega::OpenAPI.serializers - [MyBaseSerializer])`
58
+ #
59
+ # Example constructing one serializer schema:
60
+ # `SomeSerializer.openapi_schema`
61
+ #
62
+ # @example
63
+ # class BaseSerializer < Serega
64
+ # plugin :openapi
65
+ # end
66
+ #
67
+ # class UserSerializer < BaseSerializer
68
+ # attribute :name
69
+ #
70
+ # openapi_properties(
71
+ # name: { type: :string }
72
+ # )
73
+ # end
74
+ #
75
+ # class PostSerializer < BaseSerializer
76
+ # attribute :text
77
+ # attribute :user, serializer: UserSerializer, many: false
78
+ # attribute :comments, serializer: PostSerializer, many: true, hide: true
79
+ #
80
+ # openapi_properties(
81
+ # text: { type: :string },
82
+ # user: { type: 'object' }, # `$ref` option will be added automatically when constructing schema
83
+ # comments: { type: 'array' } # `items` option with `$ref` will be added automatically when constructing schema
84
+ # )
85
+ # end
86
+ #
87
+ # puts Serega::OpenAPI.schemas
88
+ # =>
89
+ # {
90
+ # "PostSerializer" => {
91
+ # type: "object",
92
+ # properties: {
93
+ # text: {type: "string"},
94
+ # user: {:$ref => "#/components/schemas/UserSerializer"},
95
+ # comments: {type: "array", items: {:$ref => "#/components/schemas/PostSerializer"}}
96
+ # },
97
+ # required: [:text, :comments],
98
+ # additionalProperties: false
99
+ # },
100
+ # "UserSerializer" => {
101
+ # type: "object",
102
+ # properties: {
103
+ # name: {type: "string"}
104
+ # },
105
+ # required: [:name],
106
+ # additionalProperties: false
107
+ # }
108
+ # }
109
+ #
110
+ module OpenAPI
111
+ # Builder for schema name (used is schemas list). Returns serializer class name
112
+ DEFAULT_SCHEMA_NAME_BUILDER = ->(serializer_class) { serializer_class.name }
113
+
114
+ # Builder for $ref openapi property
115
+ DEFAULT_REF_BUILDER = ->(serializer_class) { "#/components/schemas/#{serializer_class.openapi_schema_name}" }
116
+
117
+ # @return [Symbol] Plugin name
118
+ def self.plugin_name
119
+ :openapi
120
+ end
121
+
122
+ # Checks requirements and loads additional plugins
123
+ #
124
+ # @param serializer_class [Class<Serega>] Current serializer class
125
+ # @param opts [Hash] loaded plugins opts
126
+ #
127
+ # @return [void]
128
+ #
129
+ def self.before_load_plugin(serializer_class, **opts)
130
+ unless serializer_class.plugin_used?(:explicit_many_option)
131
+ serializer_class.plugin :explicit_many_option
132
+ end
133
+ end
134
+
135
+ #
136
+ # Applies plugin code to specific serializer
137
+ #
138
+ # @param serializer_class [Class<Serega>] Current serializer class
139
+ # @param _opts [Hash] Loaded plugins options
140
+ #
141
+ # @return [void]
142
+ #
143
+ def self.load_plugin(serializer_class, **opts)
144
+ require_relative "./lib/modules/config"
145
+ require_relative "./lib/openapi_config"
146
+
147
+ serializer_class.extend(ClassMethods)
148
+ serializer_class::SeregaConfig.include(ConfigInstanceMethods)
149
+
150
+ config = serializer_class.config
151
+ config.opts[:openapi] = {properties: {}}
152
+ openapi_config = serializer_class.config.openapi
153
+ openapi_config.schema_name_builder = opts[:schema_name_builder] || DEFAULT_SCHEMA_NAME_BUILDER
154
+ openapi_config.ref_builder = opts[:ref_builder] || DEFAULT_REF_BUILDER
155
+ end
156
+
157
+ #
158
+ # Adds config options and runs other callbacks after plugin was loaded
159
+ #
160
+ # @param serializer_class [Class<Serega>] Current serializer class
161
+ # @param opts [Hash] loaded plugins opts
162
+ #
163
+ # @return [void]
164
+ #
165
+ def self.after_load_plugin(serializer_class, **opts)
166
+ Serega::OpenAPI.serializers << serializer_class unless serializer_class.equal?(Serega)
167
+ end
168
+
169
+ #
170
+ # Serega additional/patched class methods
171
+ #
172
+ # @see Serega
173
+ #
174
+ module ClassMethods
175
+ #
176
+ # OpenAPI schema for current serializer
177
+ #
178
+ def openapi_schema
179
+ properties = SeregaUtils::EnumDeepDup.call(openapi_properties)
180
+ required_properties = []
181
+
182
+ attributes.each do |attribute_name, attribute|
183
+ add_openapi_property(properties, attribute_name, attribute)
184
+ add_openapi_required_property(required_properties, attribute_name, attribute)
185
+ end
186
+
187
+ {
188
+ type: "object",
189
+ properties: properties,
190
+ required: required_properties,
191
+ additionalProperties: false
192
+ }
193
+ end
194
+
195
+ #
196
+ # Adds new OpenAPI properties and returns all properties
197
+ #
198
+ # @param props [Hash] Specifies new properties
199
+ #
200
+ # @return [Hash] Specified OpenAPI properties
201
+ #
202
+ def openapi_properties(props = FROZEN_EMPTY_HASH)
203
+ config.openapi.properties(props)
204
+ end
205
+
206
+ #
207
+ # Builds OpenAPI schema name using configured builder
208
+ #
209
+ # @return [String] OpenAPI schema name
210
+ #
211
+ def openapi_schema_name
212
+ config.openapi.schema_name_builder.call(self)
213
+ end
214
+
215
+ private
216
+
217
+ def inherited(subclass)
218
+ super
219
+ Serega::OpenAPI.serializers << subclass
220
+ end
221
+
222
+ def add_openapi_property(properties, attribute_name, attribute)
223
+ property = properties[attribute_name] ||= {}
224
+ return unless attribute.relation?
225
+
226
+ ref = attribute.serializer.config.openapi.ref_builder.call(attribute.serializer)
227
+
228
+ if attribute.many
229
+ property[:type] = "array"
230
+ property[:items] ||= {}
231
+ property[:items][:$ref] ||= ref
232
+ else
233
+ property[:$ref] ||= ref
234
+ end
235
+ end
236
+
237
+ def add_openapi_required_property(required_properties, attribute_name, attribute)
238
+ required_properties << attribute_name unless attribute.hide
239
+ end
240
+ end
241
+ end
242
+
243
+ register_plugin(OpenAPI.plugin_name, OpenAPI)
244
+ end
245
+ end
@@ -11,11 +11,11 @@ class Serega
11
11
  attr_reader :opts
12
12
 
13
13
  #
14
- # Initializes context_metadata config object
14
+ # Initializes PreloadsConfig object
15
15
  #
16
16
  # @param opts [Hash] options
17
17
  #
18
- # @return [Serega::SeregaPlugins::Metadata::MetadataConfig]
18
+ # @return [Serega::SeregaPlugins::Preloads::PreloadsConfig]
19
19
  #
20
20
  def initialize(opts)
21
21
  @opts = opts
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: serega
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey Glushkov
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-10 00:00:00.000000000 Z
11
+ date: 2023-07-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  JSON Serializer
@@ -59,6 +59,8 @@ files:
59
59
  - lib/serega/plugins/batch/lib/validations/check_batch_opt_loader.rb
60
60
  - lib/serega/plugins/batch/lib/validations/check_opt_batch.rb
61
61
  - lib/serega/plugins/context_metadata/context_metadata.rb
62
+ - lib/serega/plugins/explicit_many_option/explicit_many_option.rb
63
+ - lib/serega/plugins/explicit_many_option/validations/check_opt_many.rb
62
64
  - lib/serega/plugins/formatters/formatters.rb
63
65
  - lib/serega/plugins/if/if.rb
64
66
  - lib/serega/plugins/if/validations/check_opt_if.rb
@@ -72,6 +74,9 @@ files:
72
74
  - lib/serega/plugins/metadata/validations/check_opt_hide_nil.rb
73
75
  - lib/serega/plugins/metadata/validations/check_opts.rb
74
76
  - lib/serega/plugins/metadata/validations/check_path.rb
77
+ - lib/serega/plugins/openapi/lib/modules/config.rb
78
+ - lib/serega/plugins/openapi/lib/openapi_config.rb
79
+ - lib/serega/plugins/openapi/openapi.rb
75
80
  - lib/serega/plugins/preloads/lib/format_user_preloads.rb
76
81
  - lib/serega/plugins/preloads/lib/modules/attribute.rb
77
82
  - lib/serega/plugins/preloads/lib/modules/attribute_normalizer.rb
@@ -117,7 +122,7 @@ metadata:
117
122
  source_code_uri: https://github.com/aglushkov/serega
118
123
  documentation_uri: https://www.rubydoc.info/gems/serega
119
124
  changelog_uri: https://github.com/aglushkov/serega/blob/master/CHANGELOG.md
120
- post_install_message:
125
+ post_install_message:
121
126
  rdoc_options: []
122
127
  require_paths:
123
128
  - lib
@@ -132,8 +137,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
137
  - !ruby/object:Gem::Version
133
138
  version: '0'
134
139
  requirements: []
135
- rubygems_version: 3.4.7
136
- signing_key:
140
+ rubygems_version: 3.4.6
141
+ signing_key:
137
142
  specification_version: 4
138
143
  summary: JSON Serializer
139
144
  test_files: []