tapioca 0.16.11 → 0.17.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 +4 -4
- data/lib/ruby_lsp/tapioca/addon.rb +23 -19
- data/lib/ruby_lsp/tapioca/run_gem_rbi_check.rb +20 -20
- data/lib/tapioca/bundler_ext/auto_require_hook.rb +5 -10
- data/lib/tapioca/commands/abstract_dsl.rb +26 -59
- data/lib/tapioca/commands/abstract_gem.rb +23 -43
- data/lib/tapioca/commands/annotations.rb +27 -33
- data/lib/tapioca/commands/check_shims.rb +4 -13
- data/lib/tapioca/commands/command.rb +8 -20
- data/lib/tapioca/commands/command_without_tracker.rb +1 -1
- data/lib/tapioca/commands/configure.rb +11 -16
- data/lib/tapioca/commands/dsl_compiler_list.rb +2 -1
- data/lib/tapioca/commands/dsl_generate.rb +2 -1
- data/lib/tapioca/commands/dsl_verify.rb +2 -1
- data/lib/tapioca/commands/gem_generate.rb +4 -8
- data/lib/tapioca/commands/gem_sync.rb +2 -1
- data/lib/tapioca/commands/gem_verify.rb +3 -2
- data/lib/tapioca/commands/require.rb +3 -7
- data/lib/tapioca/commands/todo.rb +6 -10
- data/lib/tapioca/dsl/compiler.rb +28 -53
- data/lib/tapioca/dsl/compilers/aasm.rb +31 -41
- data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +7 -5
- data/lib/tapioca/dsl/compilers/action_mailer.rb +5 -3
- data/lib/tapioca/dsl/compilers/action_text.rb +5 -3
- data/lib/tapioca/dsl/compilers/active_job.rb +5 -8
- data/lib/tapioca/dsl/compilers/active_model_attributes.rb +9 -7
- data/lib/tapioca/dsl/compilers/active_model_secure_password.rb +4 -2
- data/lib/tapioca/dsl/compilers/active_model_validations_confirmation.rb +4 -2
- data/lib/tapioca/dsl/compilers/active_record_associations.rb +16 -42
- data/lib/tapioca/dsl/compilers/active_record_columns.rb +19 -24
- data/lib/tapioca/dsl/compilers/active_record_delegated_types.rb +7 -5
- data/lib/tapioca/dsl/compilers/active_record_enum.rb +6 -4
- data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +53 -61
- data/lib/tapioca/dsl/compilers/active_record_relations.rb +86 -119
- data/lib/tapioca/dsl/compilers/active_record_scope.rb +7 -11
- data/lib/tapioca/dsl/compilers/active_record_secure_token.rb +4 -2
- data/lib/tapioca/dsl/compilers/active_record_store.rb +4 -2
- data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +18 -26
- data/lib/tapioca/dsl/compilers/active_resource.rb +18 -19
- data/lib/tapioca/dsl/compilers/active_storage.rb +5 -5
- data/lib/tapioca/dsl/compilers/active_support_concern.rb +8 -6
- data/lib/tapioca/dsl/compilers/active_support_current_attributes.rb +7 -5
- data/lib/tapioca/dsl/compilers/active_support_time_ext.rb +4 -2
- data/lib/tapioca/dsl/compilers/config.rb +4 -2
- data/lib/tapioca/dsl/compilers/frozen_record.rb +6 -9
- data/lib/tapioca/dsl/compilers/graphql_input_object.rb +8 -8
- data/lib/tapioca/dsl/compilers/graphql_mutation.rb +5 -8
- data/lib/tapioca/dsl/compilers/identity_cache.rb +10 -37
- data/lib/tapioca/dsl/compilers/json_api_client_resource.rb +8 -16
- data/lib/tapioca/dsl/compilers/kredis.rb +6 -4
- data/lib/tapioca/dsl/compilers/mixed_in_class_attributes.rb +4 -2
- data/lib/tapioca/dsl/compilers/protobuf.rb +12 -24
- data/lib/tapioca/dsl/compilers/rails_generators.rb +8 -9
- data/lib/tapioca/dsl/compilers/sidekiq_worker.rb +22 -11
- data/lib/tapioca/dsl/compilers/smart_properties.rb +11 -20
- data/lib/tapioca/dsl/compilers/state_machines.rb +14 -24
- data/lib/tapioca/dsl/compilers/url_helpers.rb +9 -7
- data/lib/tapioca/dsl/compilers.rb +4 -7
- data/lib/tapioca/dsl/helpers/active_model_type_helper.rb +13 -16
- data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +13 -28
- data/lib/tapioca/dsl/helpers/active_record_constants_helper.rb +19 -15
- data/lib/tapioca/dsl/helpers/graphql_type_helper.rb +5 -24
- data/lib/tapioca/dsl/pipeline.rb +23 -55
- data/lib/tapioca/executor.rb +6 -12
- data/lib/tapioca/gem/events.rb +22 -28
- data/lib/tapioca/gem/listeners/base.rb +6 -6
- data/lib/tapioca/gem/listeners/dynamic_mixins.rb +4 -2
- data/lib/tapioca/gem/listeners/foreign_constants.rb +5 -7
- data/lib/tapioca/gem/listeners/methods.rb +15 -34
- data/lib/tapioca/gem/listeners/mixins.rb +6 -18
- data/lib/tapioca/gem/listeners/remove_empty_payload_scopes.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_enums.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_helpers.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_props.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_required_ancestors.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_signatures.rb +7 -5
- data/lib/tapioca/gem/listeners/sorbet_type_variables.rb +6 -4
- data/lib/tapioca/gem/listeners/source_location.rb +7 -4
- data/lib/tapioca/gem/listeners/subconstants.rb +4 -2
- data/lib/tapioca/gem/listeners/yard_doc.rb +23 -22
- data/lib/tapioca/gem/pipeline.rb +57 -72
- data/lib/tapioca/gem_info.rb +1 -1
- data/lib/tapioca/gemfile.rb +64 -73
- data/lib/tapioca/helpers/cli_helper.rb +3 -3
- data/lib/tapioca/helpers/config_helper.rb +15 -24
- data/lib/tapioca/helpers/env_helper.rb +1 -1
- data/lib/tapioca/helpers/gem_helper.rb +5 -5
- data/lib/tapioca/helpers/git_attributes.rb +3 -3
- data/lib/tapioca/helpers/rbi_files_helper.rb +73 -67
- data/lib/tapioca/helpers/rbi_helper.rb +14 -22
- data/lib/tapioca/helpers/sorbet_helper.rb +9 -18
- data/lib/tapioca/helpers/source_uri.rb +15 -25
- data/lib/tapioca/helpers/test/content.rb +6 -6
- data/lib/tapioca/helpers/test/dsl_compiler.rb +19 -29
- data/lib/tapioca/helpers/test/isolation.rb +4 -4
- data/lib/tapioca/helpers/test/template.rb +5 -7
- data/lib/tapioca/internal.rb +5 -1
- data/lib/tapioca/loaders/dsl.rb +11 -19
- data/lib/tapioca/loaders/gem.rb +6 -21
- data/lib/tapioca/loaders/loader.rb +15 -27
- data/lib/tapioca/rbi_ext/model.rb +12 -37
- data/lib/tapioca/rbi_formatter.rb +10 -19
- data/lib/tapioca/rbs/rewriter.rb +55 -0
- data/lib/tapioca/repo_index.rb +7 -7
- data/lib/tapioca/runtime/attached_class_of_32.rb +1 -1
- data/lib/tapioca/runtime/attached_class_of_legacy.rb +1 -1
- data/lib/tapioca/runtime/dynamic_mixin_compiler.rb +23 -23
- data/lib/tapioca/runtime/generic_type_registry.rb +13 -23
- data/lib/tapioca/runtime/reflection.rb +48 -56
- data/lib/tapioca/runtime/trackers/autoload.rb +4 -8
- data/lib/tapioca/runtime/trackers/mixin.rb +6 -10
- data/lib/tapioca/runtime/trackers/required_ancestor.rb +3 -3
- data/lib/tapioca/runtime/trackers/tracker.rb +2 -2
- data/lib/tapioca/runtime/trackers.rb +4 -8
- data/lib/tapioca/sorbet_ext/generic_name_patch.rb +9 -15
- data/lib/tapioca/sorbet_ext/name_patch.rb +1 -1
- data/lib/tapioca/sorbet_ext/proc_bind_patch.rb +1 -1
- data/lib/tapioca/static/requires_compiler.rb +6 -6
- data/lib/tapioca/static/symbol_loader.rb +14 -16
- data/lib/tapioca/static/symbol_table_parser.rb +8 -8
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +22 -29
- metadata +25 -10
@@ -10,21 +10,19 @@ module Tapioca
|
|
10
10
|
|
11
11
|
requires_ancestor { Kernel }
|
12
12
|
|
13
|
-
ERB_SUPPORTS_KVARGS =
|
14
|
-
::ERB.instance_method(:initialize).parameters.assoc(:key), T.nilable([Symbol, Symbol])
|
15
|
-
)
|
13
|
+
ERB_SUPPORTS_KVARGS = ::ERB.instance_method(:initialize).parameters.assoc(:key) #: [Symbol, Symbol]?
|
16
14
|
|
17
|
-
|
15
|
+
#: (String selector) -> bool
|
18
16
|
def ruby_version(selector)
|
19
17
|
::Gem::Requirement.new(selector).satisfied_by?(::Gem::Version.new(RUBY_VERSION))
|
20
18
|
end
|
21
19
|
|
22
|
-
|
20
|
+
#: (String selector) -> bool
|
23
21
|
def rails_version(selector)
|
24
22
|
::Gem::Requirement.new(selector).satisfied_by?(ActiveSupport.gem_version)
|
25
23
|
end
|
26
24
|
|
27
|
-
|
25
|
+
#: (String src, ?trim_mode: String) -> String
|
28
26
|
def template(src, trim_mode: ">")
|
29
27
|
erb = if ERB_SUPPORTS_KVARGS
|
30
28
|
::ERB.new(src, trim_mode: trim_mode)
|
@@ -35,7 +33,7 @@ module Tapioca
|
|
35
33
|
erb.result(binding)
|
36
34
|
end
|
37
35
|
|
38
|
-
|
36
|
+
#: (String str, Integer indent) -> String
|
39
37
|
def indented(str, indent)
|
40
38
|
str.lines.map! do |line|
|
41
39
|
next line if line.chomp.empty?
|
data/lib/tapioca/internal.rb
CHANGED
@@ -7,6 +7,11 @@ require "tapioca"
|
|
7
7
|
require "tapioca/runtime/reflection"
|
8
8
|
require "tapioca/runtime/trackers"
|
9
9
|
|
10
|
+
# The rewriter needs to be loaded very early so RBS comments within Tapioca itself are rewritten
|
11
|
+
require "spoom"
|
12
|
+
require "tapioca/rbs/rewriter"
|
13
|
+
# ^ Do not change the order of these requires
|
14
|
+
|
10
15
|
require "benchmark"
|
11
16
|
require "bundler"
|
12
17
|
require "erb"
|
@@ -32,7 +37,6 @@ require "tapioca/sorbet_ext/generic_name_patch"
|
|
32
37
|
require "tapioca/sorbet_ext/proc_bind_patch"
|
33
38
|
require "tapioca/runtime/generic_type_registry"
|
34
39
|
|
35
|
-
require "spoom"
|
36
40
|
require "tapioca/helpers/gem_helper"
|
37
41
|
require "tapioca/helpers/git_attributes"
|
38
42
|
require "tapioca/helpers/sorbet_helper"
|
data/lib/tapioca/loaders/dsl.rb
CHANGED
@@ -9,14 +9,7 @@ module Tapioca
|
|
9
9
|
class << self
|
10
10
|
extend T::Sig
|
11
11
|
|
12
|
-
|
13
|
-
params(
|
14
|
-
tapioca_path: String,
|
15
|
-
eager_load: T::Boolean,
|
16
|
-
app_root: String,
|
17
|
-
halt_upon_load_error: T::Boolean,
|
18
|
-
).void
|
19
|
-
end
|
12
|
+
#: (tapioca_path: String, ?eager_load: bool, ?app_root: String, ?halt_upon_load_error: bool) -> void
|
20
13
|
def load_application(
|
21
14
|
tapioca_path:,
|
22
15
|
eager_load: true,
|
@@ -32,20 +25,21 @@ module Tapioca
|
|
32
25
|
end
|
33
26
|
end
|
34
27
|
|
35
|
-
|
28
|
+
# @override
|
29
|
+
#: -> void
|
36
30
|
def load
|
37
31
|
load_dsl_extensions
|
38
32
|
load_application
|
39
33
|
load_dsl_compilers
|
40
34
|
end
|
41
35
|
|
42
|
-
|
36
|
+
#: -> void
|
43
37
|
def load_dsl_extensions_and_compilers
|
44
38
|
load_dsl_extensions
|
45
39
|
load_dsl_compilers
|
46
40
|
end
|
47
41
|
|
48
|
-
|
42
|
+
#: -> void
|
49
43
|
def reload_custom_compilers
|
50
44
|
# Remove all loaded custom compilers
|
51
45
|
::Tapioca::Dsl::Compiler.descendants.each do |compiler|
|
@@ -68,9 +62,7 @@ module Tapioca
|
|
68
62
|
|
69
63
|
protected
|
70
64
|
|
71
|
-
|
72
|
-
params(tapioca_path: String, eager_load: T::Boolean, app_root: String, halt_upon_load_error: T::Boolean).void
|
73
|
-
end
|
65
|
+
#: (tapioca_path: String, ?eager_load: bool, ?app_root: String, ?halt_upon_load_error: bool) -> void
|
74
66
|
def initialize(tapioca_path:, eager_load: true, app_root: ".", halt_upon_load_error: true)
|
75
67
|
super()
|
76
68
|
|
@@ -78,10 +70,10 @@ module Tapioca
|
|
78
70
|
@eager_load = eager_load
|
79
71
|
@app_root = app_root
|
80
72
|
@halt_upon_load_error = halt_upon_load_error
|
81
|
-
@custom_compiler_paths =
|
73
|
+
@custom_compiler_paths = [] #: Array[String]
|
82
74
|
end
|
83
75
|
|
84
|
-
|
76
|
+
#: -> void
|
85
77
|
def load_dsl_extensions
|
86
78
|
say("Loading DSL extension classes... ")
|
87
79
|
|
@@ -96,7 +88,7 @@ module Tapioca
|
|
96
88
|
say("Done", :green)
|
97
89
|
end
|
98
90
|
|
99
|
-
|
91
|
+
#: -> void
|
100
92
|
def load_dsl_compilers
|
101
93
|
say("Loading DSL compiler classes... ")
|
102
94
|
|
@@ -116,7 +108,7 @@ module Tapioca
|
|
116
108
|
say("Done", :green)
|
117
109
|
end
|
118
110
|
|
119
|
-
|
111
|
+
#: -> void
|
120
112
|
def load_application
|
121
113
|
say("Loading Rails application... ")
|
122
114
|
|
@@ -132,7 +124,7 @@ module Tapioca
|
|
132
124
|
|
133
125
|
private
|
134
126
|
|
135
|
-
|
127
|
+
#: -> void
|
136
128
|
def load_custom_dsl_compilers
|
137
129
|
@custom_compiler_paths = Dir.glob([
|
138
130
|
"#{@tapioca_path}/generators/**/*.rb", # TODO: Here for backcompat, remove later
|
data/lib/tapioca/loaders/gem.rb
CHANGED
@@ -9,15 +9,7 @@ module Tapioca
|
|
9
9
|
class << self
|
10
10
|
extend T::Sig
|
11
11
|
|
12
|
-
|
13
|
-
params(
|
14
|
-
bundle: Gemfile,
|
15
|
-
prerequire: T.nilable(String),
|
16
|
-
postrequire: String,
|
17
|
-
default_command: String,
|
18
|
-
halt_upon_load_error: T::Boolean,
|
19
|
-
).void
|
20
|
-
end
|
12
|
+
#: (bundle: Gemfile, prerequire: String?, postrequire: String, default_command: String, halt_upon_load_error: bool) -> void
|
21
13
|
def load_application(bundle:, prerequire:, postrequire:, default_command:, halt_upon_load_error:)
|
22
14
|
loader = new(
|
23
15
|
bundle: bundle,
|
@@ -30,22 +22,15 @@ module Tapioca
|
|
30
22
|
end
|
31
23
|
end
|
32
24
|
|
33
|
-
|
25
|
+
# @override
|
26
|
+
#: -> void
|
34
27
|
def load
|
35
28
|
require_gem_file
|
36
29
|
end
|
37
30
|
|
38
31
|
protected
|
39
32
|
|
40
|
-
|
41
|
-
params(
|
42
|
-
bundle: Gemfile,
|
43
|
-
prerequire: T.nilable(String),
|
44
|
-
postrequire: String,
|
45
|
-
default_command: String,
|
46
|
-
halt_upon_load_error: T::Boolean,
|
47
|
-
).void
|
48
|
-
end
|
33
|
+
#: (bundle: Gemfile, prerequire: String?, postrequire: String, default_command: String, halt_upon_load_error: bool) -> void
|
49
34
|
def initialize(bundle:, prerequire:, postrequire:, default_command:, halt_upon_load_error:)
|
50
35
|
super()
|
51
36
|
|
@@ -56,7 +41,7 @@ module Tapioca
|
|
56
41
|
@halt_upon_load_error = halt_upon_load_error
|
57
42
|
end
|
58
43
|
|
59
|
-
|
44
|
+
#: -> void
|
60
45
|
def require_gem_file
|
61
46
|
say("Requiring all gems to prepare for compiling... ")
|
62
47
|
begin
|
@@ -76,7 +61,7 @@ module Tapioca
|
|
76
61
|
puts
|
77
62
|
end
|
78
63
|
|
79
|
-
|
64
|
+
#: (String file, LoadError error) -> void
|
80
65
|
def explain_failed_require(file, error)
|
81
66
|
say_error("\n\nLoadError: #{error}", :bold, :red)
|
82
67
|
say_error("\nTapioca could not load all the gems required by your application.", :yellow)
|
@@ -18,14 +18,7 @@ module Tapioca
|
|
18
18
|
|
19
19
|
private
|
20
20
|
|
21
|
-
|
22
|
-
params(
|
23
|
-
gemfile: Tapioca::Gemfile,
|
24
|
-
initialize_file: T.nilable(String),
|
25
|
-
require_file: T.nilable(String),
|
26
|
-
halt_upon_load_error: T::Boolean,
|
27
|
-
).void
|
28
|
-
end
|
21
|
+
#: (Tapioca::Gemfile gemfile, String? initialize_file, String? require_file, bool halt_upon_load_error) -> void
|
29
22
|
def load_bundle(gemfile, initialize_file, require_file, halt_upon_load_error)
|
30
23
|
require_helper(initialize_file)
|
31
24
|
|
@@ -38,14 +31,7 @@ module Tapioca
|
|
38
31
|
load_rails_engines
|
39
32
|
end
|
40
33
|
|
41
|
-
|
42
|
-
params(
|
43
|
-
environment_load: T::Boolean,
|
44
|
-
eager_load: T::Boolean,
|
45
|
-
app_root: String,
|
46
|
-
halt_upon_load_error: T::Boolean,
|
47
|
-
).void
|
48
|
-
end
|
34
|
+
#: (?environment_load: bool, ?eager_load: bool, ?app_root: String, ?halt_upon_load_error: bool) -> void
|
49
35
|
def load_rails_application(environment_load: false, eager_load: false, app_root: ".", halt_upon_load_error: true)
|
50
36
|
return unless File.exist?(File.expand_path("config/application.rb", app_root))
|
51
37
|
|
@@ -85,7 +71,7 @@ module Tapioca
|
|
85
71
|
say("Continuing RBI generation without loading the Rails application.")
|
86
72
|
end
|
87
73
|
|
88
|
-
|
74
|
+
#: -> void
|
89
75
|
def load_rails_engines
|
90
76
|
return if engines.empty?
|
91
77
|
|
@@ -110,10 +96,10 @@ module Tapioca
|
|
110
96
|
end
|
111
97
|
end
|
112
98
|
|
113
|
-
|
99
|
+
#: -> void
|
114
100
|
def load_engines_in_zeitwerk_mode
|
115
101
|
# Collect all the directories that are already managed by all existing Zeitwerk loaders.
|
116
|
-
managed_dirs = Zeitwerk::
|
102
|
+
managed_dirs = Zeitwerk::Loader.all_dirs.to_set
|
117
103
|
# We use a fresh loader to load the engine directories, so that we don't interfere with
|
118
104
|
# any of the existing loaders.
|
119
105
|
autoloader = Zeitwerk::Loader.new
|
@@ -132,7 +118,7 @@ module Tapioca
|
|
132
118
|
autoloader.setup
|
133
119
|
end
|
134
120
|
|
135
|
-
|
121
|
+
#: -> void
|
136
122
|
def load_engines_in_classic_mode
|
137
123
|
# This is code adapted from `Rails::Engine#eager_load!` in
|
138
124
|
# https://github.com/rails/rails/blob/d9e188dbab81b412f73dfb7763318d52f360af49/railties/lib/rails/engine.rb#L489-L495
|
@@ -150,14 +136,14 @@ module Tapioca
|
|
150
136
|
end
|
151
137
|
end
|
152
138
|
|
153
|
-
|
139
|
+
#: -> bool
|
154
140
|
def zeitwerk_mode?
|
155
141
|
Rails.respond_to?(:autoloaders) &&
|
156
142
|
Rails.autoloaders.respond_to?(:zeitwerk_enabled?) &&
|
157
143
|
Rails.autoloaders.zeitwerk_enabled?
|
158
144
|
end
|
159
145
|
|
160
|
-
|
146
|
+
#: { -> void } -> void
|
161
147
|
def with_rails_application(&blk)
|
162
148
|
# Store the current Rails.application object so that we can restore it
|
163
149
|
rails_application = T.unsafe(Rails.application)
|
@@ -174,7 +160,8 @@ module Tapioca
|
|
174
160
|
Rails.app_class = Rails.application = rails_application
|
175
161
|
end
|
176
162
|
|
177
|
-
|
163
|
+
# @without_runtime
|
164
|
+
#: -> Array[singleton(Rails::Engine)]
|
178
165
|
def engines
|
179
166
|
return [] unless defined?(Rails::Engine)
|
180
167
|
|
@@ -188,14 +175,14 @@ module Tapioca
|
|
188
175
|
.reject { |engine| gem_in_app_dir?(project_path, engine.config.root.to_path) }
|
189
176
|
end
|
190
177
|
|
191
|
-
|
178
|
+
#: (String path) -> void
|
192
179
|
def safe_require(path)
|
193
180
|
require path
|
194
181
|
rescue LoadError
|
195
182
|
nil
|
196
183
|
end
|
197
184
|
|
198
|
-
|
185
|
+
#: -> void
|
199
186
|
def eager_load_rails_app
|
200
187
|
application = Rails.application
|
201
188
|
|
@@ -216,7 +203,7 @@ module Tapioca
|
|
216
203
|
end
|
217
204
|
end
|
218
205
|
|
219
|
-
|
206
|
+
#: (String? file) -> void
|
220
207
|
def require_helper(file)
|
221
208
|
return unless file
|
222
209
|
|
@@ -230,7 +217,8 @@ module Tapioca
|
|
230
217
|
# The `eager_load_paths` method still exists, but doesn't return all paths anymore and causes Tapioca to miss some
|
231
218
|
# engine paths. The following commit is the change:
|
232
219
|
# https://github.com/rails/rails/commit/ebfca905db14020589c22e6937382e6f8f687664
|
233
|
-
|
220
|
+
# @without_runtime
|
221
|
+
#: (singleton(Rails::Engine) engine) -> Array[String]
|
234
222
|
def eager_load_paths(engine)
|
235
223
|
config = engine.config
|
236
224
|
|
@@ -5,7 +5,7 @@ module RBI
|
|
5
5
|
class Tree
|
6
6
|
extend T::Sig
|
7
7
|
|
8
|
-
|
8
|
+
#: (::Module constant) ?{ (Scope scope) -> void } -> Scope
|
9
9
|
def create_path(constant, &block)
|
10
10
|
constant_name = Tapioca::Runtime::Reflection.name_of(constant)
|
11
11
|
raise "given constant does not have a name" unless constant_name
|
@@ -21,72 +21,47 @@ module RBI
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
#: (String name) ?{ (Scope scope) -> void } -> Scope
|
25
25
|
def create_module(name, &block)
|
26
26
|
T.cast(create_node(RBI::Module.new(name)), RBI::Scope).tap do |node|
|
27
27
|
block&.call(node)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
params(
|
33
|
-
name: String,
|
34
|
-
superclass_name: T.nilable(String),
|
35
|
-
block: T.nilable(T.proc.params(scope: RBI::Scope).void),
|
36
|
-
).returns(Scope)
|
37
|
-
end
|
31
|
+
#: (String name, ?superclass_name: String?) ?{ (RBI::Scope scope) -> void } -> Scope
|
38
32
|
def create_class(name, superclass_name: nil, &block)
|
39
33
|
T.cast(create_node(RBI::Class.new(name, superclass_name: superclass_name)), RBI::Scope).tap do |node|
|
40
34
|
block&.call(node)
|
41
35
|
end
|
42
36
|
end
|
43
37
|
|
44
|
-
|
38
|
+
#: (String name, value: String) -> void
|
45
39
|
def create_constant(name, value:)
|
46
40
|
create_node(RBI::Const.new(name, value))
|
47
41
|
end
|
48
42
|
|
49
|
-
|
43
|
+
#: (String name) -> void
|
50
44
|
def create_include(name)
|
51
45
|
create_node(RBI::Include.new(name))
|
52
46
|
end
|
53
47
|
|
54
|
-
|
48
|
+
#: (String name) -> void
|
55
49
|
def create_extend(name)
|
56
50
|
create_node(RBI::Extend.new(name))
|
57
51
|
end
|
58
52
|
|
59
|
-
|
53
|
+
#: (String name) -> void
|
60
54
|
def create_mixes_in_class_methods(name)
|
61
55
|
create_node(RBI::MixesInClassMethods.new(name))
|
62
56
|
end
|
63
57
|
|
64
|
-
|
65
|
-
params(
|
66
|
-
name: String,
|
67
|
-
type: String,
|
68
|
-
variance: Symbol,
|
69
|
-
fixed: T.nilable(String),
|
70
|
-
upper: T.nilable(String),
|
71
|
-
lower: T.nilable(String),
|
72
|
-
).void
|
73
|
-
end
|
58
|
+
#: (String name, type: String, ?variance: Symbol, ?fixed: String?, ?upper: String?, ?lower: String?) -> void
|
74
59
|
def create_type_variable(name, type:, variance: :invariant, fixed: nil, upper: nil, lower: nil)
|
75
60
|
value = Tapioca::RBIHelper.serialize_type_variable(type, variance, fixed, upper, lower)
|
76
61
|
create_node(RBI::TypeMember.new(name, value))
|
77
62
|
end
|
78
63
|
|
79
|
-
|
80
|
-
params(
|
81
|
-
name: String,
|
82
|
-
parameters: T::Array[TypedParam],
|
83
|
-
return_type: T.nilable(String),
|
84
|
-
class_method: T::Boolean,
|
85
|
-
visibility: RBI::Visibility,
|
86
|
-
comments: T::Array[RBI::Comment],
|
87
|
-
block: T.nilable(T.proc.params(node: RBI::Method).void),
|
88
|
-
).void
|
89
|
-
end
|
64
|
+
#: (String name, ?parameters: Array[TypedParam], ?return_type: String?, ?class_method: bool, ?visibility: RBI::Visibility, ?comments: Array[RBI::Comment]) ?{ (RBI::Method node) -> void } -> void
|
90
65
|
def create_method(name, parameters: [], return_type: nil, class_method: false, visibility: RBI::Public.new,
|
91
66
|
comments: [], &block)
|
92
67
|
return unless Tapioca::RBIHelper.valid_method_name?(name)
|
@@ -114,12 +89,12 @@ module RBI
|
|
114
89
|
|
115
90
|
private
|
116
91
|
|
117
|
-
|
92
|
+
#: -> Hash[String, RBI::Node]
|
118
93
|
def nodes_cache
|
119
|
-
@nodes_cache ||=
|
94
|
+
@nodes_cache ||= {} #: Hash[String, Node]?
|
120
95
|
end
|
121
96
|
|
122
|
-
|
97
|
+
#: (RBI::Node node) -> RBI::Node
|
123
98
|
def create_node(node)
|
124
99
|
cached = nodes_cache[node.to_s]
|
125
100
|
return cached if cached
|
@@ -5,13 +5,7 @@ module Tapioca
|
|
5
5
|
class RBIFormatter < RBI::Formatter
|
6
6
|
extend T::Sig
|
7
7
|
|
8
|
-
|
9
|
-
params(
|
10
|
-
file: RBI::File,
|
11
|
-
command: String,
|
12
|
-
reason: T.nilable(String),
|
13
|
-
).void
|
14
|
-
end
|
8
|
+
#: (RBI::File file, String command, ?reason: String?) -> void
|
15
9
|
def write_header!(file, command, reason: nil)
|
16
10
|
file.comments << RBI::Comment.new("DO NOT EDIT MANUALLY")
|
17
11
|
file.comments << RBI::Comment.new("This is an autogenerated file for #{reason}.") unless reason.nil?
|
@@ -20,7 +14,7 @@ module Tapioca
|
|
20
14
|
file.comments << RBI::BlankLine.new
|
21
15
|
end
|
22
16
|
|
23
|
-
|
17
|
+
#: (RBI::File file) -> void
|
24
18
|
def write_empty_body_comment!(file)
|
25
19
|
file.comments << RBI::BlankLine.new unless file.comments.empty?
|
26
20
|
file.comments << RBI::Comment.new("THIS IS AN EMPTY RBI FILE.")
|
@@ -28,15 +22,12 @@ module Tapioca
|
|
28
22
|
end
|
29
23
|
end
|
30
24
|
|
31
|
-
DEFAULT_RBI_FORMATTER =
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
),
|
40
|
-
RBIFormatter,
|
41
|
-
)
|
25
|
+
DEFAULT_RBI_FORMATTER = RBIFormatter.new(
|
26
|
+
add_sig_templates: false,
|
27
|
+
group_nodes: true,
|
28
|
+
max_line_length: nil,
|
29
|
+
nest_singleton_methods: true,
|
30
|
+
nest_non_public_members: true,
|
31
|
+
sort_nodes: true,
|
32
|
+
) #: RBIFormatter
|
42
33
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "require-hooks/setup"
|
5
|
+
|
6
|
+
# This code rewrites RBS comments back into Sorbet's signatures as the files are being loaded.
|
7
|
+
# This will allow `sorbet-runtime` to wrap the methods as if they were originally written with the `sig{}` blocks.
|
8
|
+
# This will in turn allow Tapioca to use this signatures to generate typed RBI files.
|
9
|
+
|
10
|
+
begin
|
11
|
+
# When in a `bootsnap` environment, files are loaded from the cache and won't trigger the `source_transform` method.
|
12
|
+
# The `require-hooks` gem comes with a `bootsnap` mode that will disable the `bootsnap/compile_cache/iseq` caching.
|
13
|
+
# Sadly, we're way to early in the boot process to use it as bootsnap won't be loaded yet and the `require-hooks`
|
14
|
+
# setup won't pick it up.
|
15
|
+
#
|
16
|
+
# As a workaround, if we can preemptively require `bootsnap` and `bootsnap/compile_cache/iseq` we manually override
|
17
|
+
# the `load_iseq` method to disable the caching mechanism.
|
18
|
+
#
|
19
|
+
# This will make the Rails app load slower but allows us to trigger the RBS -> RBI source transform.
|
20
|
+
require "bootsnap"
|
21
|
+
require "bootsnap/compile_cache/iseq"
|
22
|
+
|
23
|
+
module Bootsnap
|
24
|
+
module CompileCache
|
25
|
+
module ISeq
|
26
|
+
module InstructionSequenceMixin
|
27
|
+
#: (String) -> RubyVM::InstructionSequence
|
28
|
+
def load_iseq(path)
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
# Bootsnap is not in the bundle, we don't need to do anything.
|
37
|
+
end
|
38
|
+
|
39
|
+
# We need to include `T::Sig` very early to make sure that the `sig` method is available since gems using RBS comments
|
40
|
+
# are unlikely to include `T::Sig` in their own classes.
|
41
|
+
Module.include(T::Sig)
|
42
|
+
|
43
|
+
# Trigger the source transformation for each Ruby file being loaded.
|
44
|
+
RequireHooks.source_transform(patterns: ["**/*.rb"]) do |path, source|
|
45
|
+
# The source is most likely nil since no `source_transform` hook was triggered before this one.
|
46
|
+
source ||= File.read(path)
|
47
|
+
|
48
|
+
# For performance reasons, we only rewrite files that use Sorbet.
|
49
|
+
if source =~ /^\s*#\s*typed: (ignore|false|true|strict|strong|__STDLIB_INTERNAL)/
|
50
|
+
Spoom::Sorbet::Translate.rbs_comments_to_sorbet_sigs(source, file: path)
|
51
|
+
end
|
52
|
+
rescue RBI::RBS::MethodTypeTranslator::Error
|
53
|
+
# If we can't translate the RBS comments back into Sorbet's signatures, we just skip the file.
|
54
|
+
source
|
55
|
+
end
|
data/lib/tapioca/repo_index.rb
CHANGED
@@ -9,12 +9,12 @@ module Tapioca
|
|
9
9
|
class << self
|
10
10
|
extend T::Sig
|
11
11
|
|
12
|
-
|
12
|
+
#: (String json) -> RepoIndex
|
13
13
|
def from_json(json)
|
14
14
|
RepoIndex.from_hash(JSON.parse(json))
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
#: (Hash[String, Hash[untyped, untyped]] hash) -> RepoIndex
|
18
18
|
def from_hash(hash)
|
19
19
|
hash.each_with_object(RepoIndex.new) do |(name, _), index|
|
20
20
|
index << name
|
@@ -22,22 +22,22 @@ module Tapioca
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
#: -> void
|
26
26
|
def initialize
|
27
|
-
@entries =
|
27
|
+
@entries = Set.new #: Set[String]
|
28
28
|
end
|
29
29
|
|
30
|
-
|
30
|
+
#: (String gem_name) -> void
|
31
31
|
def <<(gem_name)
|
32
32
|
@entries.add(gem_name)
|
33
33
|
end
|
34
34
|
|
35
|
-
|
35
|
+
#: -> T::Enumerable[String]
|
36
36
|
def gems
|
37
37
|
@entries.sort
|
38
38
|
end
|
39
39
|
|
40
|
-
|
40
|
+
#: (String gem_name) -> bool
|
41
41
|
def has_gem?(gem_name)
|
42
42
|
@entries.include?(gem_name)
|
43
43
|
end
|
@@ -10,7 +10,7 @@ module Tapioca
|
|
10
10
|
module AttachedClassOf
|
11
11
|
extend T::Sig
|
12
12
|
|
13
|
-
|
13
|
+
#: (Class singleton_class) -> Module?
|
14
14
|
def attached_class_of(singleton_class)
|
15
15
|
result = singleton_class.attached_object
|
16
16
|
Module === result ? result : nil
|
@@ -13,7 +13,7 @@ module Tapioca
|
|
13
13
|
|
14
14
|
requires_ancestor { Tapioca::Runtime::Reflection }
|
15
15
|
|
16
|
-
|
16
|
+
#: (Class singleton_class) -> Module?
|
17
17
|
def attached_class_of(singleton_class)
|
18
18
|
# https://stackoverflow.com/a/36622320/98634
|
19
19
|
result = ObjectSpace.each_object(singleton_class).find do |klass|
|