jbuilder-schema 2.0.3 → 2.1.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: 991bddd670414a1f167fc83b2114d27337ab2e5df0b1e6355e86cbfe832521c2
4
- data.tar.gz: ae052082eee4397d31eff6765676efe8961a0e9cccc76dd4ff468352281f27ea
3
+ metadata.gz: 8e69ae6e6726679110d135c34a461a2bfc176f967bfa1777b73989ae107fdabc
4
+ data.tar.gz: 63fc234f84fe96195c6cc849bf26f4bea6d5e60808a0363e4fdddfe778497292
5
5
  SHA512:
6
- metadata.gz: 68f345ca2156440ec1e98f89a9322cf92f5450006b51e61b17d7437721fbc542985142f4fd223d8cc805bed1e6b4b2d2c2bd96197b1805155a6a9af04f0f59cd
7
- data.tar.gz: 64d6feefab876b7446e4523d739b9c9be65fd88e42eec35bcbab54f417f5ff6966c6c7a898c06d506e301a26ba3e474e5282275a2f5af575dcba64f8e4032366
6
+ metadata.gz: 2fcc3260655ff07670c2a8be5175c801f29af27790e0675c680fc861bae3a2a48dcd30170cb5468e595ec647d58c9abe92d2177f7c5dc77acdb8569f8ab7997e
7
+ data.tar.gz: ca344a595d3ed5c43c602e5d24ca154c4e0b9872388bd055422c957af93891be133618651e423f560ccc419b66c8b068828202f68929161d0790c4efbf71c8cb
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- jbuilder-schema (2.0.3)
4
+ jbuilder-schema (2.1.0)
5
5
  jbuilder
6
6
  rails (>= 5.0.0)
7
7
 
@@ -77,7 +77,7 @@ GEM
77
77
  builder (3.2.4)
78
78
  concurrent-ruby (1.1.10)
79
79
  crass (1.0.6)
80
- erubi (1.11.0)
80
+ erubi (1.12.0)
81
81
  globalid (1.0.0)
82
82
  activesupport (>= 5.0)
83
83
  i18n (1.12.0)
@@ -86,22 +86,25 @@ GEM
86
86
  actionview (>= 5.0.0)
87
87
  activesupport (>= 5.0.0)
88
88
  json (2.6.2)
89
- loofah (2.19.0)
89
+ loofah (2.19.1)
90
90
  crass (~> 1.0.2)
91
91
  nokogiri (>= 1.5.9)
92
- mail (2.7.1)
92
+ mail (2.8.0)
93
93
  mini_mime (>= 0.1.1)
94
+ net-imap
95
+ net-pop
96
+ net-smtp
94
97
  marcel (1.0.2)
95
98
  method_source (1.0.0)
96
99
  mini_mime (1.1.2)
97
100
  mini_portile2 (2.8.0)
98
- minitest (5.16.3)
101
+ minitest (5.17.0)
99
102
  mocha (1.14.0)
100
103
  net-imap (0.3.1)
101
104
  net-protocol
102
105
  net-pop (0.1.2)
103
106
  net-protocol
104
- net-protocol (0.1.3)
107
+ net-protocol (0.2.1)
105
108
  timeout
106
109
  net-smtp (0.3.3)
107
110
  net-protocol
@@ -112,8 +115,8 @@ GEM
112
115
  parallel (1.22.1)
113
116
  parser (3.1.2.0)
114
117
  ast (~> 2.4.1)
115
- racc (1.6.0)
116
- rack (2.2.4)
118
+ racc (1.6.2)
119
+ rack (2.2.5)
117
120
  rack-test (2.0.2)
118
121
  rack (>= 1.3)
119
122
  rails (7.0.4)
@@ -133,8 +136,8 @@ GEM
133
136
  rails-dom-testing (2.0.3)
134
137
  activesupport (>= 4.2.0)
135
138
  nokogiri (>= 1.6)
136
- rails-html-sanitizer (1.4.3)
137
- loofah (~> 2.3)
139
+ rails-html-sanitizer (1.4.4)
140
+ loofah (~> 2.19, >= 2.19.1)
138
141
  railties (7.0.4)
139
142
  actionpack (= 7.0.4)
140
143
  activesupport (= 7.0.4)
@@ -168,7 +171,7 @@ GEM
168
171
  rubocop (= 1.32.0)
169
172
  rubocop-performance (= 1.14.3)
170
173
  thor (1.2.1)
171
- timeout (0.3.0)
174
+ timeout (0.3.1)
172
175
  tzinfo (2.0.5)
173
176
  concurrent-ruby (~> 1.0)
174
177
  unicode-display_width (2.2.0)
@@ -3,6 +3,7 @@ require_relative "template"
3
3
 
4
4
  class Jbuilder::Schema::Renderer
5
5
  @@view_renderer = ActionView::Base.with_empty_template_cache
6
+ @@view_renderer.prefix_partial_path_with_controller_namespace = false
6
7
 
7
8
  def initialize(paths, default_locals = nil)
8
9
  @view_renderer = @@view_renderer.with_view_paths(paths)
@@ -18,19 +19,25 @@ class Jbuilder::Schema::Renderer
18
19
  end
19
20
 
20
21
  def render(object = nil, title: nil, description: nil, assigns: nil, **options)
21
- if object
22
- partial_path = object.respond_to?(:to_partial_path_for_jbuilder_schema) ? object.to_partial_path_for_jbuilder_schema : object.to_partial_path
23
- options.merge! partial: partial_path, object: object
24
- end
22
+ @view_renderer.assign assigns if assigns
23
+
24
+ json = original_render(object || options.dup, options.dup)
25
+
26
+ partial_path = %i[to_partial_path_for_jbuilder_schema to_partial_path].map { object.public_send(_1) if object.respond_to?(_1) }.compact.first
27
+ options.merge! partial: partial_path, object: object if partial_path
25
28
 
26
29
  options[:locals] ||= {}
27
30
  options[:locals].merge! @default_locals if @default_locals
28
- options[:locals][:__jbuilder_schema_options] = { model: object&.class, title: title, description: description }
31
+ options[:locals][:__jbuilder_schema_options] = { json: json, object: object, title: title, description: description }
29
32
 
30
- @view_renderer.assign assigns if assigns
31
33
  @view_renderer.render(options)
32
34
  end
33
35
 
36
+ # Thin wrapper around the regular Jbuilder JSON output render, which also parses it into a hash.
37
+ def original_render(options = {}, locals = {})
38
+ JSON.parse @view_renderer.render(options, locals)
39
+ end
40
+
34
41
  private
35
42
 
36
43
  def normalize(schema)
@@ -5,12 +5,9 @@ require "active_support/inflections"
5
5
 
6
6
  class Jbuilder::Schema
7
7
  class Template < ::JbuilderTemplate
8
- attr_reader :attributes, :type
9
- attr_reader :model_scope
10
-
11
8
  class Handler < ::JbuilderHandler
12
9
  def self.call(template, source = nil)
13
- super.sub("JbuilderTemplate.new(self", "Jbuilder::Schema::Template.new(self, **__jbuilder_schema_options").sub("target!", "schema!")
10
+ super.sub("JbuilderTemplate.new(self", "Jbuilder::Schema::Template.build(self, local_assigns")
14
11
  end
15
12
  end
16
13
 
@@ -18,208 +15,155 @@ class Jbuilder::Schema
18
15
  ::ActionView::Template.register_template_handler :jbuilder, ::Jbuilder::Schema::Template::Handler
19
16
  end
20
17
 
21
- ModelScope = ::Struct.new(:model, :title, :description, keyword_init: true) do
22
- def initialize(**)
23
- super
24
- @scope = model&.name&.underscore&.pluralize
18
+ def self.build(view_context, local_assigns)
19
+ if (options = local_assigns[:__jbuilder_schema_options])
20
+ new(view_context, **options)
21
+ else
22
+ ::JbuilderTemplate.new(view_context)
25
23
  end
24
+ end
26
25
 
27
- def i18n_title
28
- title || ::I18n.t(::Jbuilder::Schema.title_name, scope: @scope)
26
+ class Configuration < ::Struct.new(:object, :title, :description, keyword_init: true)
27
+ def self.build(object: nil, object_title: nil, object_description: nil, **)
28
+ new(object: object, title: object_title, description: object_description)
29
29
  end
30
30
 
31
- def i18n_description
32
- description || ::I18n.t(::Jbuilder::Schema.description_name, scope: @scope)
31
+ def title
32
+ super || translate(Jbuilder::Schema.title_name)
33
33
  end
34
34
 
35
- def translate_field(key)
36
- ::I18n.t("fields.#{key}.#{::Jbuilder::Schema.description_name}", scope: @scope)
35
+ def description
36
+ super || translate(Jbuilder::Schema.description_name)
37
37
  end
38
- end
39
38
 
40
- def initialize(context, **options)
41
- @type = :object
42
- @inline_array = false
43
- @collection = false
39
+ def translate_field(key)
40
+ translate("fields.#{key}.#{Jbuilder::Schema.description_name}")
41
+ end
44
42
 
45
- @model_scope = ModelScope.new(**options)
43
+ private
44
+ def translate(key)
45
+ I18n.t(key, scope: @scope ||= object&.class&.name&.underscore&.pluralize)
46
+ end
47
+ end
46
48
 
49
+ def initialize(context, json: nil, **options)
50
+ @json = json
51
+ @configuration = Configuration.new(**options)
47
52
  super(context)
48
-
49
53
  @ignore_nil = false
50
54
  end
51
55
 
52
- def schema!
53
- {type: type}.merge(type == :object ? _object(**attributes.merge) : attributes)
56
+ def target!
57
+ schema!
54
58
  end
55
59
 
56
- def set!(key, value = BLANK, *args, schema: {}, **options, &block)
57
- result = if block
58
- if !_blank?(value)
59
- # OBJECTS ARRAY:
60
- # json.comments @article.comments { |comment| ... }
61
- # { "comments": [ { ... }, { ... } ] }
62
- _scope { array! value, &block }
63
- else
64
- # BLOCK:
65
- # json.comments { ... }
66
- # { "comments": ... }
67
- @inline_array = true
68
-
69
- _with_model_scope(**schema) do
70
- _merge_block(key) { yield self }
71
- end
72
- end
73
- elsif args.empty?
74
- if ::Jbuilder === value
75
- # ATTRIBUTE1:
76
- # json.age 32
77
- # json.person another_jbuilder
78
- # { "age": 32, "person": { ... }
79
- _schema(key, _format_keys(value.attributes!), **schema)
80
- elsif _is_collection_array?(value)
81
- # ATTRIBUTE2:
82
- _scope { array! value }
83
- # json.articles @articles
84
- else
85
- # json.age 32
86
- # { "age": 32 }
87
- _schema(key, _format_keys(value), **schema)
88
- end
89
- elsif _is_collection?(value)
90
- # COLLECTION:
91
- # json.comments @article.comments, :content, :created_at
92
- # { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] }
93
- @inline_array = true
94
- @collection = true
95
-
96
- _scope { array! value, *args }
60
+ def schema!
61
+ if ([@attributes] + @attributes.each_value.grep(::Hash)).any? { _1[:type] == :array && _1.key?(:items) }
62
+ @attributes
97
63
  else
98
- # EXTRACT!:
99
- # json.author @article.creator, :name, :email_address
100
- # { "author": { "name": "David", "email_address": "david@loudthinking.com" } }
101
- _with_model_scope(**schema) do
102
- _merge_block(key) { extract! value, *args, schema: schema }
103
- end
104
- end
105
-
106
- result = _set_description key, result if model_scope.model
107
- _set_value key, result
64
+ _object(@attributes)
65
+ end.merge(example: @json).compact
108
66
  end
109
67
 
110
- def extract!(object, *attributes, schema: {})
111
- if ::Hash === object
112
- _extract_hash_values(object, attributes, schema: schema)
113
- else
114
- _extract_method_values(object, attributes, schema: schema)
68
+ def set!(key, value = BLANK, *args, schema: nil, **options, &block)
69
+ old_configuration, @configuration = @configuration, Configuration.build(**schema) if schema&.dig(:object)
70
+
71
+ _with_schema_overrides(key => schema) do
72
+ keys = args.presence || _extract_possible_keys(value)
73
+
74
+ # Detect `json.articles user.articles` to override Jbuilder's logic, which wouldn't hit `array!` and set a `type: :array, items: {"$ref": "#/components/schemas/article"}` ref.
75
+ if block.nil? && keys.blank? && _is_collection?(value) && (value.empty? || value.all? { _is_active_model?(_1) })
76
+ _set_value(key, _scope { _set_ref(key.to_s.singularize, array: true) })
77
+ else
78
+ super(key, value, *keys, **options, &block)
79
+ end
115
80
  end
81
+ ensure
82
+ @configuration = old_configuration if old_configuration
116
83
  end
84
+ alias_method :method_missing, :set! # TODO: Remove once Jbuilder passes keyword arguments along to `set!` in its `method_missing`.
117
85
 
118
- def array!(collection = [], *args, schema: {}, **options, &block)
86
+ def array!(collection = [], *args, schema: nil, **options, &block)
119
87
  if _partial_options?(options)
120
- @collection = true
121
- _set_ref(options[:partial].split("/").last)
88
+ partial!(collection: collection, **options)
122
89
  else
123
- array = _make_array(collection, *args, schema: schema, &block)
124
-
125
- if @inline_array
126
- @attributes = {}
127
- _set_value(:type, :array)
128
- _set_value(:items, array)
129
- elsif _is_collection_array?(array)
130
- @attributes = {}
131
- @inline_array = true
132
- @collection = true
133
- array! array, *array.first&.attribute_names(&:to_sym)
134
- else
135
- @type = :array
136
- @attributes = {}
137
- _set_value(:items, array)
90
+ _with_schema_overrides(schema) do
91
+ _attributes.merge! type: :array, items: _scope { super(collection, *args, &block) }
138
92
  end
139
93
  end
140
94
  end
141
95
 
142
- def partial!(*args)
143
- if args.one? && _is_active_model?(args.first)
96
+ def extract!(object, *attributes, schema: nil)
97
+ _with_schema_overrides(schema) { super(object, *attributes) }
98
+ end
99
+
100
+ def partial!(model = nil, *args, partial: nil, collection: nil, **options)
101
+ if args.none? && _is_active_model?(model)
144
102
  # TODO: Find where it is being used
145
- _render_active_model_partial args.first
146
- elsif args.first.is_a?(::Hash)
147
- _set_ref(args.first[:partial].split("/").last)
103
+ _render_active_model_partial model
148
104
  else
149
- @collection = true if args[1].key?(:collection)
150
- _set_ref(args.first&.split("/")&.last)
105
+ _set_ref(partial || model, array: collection&.any?)
151
106
  end
152
107
  end
153
108
 
154
109
  def merge!(object)
155
- hash_or_array = ::Jbuilder === object ? object.attributes! : object
156
- hash_or_array = _format_keys(hash_or_array)
157
- if hash_or_array.is_a?(::Hash)
158
- hash_or_array = hash_or_array.each_with_object({}) do |(key, value), a|
159
- result = _schema(key, value)
160
- result = _set_description(key, result) if model_scope.model
161
- a[key] = result
162
- end
163
- end
164
- @attributes = _merge_values(@attributes, hash_or_array)
110
+ object = object.to_h { [_1, _schema(_1, _2)] } if object.is_a?(::Hash)
111
+ super
165
112
  end
166
113
 
167
114
  def cache!(key = nil, **options)
168
115
  yield # TODO: Our schema generation breaks Jbuilder's fragment caching.
169
116
  end
170
117
 
171
- def method_missing(*args, **options, &block) # standard:disable Style/MissingRespondToMissing
172
- # TODO: Remove once Jbuilder passes keyword arguments along to `set!` in its `method_missing`.
173
- set!(*args, **options, &block)
174
- end
175
-
176
118
  private
177
119
 
178
- def _with_model_scope(object: nil, object_title: nil, object_description: nil, **)
179
- old_model_scope, @model_scope = @model_scope, ModelScope.new(model: object.class, title: object_title, description: object_description) if object
120
+ def _extract_possible_keys(value)
121
+ value.first.as_json.keys if _is_collection?(value) && _is_active_model?(value.first)
122
+ end
123
+
124
+ def _with_schema_overrides(overrides)
125
+ old_schema_overrides, @schema_overrides = @schema_overrides, overrides if overrides
180
126
  yield
181
127
  ensure
182
- @model_scope = old_model_scope if object
128
+ @schema_overrides = old_schema_overrides if overrides
183
129
  end
184
130
 
185
- def _object(**attributes)
131
+ def _object(attributes)
186
132
  {
187
133
  type: :object,
188
- title: model_scope.i18n_title,
189
- description: model_scope.i18n_description,
134
+ title: @configuration.title,
135
+ description: @configuration.description,
190
136
  required: _required!(attributes.keys),
191
137
  properties: attributes
192
138
  }
193
139
  end
194
140
 
195
141
  def _set_description(key, value)
196
- unless value.key?(:description)
197
- description = model_scope.translate_field(key)
198
- value = {description: description}.merge! value
142
+ if !value.key?(:description) && @configuration.object
143
+ value[:description] = @configuration.translate_field(key)
199
144
  end
200
- value
201
145
  end
202
146
 
203
- def _set_ref(component)
204
- component_path = "#/#{::Jbuilder::Schema.components_path}/#{component}"
147
+ def _set_ref(part, array: false)
148
+ ref = {"$ref": "#/#{::Jbuilder::Schema.components_path}/#{part.split("/").last}"}
205
149
 
206
- if @inline_array
207
- if @collection
208
- _set_value(:type, :array)
209
- _set_value(:items, {:$ref => component_path})
210
- else
211
- _set_value(:type, :object)
212
- _set_value(:$ref, component_path)
213
- end
150
+ if array
151
+ _attributes.merge! type: :array, items: ref
214
152
  else
215
- @type = :array
216
- _set_value(:items, {:$ref => component_path})
153
+ _attributes.merge! type: :object, **ref
217
154
  end
218
155
  end
219
156
 
157
+ def _attributes
158
+ @attributes = {} if _blank?
159
+ @attributes
160
+ end
161
+
220
162
  FORMATS = {::DateTime => "date-time", ::ActiveSupport::TimeWithZone => "date-time", ::Date => "date", ::Time => "time"}
221
163
 
222
164
  def _schema(key, value, **options)
165
+ options = @schema_overrides&.dig(key).to_h if options.empty?
166
+
223
167
  unless options[:type]
224
168
  options[:type] = _primitive_type value
225
169
 
@@ -231,10 +175,11 @@ class Jbuilder::Schema
231
175
  format = FORMATS[value.class] and options[:format] ||= format
232
176
  end
233
177
 
234
- if (model = model_scope.model) && (defined_enum = model.try(:defined_enums)&.dig(key.to_s))
178
+ if (klass = @configuration.object&.class) && (defined_enum = klass.try(:defined_enums)&.dig(key.to_s))
235
179
  options[:enum] = defined_enum.keys
236
180
  end
237
181
 
182
+ _set_description key, options
238
183
  options
239
184
  end
240
185
 
@@ -249,24 +194,14 @@ class Jbuilder::Schema
249
194
  end
250
195
  end
251
196
 
252
- def _make_array(collection, *args, schema: {}, &block)
253
- if collection.nil?
254
- []
255
- elsif block
256
- _map_collection(collection, &block)
257
- elsif args.any?
258
- _map_collection(collection) { |element| extract! element, *args, schema: schema }
259
- else
260
- _format_keys(collection.to_a)
261
- end
262
- end
263
-
264
- def _is_collection_array?(object)
265
- object.is_a?(::Array) && object.all? { _is_active_model? _1 }
197
+ def _set_value(key, value)
198
+ value = _schema(key, value) unless value.is_a?(::Hash) && value.key?(:type)
199
+ _set_description(key, value)
200
+ super
266
201
  end
267
202
 
268
203
  def _required!(keys)
269
- presence_validated_attributes = model_scope.model.try(:validators).to_a.flat_map { _1.attributes if _1.is_a?(::ActiveRecord::Validations::PresenceValidator) }
204
+ presence_validated_attributes = @configuration.object&.class.try(:validators).to_a.flat_map { _1.attributes if _1.is_a?(::ActiveRecord::Validations::PresenceValidator) }
270
205
  keys & [_key(:id), *presence_validated_attributes.map { _key _1 }]
271
206
  end
272
207
 
@@ -274,22 +209,6 @@ class Jbuilder::Schema
274
209
  # Jbuilder methods
275
210
  ###
276
211
 
277
- def _extract_hash_values(object, attributes, schema:)
278
- attributes.each do |key|
279
- result = _schema(key, _format_keys(object.fetch(key)), **schema[key] || {})
280
- result = _set_description(key, result) if model_scope.model
281
- _set_value key, result
282
- end
283
- end
284
-
285
- def _extract_method_values(object, attributes, schema:)
286
- attributes.each do |key|
287
- result = _schema(key, _format_keys(object.public_send(key)), **schema[key] || {})
288
- result = _set_description(key, result) if model_scope.model
289
- _set_value key, result
290
- end
291
- end
292
-
293
212
  def _map_collection(collection)
294
213
  super.first
295
214
  end
@@ -299,20 +218,8 @@ class Jbuilder::Schema
299
218
  raise NullError.build(key) if current_value.nil?
300
219
 
301
220
  value = _scope { yield self }
302
- value = _object(**value) unless value.values_at("type", :type).any?(:array) || value.key?(:$ref) || value.key?("$ref")
221
+ value = _object(value) unless value[:type] == :array || value.key?(:$ref)
303
222
  _merge_values(current_value, value)
304
223
  end
305
224
  end
306
225
  end
307
-
308
- class Jbuilder
309
- module SkipFormatting
310
- SCHEMA_KEYS = %i[type items properties]
311
-
312
- def format(key)
313
- SCHEMA_KEYS.include?(key) ? key : super
314
- end
315
- end
316
-
317
- KeyFormatter.prepend SkipFormatting
318
- end
@@ -1,4 +1,4 @@
1
1
  # We can't use the standard `Jbuilder::Schema::VERSION =` because
2
2
  # `Jbuilder` isn't a regular module namespace, but a class …which also loads Active Support.
3
3
  # So we use trickery, and assign the proper version once `jbuilder/schema.rb` is loaded.
4
- JBUILDER_SCHEMA_VERSION = "2.0.3"
4
+ JBUILDER_SCHEMA_VERSION = "2.1.0"
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/module/delegation"
3
+ require "jbuilder"
4
4
  require "jbuilder/schema/version"
5
+ require "active_support/core_ext/module/delegation"
5
6
 
6
7
  class Jbuilder::Schema
7
- VERSION = "2.0.3" # TODO Fix this. It's throwing errors when including the Ruby gem in downstream projects.
8
+ VERSION = JBUILDER_SCHEMA_VERSION # See `jbuilder/schema/version.rb`
8
9
 
9
10
  module IgnoreSchemaMeta
10
11
  ::Jbuilder.prepend self
@@ -12,6 +13,18 @@ class Jbuilder::Schema
12
13
  def method_missing(*args, schema: nil, **options, &block) # standard:disable Style/MissingRespondToMissing
13
14
  super(*args, **options, &block)
14
15
  end
16
+
17
+ def set!(*args, schema: nil, **options, &block)
18
+ super(*args, **options, &block)
19
+ end
20
+
21
+ def array!(*args, schema: nil, **options, &block)
22
+ super(*args, **options, &block)
23
+ end
24
+
25
+ def extract!(*args, schema: nil, **options, &block)
26
+ super(*args, **options, &block)
27
+ end
15
28
  end
16
29
 
17
30
  singleton_class.alias_method :configure, :tap
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jbuilder-schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuri Sidorov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-08 00:00:00.000000000 Z
11
+ date: 2023-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jbuilder
@@ -76,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
78
  requirements: []
79
- rubygems_version: 3.3.7
79
+ rubygems_version: 3.4.1
80
80
  signing_key:
81
81
  specification_version: 4
82
82
  summary: Generate JSON Schema from Jbuilder files