tapioca 0.11.8 → 0.11.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +116 -49
  3. data/lib/tapioca/cli.rb +76 -67
  4. data/lib/tapioca/commands/{dsl.rb → abstract_dsl.rb} +32 -78
  5. data/lib/tapioca/commands/{gem.rb → abstract_gem.rb} +26 -93
  6. data/lib/tapioca/commands/annotations.rb +9 -7
  7. data/lib/tapioca/commands/check_shims.rb +2 -0
  8. data/lib/tapioca/commands/command.rb +9 -2
  9. data/lib/tapioca/commands/configure.rb +2 -2
  10. data/lib/tapioca/commands/dsl_compiler_list.rb +31 -0
  11. data/lib/tapioca/commands/dsl_generate.rb +40 -0
  12. data/lib/tapioca/commands/dsl_verify.rb +25 -0
  13. data/lib/tapioca/commands/gem_generate.rb +51 -0
  14. data/lib/tapioca/commands/gem_sync.rb +37 -0
  15. data/lib/tapioca/commands/gem_verify.rb +36 -0
  16. data/lib/tapioca/commands/require.rb +2 -0
  17. data/lib/tapioca/commands/todo.rb +21 -2
  18. data/lib/tapioca/commands.rb +8 -2
  19. data/lib/tapioca/dsl/compiler.rb +8 -4
  20. data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +3 -1
  21. data/lib/tapioca/dsl/compilers/active_model_validations_confirmation.rb +94 -0
  22. data/lib/tapioca/dsl/compilers/active_record_columns.rb +19 -9
  23. data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +3 -2
  24. data/lib/tapioca/dsl/compilers/active_support_concern.rb +1 -1
  25. data/lib/tapioca/dsl/compilers/graphql_input_object.rb +1 -1
  26. data/lib/tapioca/dsl/compilers/graphql_mutation.rb +9 -2
  27. data/lib/tapioca/dsl/compilers/json_api_client_resource.rb +208 -0
  28. data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +20 -4
  29. data/lib/tapioca/dsl/helpers/graphql_type_helper.rb +20 -3
  30. data/lib/tapioca/dsl/pipeline.rb +6 -4
  31. data/lib/tapioca/gem/pipeline.rb +103 -36
  32. data/lib/tapioca/gemfile.rb +13 -7
  33. data/lib/tapioca/helpers/git_attributes.rb +34 -0
  34. data/lib/tapioca/helpers/test/template.rb +4 -4
  35. data/lib/tapioca/internal.rb +1 -0
  36. data/lib/tapioca/loaders/dsl.rb +11 -1
  37. data/lib/tapioca/sorbet_ext/generic_name_patch.rb +0 -27
  38. data/lib/tapioca/static/symbol_loader.rb +9 -8
  39. data/lib/tapioca/version.rb +1 -1
  40. metadata +19 -10
@@ -50,6 +50,8 @@ module Tapioca
50
50
  @root
51
51
  end
52
52
 
53
+ # Events handling
54
+
53
55
  sig { params(symbol: String).void }
54
56
  def push_symbol(symbol)
55
57
  @events << Gem::SymbolFound.new(symbol)
@@ -98,6 +100,8 @@ module Tapioca
98
100
  @events << Gem::MethodNodeAdded.new(symbol, constant, method, node, signature, parameters)
99
101
  end
100
102
 
103
+ # Constants and properties filtering
104
+
101
105
  sig { params(symbol_name: String).returns(T::Boolean) }
102
106
  def symbol_in_payload?(symbol_name)
103
107
  symbol_name = symbol_name[2..-1] if symbol_name.start_with?("::")
@@ -106,16 +110,27 @@ module Tapioca
106
110
  @payload_symbols.include?(symbol_name)
107
111
  end
108
112
 
113
+ # this looks something like:
114
+ # "(eval at /path/to/file.rb:123)"
115
+ # and we are just interested in the "/path/to/file.rb" part
116
+ EVAL_SOURCE_FILE_PATTERN = T.let(/\(eval at (.+):\d+\)/, Regexp)
117
+
109
118
  sig { params(name: T.any(String, Symbol)).returns(T::Boolean) }
110
119
  def constant_in_gem?(name)
111
120
  return true unless Object.respond_to?(:const_source_location)
112
121
 
113
- source_location, _ = Object.const_source_location(name)
114
- return true unless source_location
122
+ source_file, _ = Object.const_source_location(name)
123
+ return true unless source_file
115
124
  # If the source location of the constant is "(eval)", all bets are off.
116
- return true if source_location == "(eval)"
125
+ return true if source_file == "(eval)"
117
126
 
118
- gem.contains_path?(source_location)
127
+ # Ruby 3.3 adds automatic definition of source location for evals if
128
+ # `file` and `line` arguments are not provided. This results in the source
129
+ # file being something like `(eval at /path/to/file.rb:123)`. We try to parse
130
+ # this string to get the actual source file.
131
+ source_file = source_file.sub(EVAL_SOURCE_FILE_PATTERN, "\\1")
132
+
133
+ gem.contains_path?(source_file)
119
134
  end
120
135
 
121
136
  sig { params(method: UnboundMethod).returns(T::Boolean) }
@@ -126,6 +141,8 @@ module Tapioca
126
141
  @gem.contains_path?(source_location)
127
142
  end
128
143
 
144
+ # Helpers
145
+
129
146
  sig { params(constant: Module).returns(T.nilable(String)) }
130
147
  def name_of(constant)
131
148
  name = name_of_proxy_target(constant, super(class_of(constant)))
@@ -149,6 +166,8 @@ module Tapioca
149
166
  gem_symbols.union(engine_symbols)
150
167
  end
151
168
 
169
+ # Events handling
170
+
152
171
  sig { returns(Gem::Event) }
153
172
  def next_event
154
173
  T.must(@events.shift)
@@ -171,7 +190,7 @@ module Tapioca
171
190
  sig { params(event: Gem::SymbolFound).void }
172
191
  def on_symbol(event)
173
192
  symbol = event.symbol.delete_prefix("::")
174
- return if symbol_in_payload?(symbol) && !@bootstrap_symbols.include?(symbol)
193
+ return if skip_symbol?(symbol)
175
194
 
176
195
  constant = constantize(symbol)
177
196
  push_constant(symbol, constant) if Runtime::Reflection.constant_defined?(constant)
@@ -180,13 +199,7 @@ module Tapioca
180
199
  sig { params(event: Gem::ConstantFound).void.checked(:never) }
181
200
  def on_constant(event)
182
201
  name = event.symbol
183
-
184
- return if name.strip.empty?
185
- return if name.start_with?("#<")
186
- return if name.downcase == name
187
- return if alias_namespaced?(name)
188
-
189
- return if T::Enum === event.constant # T::Enum instances are defined via `compile_enums`
202
+ return if skip_constant?(name, event.constant)
190
203
 
191
204
  if event.is_a?(Gem::ForeignConstantFound)
192
205
  compile_foreign_constant(name, event.constant)
@@ -200,11 +213,17 @@ module Tapioca
200
213
  @node_listeners.each { |listener| listener.dispatch(event) }
201
214
  end
202
215
 
203
- # Compile
216
+ # Compiling
204
217
 
205
218
  sig { params(symbol: String, constant: Module).void }
206
219
  def compile_foreign_constant(symbol, constant)
207
- compile_module(symbol, constant, foreign_constant: true)
220
+ return if skip_foreign_constant?(symbol, constant)
221
+ return if seen?(symbol)
222
+
223
+ seen!(symbol)
224
+
225
+ scope = compile_scope(symbol, constant)
226
+ push_foreign_scope(symbol, constant, scope)
208
227
  end
209
228
 
210
229
  sig { params(symbol: String, constant: BasicObject).void.checked(:never) }
@@ -225,10 +244,9 @@ module Tapioca
225
244
  def compile_alias(name, constant)
226
245
  return if seen?(name)
227
246
 
228
- mark_seen(name)
247
+ seen!(name)
229
248
 
230
- return if symbol_in_payload?(name)
231
- return unless constant_in_gem?(name)
249
+ return if skip_alias?(name, constant)
232
250
 
233
251
  target = name_of(constant)
234
252
  # If target has no name, let's make it an anonymous class or module with `Class.new` or `Module.new`
@@ -247,10 +265,9 @@ module Tapioca
247
265
  def compile_object(name, value)
248
266
  return if seen?(name)
249
267
 
250
- mark_seen(name)
268
+ seen!(name)
251
269
 
252
- return if symbol_in_payload?(name)
253
- return unless constant_in_gem?(name)
270
+ return if skip_object?(name, value)
254
271
 
255
272
  klass = class_of(value)
256
273
 
@@ -279,29 +296,29 @@ module Tapioca
279
296
  @root << node
280
297
  end
281
298
 
282
- sig { params(name: String, constant: Module, foreign_constant: T::Boolean).void }
283
- def compile_module(name, constant, foreign_constant: false)
284
- return unless defined_in_gem?(constant, strict: false) || foreign_constant
285
- return if Tapioca::TypeVariableModule === constant
299
+ sig { params(name: String, constant: Module).void }
300
+ def compile_module(name, constant)
301
+ return if skip_module?(name, constant)
286
302
  return if seen?(name)
287
303
 
288
- mark_seen(name)
304
+ seen!(name)
289
305
 
290
- scope =
291
- if constant.is_a?(Class)
292
- superclass = compile_superclass(constant)
293
- RBI::Class.new(name, superclass_name: superclass)
294
- else
295
- RBI::Module.new(name)
296
- end
306
+ scope = compile_scope(name, constant)
307
+ push_scope(name, constant, scope)
308
+ end
297
309
 
298
- if foreign_constant
299
- push_foreign_scope(name, constant, scope)
310
+ sig { params(name: String, constant: Module).returns(RBI::Scope) }
311
+ def compile_scope(name, constant)
312
+ scope = if constant.is_a?(Class)
313
+ superclass = compile_superclass(constant)
314
+ RBI::Class.new(name, superclass_name: superclass)
300
315
  else
301
- push_scope(name, constant, scope)
316
+ RBI::Module.new(name)
302
317
  end
303
318
 
304
319
  @root << scope
320
+
321
+ scope
305
322
  end
306
323
 
307
324
  sig { params(constant: T::Class[T.anything]).returns(T.nilable(String)) }
@@ -353,6 +370,54 @@ module Tapioca
353
370
  "::#{name}"
354
371
  end
355
372
 
373
+ # Constants and properties filtering
374
+
375
+ sig { params(name: String).returns(T::Boolean) }
376
+ def skip_symbol?(name)
377
+ symbol_in_payload?(name) && !@bootstrap_symbols.include?(name)
378
+ end
379
+
380
+ sig { params(name: String, constant: T.anything).returns(T::Boolean).checked(:never) }
381
+ def skip_constant?(name, constant)
382
+ return true if name.strip.empty?
383
+ return true if name.start_with?("#<")
384
+ return true if name.downcase == name
385
+ return true if alias_namespaced?(name)
386
+
387
+ return true if T::Enum === constant # T::Enum instances are defined via `compile_enums`
388
+
389
+ false
390
+ end
391
+
392
+ sig { params(name: String, constant: Module).returns(T::Boolean) }
393
+ def skip_alias?(name, constant)
394
+ return true if symbol_in_payload?(name)
395
+ return true unless constant_in_gem?(name)
396
+
397
+ false
398
+ end
399
+
400
+ sig { params(name: String, constant: BasicObject).returns(T::Boolean).checked(:never) }
401
+ def skip_object?(name, constant)
402
+ return true if symbol_in_payload?(name)
403
+ return true unless constant_in_gem?(name)
404
+
405
+ false
406
+ end
407
+
408
+ sig { params(name: String, constant: Module).returns(T::Boolean) }
409
+ def skip_foreign_constant?(name, constant)
410
+ Tapioca::TypeVariableModule === constant
411
+ end
412
+
413
+ sig { params(name: String, constant: Module).returns(T::Boolean) }
414
+ def skip_module?(name, constant)
415
+ return true unless defined_in_gem?(constant, strict: false)
416
+ return true if Tapioca::TypeVariableModule === constant
417
+
418
+ false
419
+ end
420
+
356
421
  sig { params(constant: Module, strict: T::Boolean).returns(T::Boolean) }
357
422
  def defined_in_gem?(constant, strict: true)
358
423
  files = get_file_candidates(constant)
@@ -385,7 +450,7 @@ module Tapioca
385
450
  end
386
451
 
387
452
  sig { params(name: String).void }
388
- def mark_seen(name)
453
+ def seen!(name)
389
454
  @seen.add(name)
390
455
  end
391
456
 
@@ -394,6 +459,8 @@ module Tapioca
394
459
  @seen.include?(name)
395
460
  end
396
461
 
462
+ # Helpers
463
+
397
464
  sig { params(constant: T.all(Module, T::Generic)).returns(String) }
398
465
  def generic_name_of(constant)
399
466
  type_name = T.must(constant.name)
@@ -156,6 +156,11 @@ module Tapioca
156
156
  @spec.name
157
157
  end
158
158
 
159
+ sig { returns(T::Array[::Gem::Dependency]) }
160
+ def dependencies
161
+ @spec.dependencies
162
+ end
163
+
159
164
  sig { returns(String) }
160
165
  def rbi_file_name
161
166
  "#{name}@#{version}.rbi"
@@ -230,13 +235,14 @@ module Tapioca
230
235
 
231
236
  sig { returns(Regexp) }
232
237
  def require_paths_prefix_matcher
233
- @require_paths_prefix_matcher = T.let(@require_paths_prefix_matcher, T.nilable(Regexp))
234
-
235
- @require_paths_prefix_matcher ||= begin
236
- require_paths = T.unsafe(@spec).require_paths
237
- prefix_matchers = require_paths.map { |rp| Regexp.new("^#{rp}/") }
238
- Regexp.union(prefix_matchers)
239
- end
238
+ @require_paths_prefix_matcher ||= T.let(
239
+ begin
240
+ require_paths = T.unsafe(@spec).require_paths
241
+ prefix_matchers = require_paths.map { |rp| Regexp.new("^#{rp}/") }
242
+ Regexp.union(prefix_matchers)
243
+ end,
244
+ T.nilable(Regexp),
245
+ )
240
246
  end
241
247
 
242
248
  sig { params(file: String).returns(Pathname) }
@@ -0,0 +1,34 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ class GitAttributes
5
+ class << self
6
+ extend T::Sig
7
+
8
+ sig { params(path: Pathname).void }
9
+ def create_generated_attribute_file(path)
10
+ create_gitattributes_file(path, <<~CONTENT)
11
+ **/*.rbi linguist-generated=true
12
+ CONTENT
13
+ end
14
+
15
+ sig { params(path: Pathname).void }
16
+ def create_vendored_attribute_file(path)
17
+ create_gitattributes_file(path, <<~CONTENT)
18
+ **/*.rbi linguist-vendored=true
19
+ CONTENT
20
+ end
21
+
22
+ private
23
+
24
+ sig { params(path: Pathname, content: String).void }
25
+ def create_gitattributes_file(path, content)
26
+ # We don't want to start creating folders, just to write
27
+ # the `.gitattributes` file. So, if the folder doesn't
28
+ # exist, we just return.
29
+ return unless path.exist?
30
+
31
+ File.write(path.join(".gitattributes"), content)
32
+ end
33
+ end
34
+ end
@@ -24,12 +24,12 @@ module Tapioca
24
24
  ::Gem::Requirement.new(selector).satisfied_by?(ActiveSupport.gem_version)
25
25
  end
26
26
 
27
- sig { params(src: String).returns(String) }
28
- def template(src)
27
+ sig { params(src: String, trim_mode: String).returns(String) }
28
+ def template(src, trim_mode: ">")
29
29
  erb = if ERB_SUPPORTS_KVARGS
30
- ::ERB.new(src, trim_mode: ">")
30
+ ::ERB.new(src, trim_mode: trim_mode)
31
31
  else
32
- ::ERB.new(src, nil, ">")
32
+ ::ERB.new(src, nil, trim_mode)
33
33
  end
34
34
 
35
35
  erb.result(binding)
@@ -28,6 +28,7 @@ require "yard-sorbet"
28
28
  require "tapioca/runtime/dynamic_mixin_compiler"
29
29
  require "tapioca/helpers/gem_helper"
30
30
 
31
+ require "tapioca/helpers/git_attributes"
31
32
  require "tapioca/helpers/sorbet_helper"
32
33
  require "tapioca/helpers/rbi_helper"
33
34
  require "tapioca/sorbet_ext/backcompat_patches"
@@ -46,7 +46,17 @@ module Tapioca
46
46
 
47
47
  sig { void }
48
48
  def load_dsl_extensions
49
- Dir["#{__dir__}/../dsl/extensions/*.rb"].sort.each { |f| require(f) }
49
+ say("Loading DSL extension classes... ")
50
+
51
+ Dir.glob(["#{@tapioca_path}/extensions/**/*.rb"]).each do |extension|
52
+ require File.expand_path(extension)
53
+ end
54
+
55
+ ::Gem.find_files("tapioca/dsl/extensions/*.rb").each do |extension|
56
+ require File.expand_path(extension)
57
+ end
58
+
59
+ say("Done", :green)
50
60
  end
51
61
 
52
62
  sig { void }
@@ -191,19 +191,6 @@ module Tapioca
191
191
  sig { returns(T.nilable(String)) }
192
192
  def name
193
193
  constant_name = super
194
-
195
- # This is a hack to work around modules under anonymous modules not having
196
- # names in 2.7: https://bugs.ruby-lang.org/issues/14895
197
- #
198
- # This happens when a type variable is declared under `class << self`, for
199
- # example.
200
- #
201
- # The workaround is to give the parent context a name, at which point, our
202
- # module gets bound to a name under that name, as well.
203
- unless constant_name
204
- constant_name = with_bound_name_pre_3_0 { super }
205
- end
206
-
207
194
  constant_name&.split("::")&.last
208
195
  end
209
196
 
@@ -247,20 +234,6 @@ module Tapioca
247
234
  -> { bounds }
248
235
  end
249
236
 
250
- sig do
251
- type_parameters(:Result)
252
- .params(block: T.proc.returns(T.type_parameter(:Result)))
253
- .returns(T.type_parameter(:Result))
254
- end
255
- def with_bound_name_pre_3_0(&block)
256
- require "securerandom"
257
- temp_name = "TYPE_VARIABLE_TRACKING_#{SecureRandom.hex}"
258
- self.class.const_set(temp_name, @context)
259
- block.call
260
- ensure
261
- self.class.send(:remove_const, temp_name) if temp_name
262
- end
263
-
264
237
  sig { returns(T::Hash[Symbol, T.untyped]) }
265
238
  def bounds
266
239
  @bounds ||= @bounds_proc.call
@@ -59,14 +59,15 @@ module Tapioca
59
59
 
60
60
  sig { returns(T::Array[T.class_of(Rails::Engine)]) }
61
61
  def engines
62
- @engines = T.let(@engines, T.nilable(T::Array[T.class_of(Rails::Engine)]))
63
-
64
- @engines ||= if Object.const_defined?("Rails::Engine")
65
- descendants_of(Object.const_get("Rails::Engine"))
66
- .reject(&:abstract_railtie?)
67
- else
68
- []
69
- end
62
+ @engines ||= T.let(
63
+ if Object.const_defined?("Rails::Engine")
64
+ descendants_of(Object.const_get("Rails::Engine"))
65
+ .reject(&:abstract_railtie?)
66
+ else
67
+ []
68
+ end,
69
+ T.nilable(T::Array[T.class_of(Rails::Engine)]),
70
+ )
70
71
  end
71
72
 
72
73
  sig { params(input: String, table_type: String).returns(String) }
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- VERSION = "0.11.8"
5
+ VERSION = "0.11.9"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tapioca
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.8
4
+ version: 0.11.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ufuk Kayserilioglu
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2023-07-12 00:00:00.000000000 Z
14
+ date: 2023-09-13 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -61,20 +61,20 @@ dependencies:
61
61
  requirements:
62
62
  - - "~>"
63
63
  - !ruby/object:Gem::Version
64
- version: 0.0.0
64
+ version: 0.1.0
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
- version: 0.0.16
67
+ version: 0.1.0
68
68
  type: :runtime
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: 0.0.0
74
+ version: 0.1.0
75
75
  - - ">="
76
76
  - !ruby/object:Gem::Version
77
- version: 0.0.16
77
+ version: 0.1.0
78
78
  - !ruby/object:Gem::Dependency
79
79
  name: sorbet-static-and-runtime
80
80
  requirement: !ruby/object:Gem::Requirement
@@ -152,13 +152,19 @@ files:
152
152
  - lib/tapioca/bundler_ext/auto_require_hook.rb
153
153
  - lib/tapioca/cli.rb
154
154
  - lib/tapioca/commands.rb
155
+ - lib/tapioca/commands/abstract_dsl.rb
156
+ - lib/tapioca/commands/abstract_gem.rb
155
157
  - lib/tapioca/commands/annotations.rb
156
158
  - lib/tapioca/commands/check_shims.rb
157
159
  - lib/tapioca/commands/command.rb
158
160
  - lib/tapioca/commands/command_without_tracker.rb
159
161
  - lib/tapioca/commands/configure.rb
160
- - lib/tapioca/commands/dsl.rb
161
- - lib/tapioca/commands/gem.rb
162
+ - lib/tapioca/commands/dsl_compiler_list.rb
163
+ - lib/tapioca/commands/dsl_generate.rb
164
+ - lib/tapioca/commands/dsl_verify.rb
165
+ - lib/tapioca/commands/gem_generate.rb
166
+ - lib/tapioca/commands/gem_sync.rb
167
+ - lib/tapioca/commands/gem_verify.rb
162
168
  - lib/tapioca/commands/require.rb
163
169
  - lib/tapioca/commands/todo.rb
164
170
  - lib/tapioca/dsl.rb
@@ -170,6 +176,7 @@ files:
170
176
  - lib/tapioca/dsl/compilers/active_job.rb
171
177
  - lib/tapioca/dsl/compilers/active_model_attributes.rb
172
178
  - lib/tapioca/dsl/compilers/active_model_secure_password.rb
179
+ - lib/tapioca/dsl/compilers/active_model_validations_confirmation.rb
173
180
  - lib/tapioca/dsl/compilers/active_record_associations.rb
174
181
  - lib/tapioca/dsl/compilers/active_record_columns.rb
175
182
  - lib/tapioca/dsl/compilers/active_record_delegated_types.rb
@@ -188,6 +195,7 @@ files:
188
195
  - lib/tapioca/dsl/compilers/graphql_input_object.rb
189
196
  - lib/tapioca/dsl/compilers/graphql_mutation.rb
190
197
  - lib/tapioca/dsl/compilers/identity_cache.rb
198
+ - lib/tapioca/dsl/compilers/json_api_client_resource.rb
191
199
  - lib/tapioca/dsl/compilers/kredis.rb
192
200
  - lib/tapioca/dsl/compilers/mixed_in_class_attributes.rb
193
201
  - lib/tapioca/dsl/compilers/protobuf.rb
@@ -228,6 +236,7 @@ files:
228
236
  - lib/tapioca/helpers/config_helper.rb
229
237
  - lib/tapioca/helpers/env_helper.rb
230
238
  - lib/tapioca/helpers/gem_helper.rb
239
+ - lib/tapioca/helpers/git_attributes.rb
231
240
  - lib/tapioca/helpers/rbi_files_helper.rb
232
241
  - lib/tapioca/helpers/rbi_helper.rb
233
242
  - lib/tapioca/helpers/sorbet_helper.rb
@@ -276,14 +285,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
276
285
  requirements:
277
286
  - - ">="
278
287
  - !ruby/object:Gem::Version
279
- version: '2.7'
288
+ version: '3.0'
280
289
  required_rubygems_version: !ruby/object:Gem::Requirement
281
290
  requirements:
282
291
  - - ">="
283
292
  - !ruby/object:Gem::Version
284
293
  version: '0'
285
294
  requirements: []
286
- rubygems_version: 3.4.16
295
+ rubygems_version: 3.4.19
287
296
  signing_key:
288
297
  specification_version: 4
289
298
  summary: A Ruby Interface file generator for gems, core types and the Ruby standard