tapioca 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/README.md +491 -73
  4. data/lib/tapioca/cli.rb +40 -3
  5. data/lib/tapioca/commands/annotations.rb +154 -0
  6. data/lib/tapioca/commands/dsl.rb +20 -1
  7. data/lib/tapioca/commands/gem.rb +17 -57
  8. data/lib/tapioca/commands/init.rb +1 -0
  9. data/lib/tapioca/commands/todo.rb +4 -2
  10. data/lib/tapioca/commands.rb +1 -0
  11. data/lib/tapioca/dsl/compiler.rb +2 -2
  12. data/lib/tapioca/dsl/compilers/aasm.rb +1 -1
  13. data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +1 -1
  14. data/lib/tapioca/dsl/compilers/action_mailer.rb +1 -1
  15. data/lib/tapioca/dsl/compilers/active_job.rb +1 -1
  16. data/lib/tapioca/dsl/compilers/active_model_attributes.rb +1 -1
  17. data/lib/tapioca/dsl/compilers/active_model_secure_password.rb +1 -1
  18. data/lib/tapioca/dsl/compilers/active_record_associations.rb +1 -1
  19. data/lib/tapioca/dsl/compilers/active_record_columns.rb +1 -1
  20. data/lib/tapioca/dsl/compilers/active_record_enum.rb +1 -1
  21. data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +3 -1
  22. data/lib/tapioca/dsl/compilers/active_record_relations.rb +8 -8
  23. data/lib/tapioca/dsl/compilers/active_record_scope.rb +1 -1
  24. data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +1 -1
  25. data/lib/tapioca/dsl/compilers/active_resource.rb +1 -1
  26. data/lib/tapioca/dsl/compilers/active_storage.rb +6 -2
  27. data/lib/tapioca/dsl/compilers/active_support_concern.rb +1 -1
  28. data/lib/tapioca/dsl/compilers/active_support_current_attributes.rb +1 -1
  29. data/lib/tapioca/dsl/compilers/config.rb +2 -2
  30. data/lib/tapioca/dsl/compilers/frozen_record.rb +1 -1
  31. data/lib/tapioca/dsl/compilers/identity_cache.rb +1 -1
  32. data/lib/tapioca/dsl/compilers/mixed_in_class_attributes.rb +1 -1
  33. data/lib/tapioca/dsl/compilers/protobuf.rb +27 -3
  34. data/lib/tapioca/dsl/compilers/rails_generators.rb +1 -1
  35. data/lib/tapioca/dsl/compilers/sidekiq_worker.rb +1 -1
  36. data/lib/tapioca/dsl/compilers/smart_properties.rb +1 -1
  37. data/lib/tapioca/dsl/compilers/state_machines.rb +1 -1
  38. data/lib/tapioca/dsl/compilers/url_helpers.rb +5 -2
  39. data/lib/tapioca/dsl/helpers/param_helper.rb +4 -1
  40. data/lib/tapioca/dsl/pipeline.rb +32 -1
  41. data/lib/tapioca/dsl.rb +6 -0
  42. data/lib/tapioca/executor.rb +4 -46
  43. data/lib/tapioca/gem/listeners/methods.rb +26 -1
  44. data/lib/tapioca/gem/listeners/sorbet_props.rb +1 -1
  45. data/lib/tapioca/gem/listeners/sorbet_required_ancestors.rb +1 -0
  46. data/lib/tapioca/gem/listeners/sorbet_signatures.rb +1 -1
  47. data/lib/tapioca/gem/pipeline.rb +5 -1
  48. data/lib/tapioca/gemfile.rb +50 -3
  49. data/lib/tapioca/helpers/config_helper.rb +13 -0
  50. data/lib/tapioca/helpers/rbi_helper.rb +114 -7
  51. data/lib/tapioca/helpers/shims_helper.rb +36 -8
  52. data/lib/tapioca/helpers/signatures_helper.rb +17 -0
  53. data/lib/tapioca/helpers/sorbet_helper.rb +5 -11
  54. data/lib/tapioca/helpers/test/content.rb +1 -0
  55. data/lib/tapioca/helpers/test/dsl_compiler.rb +1 -0
  56. data/lib/tapioca/helpers/test/template.rb +1 -0
  57. data/lib/tapioca/helpers/type_variable_helper.rb +43 -0
  58. data/lib/tapioca/internal.rb +4 -1
  59. data/lib/tapioca/rbi_ext/model.rb +14 -2
  60. data/lib/tapioca/repo_index.rb +41 -0
  61. data/lib/tapioca/runtime/generic_type_registry.rb +4 -2
  62. data/lib/tapioca/runtime/loader.rb +3 -0
  63. data/lib/tapioca/runtime/reflection.rb +17 -13
  64. data/lib/tapioca/sorbet_ext/generic_name_patch.rb +38 -21
  65. data/lib/tapioca/static/symbol_table_parser.rb +2 -0
  66. data/lib/tapioca/version.rb +1 -1
  67. data/lib/tapioca.rb +5 -0
  68. metadata +26 -21
data/lib/tapioca/cli.rb CHANGED
@@ -5,6 +5,7 @@ module Tapioca
5
5
  class Cli < Thor
6
6
  include CliHelper
7
7
  include ConfigHelper
8
+ include SorbetHelper
8
9
  include ShimsHelper
9
10
 
10
11
  FILE_HEADER_OPTION_DESC = "Add a \"This file is generated\" header on top of each generated RBI file"
@@ -89,7 +90,7 @@ module Tapioca
89
90
  option :quiet,
90
91
  aliases: ["-q"],
91
92
  type: :boolean,
92
- desc: "Supresses file creation output",
93
+ desc: "Suppresses file creation output",
93
94
  default: false
94
95
  option :workers,
95
96
  aliases: ["-w"],
@@ -171,7 +172,7 @@ module Tapioca
171
172
  option :doc,
172
173
  type: :boolean,
173
174
  desc: "Include YARD documentation from sources when generating RBIs. Warning: this might be slow",
174
- default: false
175
+ default: true
175
176
  option :exported_gem_rbis,
176
177
  type: :boolean,
177
178
  desc: "Include RBIs found in the `rbi/` directory of the gem",
@@ -242,6 +243,7 @@ module Tapioca
242
243
  option :gem_rbi_dir, type: :string, desc: "Path to gem RBIs", default: DEFAULT_GEM_DIR
243
244
  option :dsl_rbi_dir, type: :string, desc: "Path to DSL RBIs", default: DEFAULT_DSL_DIR
244
245
  option :shim_rbi_dir, type: :string, desc: "Path to shim RBIs", default: DEFAULT_SHIM_DIR
246
+ option :payload, type: :boolean, desc: "Check shims against Sorbet's payload", default: true
245
247
  def check_shims
246
248
  index = RBI::Index.new
247
249
 
@@ -251,6 +253,30 @@ module Tapioca
251
253
  exit(0)
252
254
  end
253
255
 
256
+ payload_path = T.let(nil, T.nilable(String))
257
+
258
+ if options[:payload]
259
+ if sorbet_supports?(:print_payload_sources)
260
+ Dir.mktmpdir do |dir|
261
+ payload_path = dir
262
+ result = sorbet("--no-config --print=payload-sources:#{payload_path}")
263
+
264
+ unless result.status
265
+ say_error("Sorbet failed to dump payload")
266
+ say_error(result.err)
267
+ exit(1)
268
+ end
269
+
270
+ index_payload(index, payload_path)
271
+ end
272
+ else
273
+ say_error("The version of Sorbet used in your Gemfile.lock does not support `--print=payload-sources`")
274
+ say_error("Current: v#{SORBET_GEM_SPEC.version}")
275
+ say_error("Required: #{FEATURE_REQUIREMENTS[:print_payload_sources]}")
276
+ exit(1)
277
+ end
278
+ end
279
+
254
280
  index_rbis(index, "shim", shim_rbi_dir)
255
281
  index_rbis(index, "gem", options[:gem_rbi_dir])
256
282
  index_rbis(index, "dsl", options[:dsl_rbi_dir])
@@ -260,7 +286,11 @@ module Tapioca
260
286
  duplicates.each do |key, nodes|
261
287
  say_error("\nDuplicated RBI for #{key}:", :red)
262
288
  nodes.each do |node|
263
- say_error(" * #{node.loc}", :red)
289
+ node_loc = node.loc
290
+ next unless node_loc
291
+
292
+ loc_string = location_to_payload_url(node_loc, path_prefix: payload_path)
293
+ say_error(" * #{loc_string}", :red)
264
294
  end
265
295
  end
266
296
  say_error("\nPlease remove the duplicated definitions from the #{shim_rbi_dir} directory.", :red)
@@ -271,6 +301,13 @@ module Tapioca
271
301
  exit(0)
272
302
  end
273
303
 
304
+ desc "annotations", "Pull gem annotations from a central RBI repository"
305
+ option :repo_uri, type: :string, desc: "Repository URI to pull annotations from", default: CENTRAL_REPO_ROOT_URI
306
+ def annotations
307
+ command = Commands::Annotations.new(central_repo_root_uri: options[:repo_uri])
308
+ command.execute
309
+ end
310
+
274
311
  map ["--version", "-v"] => :__print_version
275
312
 
276
313
  desc "--version, -v", "show version"
@@ -0,0 +1,154 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "net/http"
5
+
6
+ module Tapioca
7
+ module Commands
8
+ class Annotations < Command
9
+ extend T::Sig
10
+
11
+ sig do
12
+ params(
13
+ central_repo_root_uri: String,
14
+ central_repo_index_path: String
15
+ ).void
16
+ end
17
+ def initialize(central_repo_root_uri:, central_repo_index_path: CENTRAL_REPO_INDEX_PATH)
18
+ super()
19
+ @central_repo_root_uri = central_repo_root_uri
20
+ @index = T.let(fetch_index, RepoIndex)
21
+ end
22
+
23
+ sig { override.void }
24
+ def execute
25
+ project_gems = list_gemfile_gems
26
+ remove_expired_annotations(project_gems)
27
+ fetch_annotations(project_gems)
28
+ end
29
+
30
+ private
31
+
32
+ sig { returns(T::Array[String]) }
33
+ def list_gemfile_gems
34
+ say("Listing gems from Gemfile.lock... ", [:blue, :bold])
35
+ gemfile = Bundler.read_file("Gemfile.lock")
36
+ parser = Bundler::LockfileParser.new(gemfile)
37
+ gem_names = parser.specs.map(&:name)
38
+ say("Done", :green)
39
+ gem_names
40
+ end
41
+
42
+ sig { params(project_gems: T::Array[String]).void }
43
+ def remove_expired_annotations(project_gems)
44
+ say("Removing annotations for gems that have been removed... ", [:blue, :bold])
45
+
46
+ annotations = Pathname.glob("#{DEFAULT_ANNOTATIONS_DIR}/*.rbi").map { |f| f.basename(".*").to_s }
47
+ expired = annotations - project_gems
48
+
49
+ if expired.empty?
50
+ say(" Nothing to do")
51
+ return
52
+ end
53
+
54
+ say("\n")
55
+ expired.each do |gem_name|
56
+ say("\n")
57
+ path = "#{DEFAULT_ANNOTATIONS_DIR}/#{gem_name}.rbi"
58
+ remove_file(path)
59
+ end
60
+ say("\nDone\n\n", :green)
61
+ end
62
+
63
+ sig { returns(RepoIndex) }
64
+ def fetch_index
65
+ say("Retrieving index from central repository... ", [:blue, :bold])
66
+ content = fetch_file(CENTRAL_REPO_INDEX_PATH)
67
+ exit(1) unless content
68
+
69
+ index = RepoIndex.from_json(content)
70
+ say("Done", :green)
71
+ index
72
+ end
73
+
74
+ sig { params(gem_names: T::Array[String]).returns(T::Array[String]) }
75
+ def fetch_annotations(gem_names)
76
+ say("Fetching gem annotations from central repository... ", [:blue, :bold])
77
+ fetchable_gems = gem_names.select { |gem_name| @index.has_gem?(gem_name) }
78
+
79
+ if fetchable_gems.empty?
80
+ say(" Nothing to do")
81
+ exit(0)
82
+ end
83
+
84
+ say("\n")
85
+ fetched_gems = fetchable_gems.select { |name| fetch_annotation(name) }
86
+ say("\nDone", :green)
87
+ fetched_gems
88
+ end
89
+
90
+ sig { params(gem_name: String).void }
91
+ def fetch_annotation(gem_name)
92
+ content = fetch_file("#{CENTRAL_REPO_ANNOTATIONS_DIR}/#{gem_name}.rbi")
93
+ return unless content
94
+
95
+ content = add_header(gem_name, content)
96
+
97
+ dir = DEFAULT_ANNOTATIONS_DIR
98
+ FileUtils.mkdir_p(dir)
99
+ say("\n Fetched #{set_color(gem_name, :yellow, :bold)}", :green)
100
+ create_file("#{dir}/#{gem_name}.rbi", content)
101
+ end
102
+
103
+ sig { params(path: String).returns(T.nilable(String)) }
104
+ def fetch_file(path)
105
+ if @central_repo_root_uri.start_with?(%r{https?://})
106
+ fetch_http_file(path)
107
+ else
108
+ fetch_local_file(path)
109
+ end
110
+ end
111
+
112
+ sig { params(path: String).returns(T.nilable(String)) }
113
+ def fetch_local_file(path)
114
+ File.read("#{@central_repo_root_uri}/#{path}")
115
+ rescue => e
116
+ say_error("\nCan't fetch file `#{path}` (#{e.message})", :bold, :red)
117
+ nil
118
+ end
119
+
120
+ sig { params(path: String).returns(T.nilable(String)) }
121
+ def fetch_http_file(path)
122
+ uri = URI("#{@central_repo_root_uri}/#{path}")
123
+ response = Net::HTTP.get_response(uri)
124
+ case response
125
+ when Net::HTTPSuccess
126
+ response.body
127
+ else
128
+ say_error("\nCan't fetch file `#{path}` from #{@central_repo_root_uri} (#{response.class})", :bold, :red)
129
+ nil
130
+ end
131
+ rescue SocketError, Errno::ECONNREFUSED => e
132
+ say_error("\nCan't fetch file `#{path}` from #{@central_repo_root_uri} (#{e.message})", :bold, :red)
133
+ nil
134
+ end
135
+
136
+ sig { params(name: String, content: String).returns(String) }
137
+ def add_header(name, content)
138
+ header = <<~COMMENT
139
+ # DO NOT EDIT MANUALLY
140
+ # This file was pulled from #{@central_repo_root_uri}.
141
+ # Please run `#{default_command(:annotations)}` to update it.
142
+ COMMENT
143
+
144
+ contents = content.split("\n")
145
+ if contents[0]&.start_with?("# typed:") && contents[1]&.empty?
146
+ contents.insert(2, header).join("\n")
147
+ else
148
+ say_error("Couldn't insert file header for content: #{content} due to unexpected file format")
149
+ content
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
@@ -4,6 +4,9 @@
4
4
  module Tapioca
5
5
  module Commands
6
6
  class Dsl < Command
7
+ include SorbetHelper
8
+ include RBIHelper
9
+
7
10
  sig do
8
11
  params(
9
12
  requested_constants: T::Array[String],
@@ -17,6 +20,8 @@ module Tapioca
17
20
  quiet: T::Boolean,
18
21
  verbose: T::Boolean,
19
22
  number_of_workers: T.nilable(Integer),
23
+ auto_strictness: T::Boolean,
24
+ gem_dir: String,
20
25
  rbi_formatter: RBIFormatter
21
26
  ).void
22
27
  end
@@ -32,6 +37,8 @@ module Tapioca
32
37
  quiet: false,
33
38
  verbose: false,
34
39
  number_of_workers: nil,
40
+ auto_strictness: true,
41
+ gem_dir: DEFAULT_GEM_DIR,
35
42
  rbi_formatter: DEFAULT_RBI_FORMATTER
36
43
  )
37
44
  @requested_constants = requested_constants
@@ -45,6 +52,8 @@ module Tapioca
45
52
  @quiet = quiet
46
53
  @verbose = verbose
47
54
  @number_of_workers = number_of_workers
55
+ @auto_strictness = auto_strictness
56
+ @gem_dir = gem_dir
48
57
  @rbi_formatter = rbi_formatter
49
58
 
50
59
  super()
@@ -102,9 +111,19 @@ module Tapioca
102
111
  perform_dsl_verification(outpath)
103
112
  else
104
113
  purge_stale_dsl_rbi_files(rbi_files_to_purge)
105
-
106
114
  say("Done", :green)
107
115
 
116
+ if @auto_strictness
117
+ say("")
118
+ validate_rbi_files(
119
+ command: default_command(:dsl, @requested_constants.join(" ")),
120
+ gem_dir: @gem_dir,
121
+ dsl_dir: @outpath.to_s,
122
+ auto_strictness: @auto_strictness,
123
+ compilers: pipeline.compilers
124
+ )
125
+ end
126
+
108
127
  say("All operations performed in working directory.", [:green, :bold])
109
128
  say("Please review changes and commit them.", [:green, :bold])
110
129
  end
@@ -5,6 +5,7 @@ module Tapioca
5
5
  module Commands
6
6
  class Gem < Command
7
7
  include SorbetHelper
8
+ include RBIHelper
8
9
 
9
10
  sig do
10
11
  params(
@@ -78,7 +79,13 @@ module Tapioca
78
79
  end
79
80
 
80
81
  if anything_done
81
- update_strictnesses(gem_queue.map(&:name), gem_dir: @outpath.to_s, dsl_dir: @dsl_dir) if @auto_strictness
82
+ validate_rbi_files(
83
+ command: default_command(:gem, @gem_names.join(" ")),
84
+ gem_dir: @outpath.to_s,
85
+ dsl_dir: @dsl_dir,
86
+ auto_strictness: @auto_strictness,
87
+ gems: bundle.dependencies
88
+ )
82
89
 
83
90
  say("All operations performed in working directory.", [:green, :bold])
84
91
  say("Please review changes and commit them.", [:green, :bold])
@@ -102,7 +109,13 @@ module Tapioca
102
109
  ].any?
103
110
 
104
111
  if anything_done
105
- update_strictnesses([], gem_dir: @outpath.to_s, dsl_dir: @dsl_dir) if @auto_strictness
112
+ validate_rbi_files(
113
+ command: default_command(:gem),
114
+ gem_dir: @outpath.to_s,
115
+ dsl_dir: @dsl_dir,
116
+ auto_strictness: @auto_strictness,
117
+ gems: bundle.dependencies
118
+ )
106
119
 
107
120
  say("All operations performed in working directory.", [:green, :bold])
108
121
  say("Please review changes and commit them.", [:green, :bold])
@@ -122,7 +135,7 @@ module Tapioca
122
135
 
123
136
  sig { returns(Gemfile) }
124
137
  def bundle
125
- @bundle ||= Gemfile.new
138
+ @bundle ||= Gemfile.new(@exclude)
126
139
  end
127
140
 
128
141
  sig { void }
@@ -359,6 +372,7 @@ module Tapioca
359
372
  sig { params(gem: Gemfile::GemSpec, file: RBI::File).void }
360
373
  def merge_with_exported_rbi(gem, file)
361
374
  return file unless gem.export_rbi_files?
375
+
362
376
  tree = gem.exported_rbi_tree
363
377
 
364
378
  unless tree.conflicts.empty?
@@ -379,60 +393,6 @@ module Tapioca
379
393
  say_error("\n\n RBIs exported by `#{gem.name}` contain errors and can't be used:", :yellow)
380
394
  say_error("Cause: #{e.message} (#{e.location})")
381
395
  end
382
-
383
- sig { params(gem_names: T::Array[String], gem_dir: String, dsl_dir: String).void }
384
- def update_strictnesses(gem_names, gem_dir: DEFAULT_GEM_DIR, dsl_dir: DEFAULT_DSL_DIR)
385
- return unless File.directory?(dsl_dir)
386
-
387
- error_url_base = Spoom::Sorbet::Errors::DEFAULT_ERROR_URL_BASE
388
-
389
- say("Typechecking RBI files... ")
390
- res = sorbet(
391
- "--no-config",
392
- "--error-url-base=#{error_url_base}",
393
- "--isolate-error-code 4010",
394
- dsl_dir,
395
- gem_dir
396
- )
397
- say(" Done", :green)
398
-
399
- errors = Spoom::Sorbet::Errors::Parser.parse_string(res.err)
400
-
401
- if errors.empty?
402
- say("No error found", [:green, :bold])
403
- return
404
- end
405
-
406
- files = []
407
-
408
- errors.each do |error|
409
- # Collect the file with error
410
- files << error.file
411
- error.more.each do |line|
412
- # Also collect the conflicting definition file paths
413
- next unless line.include?("Previous definition")
414
- files << line.split(":").first&.strip
415
- end
416
- end
417
-
418
- files
419
- .uniq
420
- .sort
421
- .select do |file|
422
- name = gem_name_from_rbi_path(file)
423
- file.start_with?(gem_dir) && (gem_names.empty? || gem_names.include?(name))
424
- end.each do |file|
425
- Spoom::Sorbet::Sigils.change_sigil_in_file(file, "false")
426
- say("\n Changed strictness of #{file} to `typed: false` (conflicting with DSL files)", [:yellow, :bold])
427
- end
428
-
429
- say("\n")
430
- end
431
-
432
- sig { params(path: String).returns(String) }
433
- def gem_name_from_rbi_path(path)
434
- T.must(File.basename(path, ".rbi").split("@").first)
435
- end
436
396
  end
437
397
  end
438
398
  end
@@ -41,6 +41,7 @@ module Tapioca
41
41
  create_file(@sorbet_config, <<~CONTENT, skip: true, force: false)
42
42
  --dir
43
43
  .
44
+ --ignore=vendor/
44
45
  CONTENT
45
46
  end
46
47
 
@@ -74,10 +74,12 @@ module Tapioca
74
74
  .each_line
75
75
  .map do |line|
76
76
  next if line.include?("<")
77
- next if line.include?("class_of")
78
- line.strip.gsub("T.untyped::", "")
77
+
78
+ line.strip
79
+ .gsub(/T\.class_of\(([:\w]+)\)/, '\1') # Turn T.class_of(Foo)::Bar into Foo::Bar
79
80
  end
80
81
  .compact
82
+ .sort
81
83
  end
82
84
  end
83
85
  end
@@ -4,6 +4,7 @@
4
4
  module Tapioca
5
5
  module Commands
6
6
  autoload :Command, "tapioca/commands/command"
7
+ autoload :Annotations, "tapioca/commands/annotations"
7
8
  autoload :Dsl, "tapioca/commands/dsl"
8
9
  autoload :Init, "tapioca/commands/init"
9
10
  autoload :Gem, "tapioca/commands/gem"
@@ -17,7 +17,7 @@ module Tapioca
17
17
  include Runtime::Reflection
18
18
  extend Runtime::Reflection
19
19
 
20
- ConstantType = type_member(upper: Module)
20
+ ConstantType = type_member { { upper: Module } }
21
21
 
22
22
  abstract!
23
23
 
@@ -54,7 +54,7 @@ module Tapioca
54
54
  sig { returns(T::Set[Module]) }
55
55
  def self.processable_constants
56
56
  @processable_constants ||= T.let(
57
- Set.new(gather_constants).tap(&:compare_by_identity),
57
+ T::Set[Module].new(gather_constants).compare_by_identity,
58
58
  T.nilable(T::Set[Module])
59
59
  )
60
60
  T.must(@processable_constants)
@@ -49,7 +49,7 @@ module Tapioca
49
49
  T::Array[String]
50
50
  )
51
51
 
52
- ConstantType = type_member(fixed: T.all(::AASM::ClassMethods, Class))
52
+ ConstantType = type_member { { fixed: T.all(::AASM::ClassMethods, Class) } }
53
53
 
54
54
  sig { override.void }
55
55
  def decorate
@@ -68,7 +68,7 @@ module Tapioca
68
68
  class ActionControllerHelpers < Compiler
69
69
  extend T::Sig
70
70
 
71
- ConstantType = type_member(fixed: T.class_of(::ActionController::Base))
71
+ ConstantType = type_member { { fixed: T.class_of(::ActionController::Base) } }
72
72
 
73
73
  sig { override.void }
74
74
  def decorate
@@ -36,7 +36,7 @@ module Tapioca
36
36
  class ActionMailer < Compiler
37
37
  extend T::Sig
38
38
 
39
- ConstantType = type_member(fixed: T.class_of(::ActionMailer::Base))
39
+ ConstantType = type_member { { fixed: T.class_of(::ActionMailer::Base) } }
40
40
 
41
41
  sig { override.void }
42
42
  def decorate
@@ -40,7 +40,7 @@ module Tapioca
40
40
  class ActiveJob < Compiler
41
41
  extend T::Sig
42
42
 
43
- ConstantType = type_member(fixed: T.class_of(::ActiveJob::Base))
43
+ ConstantType = type_member { { fixed: T.class_of(::ActiveJob::Base) } }
44
44
 
45
45
  sig { override.void }
46
46
  def decorate
@@ -39,7 +39,7 @@ module Tapioca
39
39
  class ActiveModelAttributes < Compiler
40
40
  extend T::Sig
41
41
 
42
- ConstantType = type_member(fixed: T.all(Class, ::ActiveModel::Attributes::ClassMethods))
42
+ ConstantType = type_member { { fixed: T.all(Class, ::ActiveModel::Attributes::ClassMethods) } }
43
43
 
44
44
  sig { override.void }
45
45
  def decorate
@@ -60,7 +60,7 @@ module Tapioca
60
60
  class ActiveModelSecurePassword < Compiler
61
61
  extend T::Sig
62
62
 
63
- ConstantType = type_member(fixed: T.all(Class, ::ActiveModel::SecurePassword::ClassMethods))
63
+ ConstantType = type_member { { fixed: T.all(Class, ::ActiveModel::SecurePassword::ClassMethods) } }
64
64
 
65
65
  sig { override.void }
66
66
  def decorate
@@ -119,7 +119,7 @@ module Tapioca
119
119
  end
120
120
  end
121
121
 
122
- ConstantType = type_member(fixed: T.class_of(ActiveRecord::Base))
122
+ ConstantType = type_member { { fixed: T.class_of(ActiveRecord::Base) } }
123
123
 
124
124
  sig { override.void }
125
125
  def decorate
@@ -101,7 +101,7 @@ module Tapioca
101
101
  extend T::Sig
102
102
  include Helpers::ActiveRecordConstantsHelper
103
103
 
104
- ConstantType = type_member(fixed: T.class_of(ActiveRecord::Base))
104
+ ConstantType = type_member { { fixed: T.class_of(ActiveRecord::Base) } }
105
105
 
106
106
  sig { override.void }
107
107
  def decorate
@@ -58,7 +58,7 @@ module Tapioca
58
58
  class ActiveRecordEnum < Compiler
59
59
  extend T::Sig
60
60
 
61
- ConstantType = type_member(fixed: T.class_of(::ActiveRecord::Base))
61
+ ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
62
62
 
63
63
  sig { override.void }
64
64
  def decorate
@@ -38,7 +38,7 @@ module Tapioca
38
38
  class ActiveRecordFixtures < Compiler
39
39
  extend T::Sig
40
40
 
41
- ConstantType = type_member(fixed: T.class_of(ActiveSupport::TestCase))
41
+ ConstantType = type_member { { fixed: T.class_of(ActiveSupport::TestCase) } }
42
42
 
43
43
  sig { override.void }
44
44
  def decorate
@@ -60,6 +60,8 @@ module Tapioca
60
60
 
61
61
  sig { override.returns(T::Enumerable[Module]) }
62
62
  def self.gather_constants
63
+ return [] unless Rails.application
64
+
63
65
  [ActiveSupport::TestCase]
64
66
  end
65
67
 
@@ -118,7 +118,7 @@ module Tapioca
118
118
  # sig { returns(T::Array[::Post]) }
119
119
  # def to_ary; end
120
120
  #
121
- # Elem = type_member(fixed: ::Post)
121
+ # Elem = type_member { { fixed: ::Post } }
122
122
  # end
123
123
  #
124
124
  # class PrivateCollectionProxy < ::ActiveRecord::Associations::CollectionProxy
@@ -141,7 +141,7 @@ module Tapioca
141
141
  # sig { returns(T::Array[::Post]) }
142
142
  # def to_ary; end
143
143
  #
144
- # Elem = type_member(fixed: ::Post)
144
+ # Elem = type_member { { fixed: ::Post } }
145
145
  # end
146
146
  # end
147
147
  # ~~~
@@ -150,7 +150,7 @@ module Tapioca
150
150
  include Helpers::ActiveRecordConstantsHelper
151
151
  include SorbetHelper
152
152
 
153
- ConstantType = type_member(fixed: T.class_of(::ActiveRecord::Base))
153
+ ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
154
154
 
155
155
  sig { override.void }
156
156
  def decorate
@@ -253,7 +253,7 @@ module Tapioca
253
253
  model.create_class(RelationClassName, superclass_name: superclass) do |klass|
254
254
  klass.create_include(CommonRelationMethodsModuleName)
255
255
  klass.create_include(RelationMethodsModuleName)
256
- klass.create_constant("Elem", value: "type_member(fixed: #{constant_name})")
256
+ klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
257
257
 
258
258
  klass.create_method("to_ary", return_type: "T::Array[#{constant_name}]")
259
259
  end
@@ -269,7 +269,7 @@ module Tapioca
269
269
  model.create_class(AssociationRelationClassName, superclass_name: superclass) do |klass|
270
270
  klass.create_include(CommonRelationMethodsModuleName)
271
271
  klass.create_include(AssociationRelationMethodsModuleName)
272
- klass.create_constant("Elem", value: "type_member(fixed: #{constant_name})")
272
+ klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
273
273
 
274
274
  klass.create_method("to_ary", return_type: "T::Array[#{constant_name}]")
275
275
  end
@@ -281,7 +281,7 @@ module Tapioca
281
281
  def create_relation_where_chain_class(model)
282
282
  model.create_class(RelationWhereChainClassName, superclass_name: RelationClassName) do |klass|
283
283
  create_where_chain_methods(klass, RelationClassName)
284
- klass.create_constant("Elem", value: "type_member(fixed: #{constant_name})")
284
+ klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
285
285
  end
286
286
  end
287
287
 
@@ -292,7 +292,7 @@ module Tapioca
292
292
  superclass_name: AssociationRelationClassName
293
293
  ) do |klass|
294
294
  create_where_chain_methods(klass, AssociationRelationClassName)
295
- klass.create_constant("Elem", value: "type_member(fixed: #{constant_name})")
295
+ klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
296
296
  end
297
297
  end
298
298
 
@@ -329,7 +329,7 @@ module Tapioca
329
329
  model.create_class(AssociationsCollectionProxyClassName, superclass_name: superclass) do |klass|
330
330
  klass.create_include(CommonRelationMethodsModuleName)
331
331
  klass.create_include(AssociationRelationMethodsModuleName)
332
- klass.create_constant("Elem", value: "type_member(fixed: #{constant_name})")
332
+ klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
333
333
 
334
334
  klass.create_method("to_ary", return_type: "T::Array[#{constant_name}]")
335
335
  create_collection_proxy_methods(klass)
@@ -46,7 +46,7 @@ module Tapioca
46
46
  extend T::Sig
47
47
  include Helpers::ActiveRecordConstantsHelper
48
48
 
49
- ConstantType = type_member(fixed: T.class_of(::ActiveRecord::Base))
49
+ ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
50
50
 
51
51
  sig { override.void }
52
52
  def decorate
@@ -90,7 +90,7 @@ module Tapioca
90
90
  class ActiveRecordTypedStore < Compiler
91
91
  extend T::Sig
92
92
 
93
- ConstantType = type_member(fixed: T.class_of(::ActiveRecord::Base))
93
+ ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
94
94
 
95
95
  sig { override.void }
96
96
  def decorate
@@ -61,7 +61,7 @@ module Tapioca
61
61
  class ActiveResource < Compiler
62
62
  extend T::Sig
63
63
 
64
- ConstantType = type_member(fixed: T.class_of(::ActiveResource::Base))
64
+ ConstantType = type_member { { fixed: T.class_of(::ActiveResource::Base) } }
65
65
 
66
66
  sig { override.void }
67
67
  def decorate