tapioca 0.11.6 → 0.11.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +62 -56
- data/lib/tapioca/bundler_ext/auto_require_hook.rb +69 -0
- data/lib/tapioca/cli.rb +10 -0
- data/lib/tapioca/commands/annotations.rb +6 -6
- data/lib/tapioca/commands/dsl.rb +6 -1
- data/lib/tapioca/commands/gem.rb +6 -1
- data/lib/tapioca/dsl/compiler.rb +3 -3
- data/lib/tapioca/dsl/compilers/aasm.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_model_attributes.rb +3 -1
- data/lib/tapioca/dsl/compilers/active_model_secure_password.rb +3 -1
- data/lib/tapioca/dsl/compilers/active_record_delegated_types.rb +2 -1
- data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +16 -7
- data/lib/tapioca/dsl/compilers/kredis.rb +3 -1
- data/lib/tapioca/dsl/compilers/protobuf.rb +19 -15
- data/lib/tapioca/gem/listeners/methods.rb +23 -2
- data/lib/tapioca/gem/listeners/sorbet_helpers.rb +3 -4
- data/lib/tapioca/gem/listeners/sorbet_type_variables.rb +20 -7
- data/lib/tapioca/gem/pipeline.rb +2 -2
- data/lib/tapioca/gemfile.rb +10 -48
- data/lib/tapioca/helpers/cli_helper.rb +2 -2
- data/lib/tapioca/helpers/rbi_files_helper.rb +1 -1
- data/lib/tapioca/helpers/sorbet_helper.rb +1 -0
- data/lib/tapioca/helpers/test/isolation.rb +7 -2
- data/lib/tapioca/internal.rb +1 -0
- data/lib/tapioca/loaders/dsl.rb +16 -5
- data/lib/tapioca/loaders/gem.rb +7 -3
- data/lib/tapioca/loaders/loader.rb +22 -6
- data/lib/tapioca/runtime/generic_type_registry.rb +1 -1
- data/lib/tapioca/runtime/reflection.rb +21 -5
- data/lib/tapioca/sorbet_ext/backcompat_patches.rb +24 -0
- data/lib/tapioca/sorbet_ext/generic_name_patch.rb +19 -0
- data/lib/tapioca/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e1d35be8426874dde08ba495772d5076d85167f24fa5cfa16b59f424ca3c820
|
4
|
+
data.tar.gz: ce7b53d0399658d9ecfdcda6e42f030b2316bfcd75c3c02ee018dbab966bce30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6dd882c66362cc1666f9e89a9634c38b3131fba7a10b0c5fabe19f5675e98adf308132b07c09b3f62d3035f4fc7ab05f36693de13cb74701324aee3933c43234
|
7
|
+
data.tar.gz: 74f78ab7a8d5f284b4a1efbcb7eaf098d609294b3c201e227890d3f1276a5c689ee528b5a610a8a4039eaf549c1e0655c71da04631d62b174a16baf23e312bf4
|
data/README.md
CHANGED
@@ -163,36 +163,38 @@ Usage:
|
|
163
163
|
tapioca gem [gem...]
|
164
164
|
|
165
165
|
Options:
|
166
|
-
--out, -o,
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
--pre, -b,
|
172
|
-
--post, -a,
|
173
|
-
|
174
|
-
-x,
|
175
|
-
--typed, -t, [--typed-overrides=gem:level [gem:level ...]]
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
-w,
|
185
|
-
|
186
|
-
|
187
|
-
--dsl-dir,
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
-e,
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
-
|
166
|
+
--out, -o, [--outdir=directory] # The output directory for generated gem RBI files
|
167
|
+
# Default: sorbet/rbi/gems
|
168
|
+
[--file-header], [--no-file-header] # Add a "This file is generated" header on top of each generated RBI file
|
169
|
+
# Default: true
|
170
|
+
[--all], [--no-all] # Regenerate RBI files for all gems
|
171
|
+
--pre, -b, [--prerequire=file] # A file to be required before Bundler.require is called
|
172
|
+
--post, -a, [--postrequire=file] # A file to be required after Bundler.require is called
|
173
|
+
# Default: sorbet/tapioca/require.rb
|
174
|
+
-x, [--exclude=gem [gem ...]] # Exclude the given gem(s) from RBI generation
|
175
|
+
--typed, -t, [--typed-overrides=gem:level [gem:level ...]] # Override for typed sigils for generated gem RBIs
|
176
|
+
# Default: {"activesupport"=>"false"}
|
177
|
+
[--verify], [--no-verify] # Verify RBIs are up-to-date
|
178
|
+
[--doc], [--no-doc] # Include YARD documentation from sources when generating RBIs. Warning: this might be slow
|
179
|
+
# Default: true
|
180
|
+
[--loc], [--no-loc] # Include comments with source location when generating RBIs
|
181
|
+
# Default: true
|
182
|
+
[--exported-gem-rbis], [--no-exported-gem-rbis] # Include RBIs found in the `rbi/` directory of the gem
|
183
|
+
# Default: true
|
184
|
+
-w, [--workers=N] # Number of parallel workers to use when generating RBIs (default: auto)
|
185
|
+
[--auto-strictness], [--no-auto-strictness] # Autocorrect strictness in gem RBIs in case of conflict with the DSL RBIs
|
186
|
+
# Default: true
|
187
|
+
--dsl-dir, [--dsl-dir=directory] # The DSL directory used to correct gems strictnesses
|
188
|
+
# Default: sorbet/rbi/dsl
|
189
|
+
[--rbi-max-line-length=N] # Set the max line length of generated RBIs. Signatures longer than the max line length will be wrapped
|
190
|
+
# Default: 120
|
191
|
+
-e, [--environment=ENVIRONMENT] # The Rack/Rails environment to use when generating RBIs
|
192
|
+
# Default: development
|
193
|
+
[--halt-upon-load-error], [--no-halt-upon-load-error] # Halt upon a load error while loading the Rails application
|
194
|
+
# Default: true
|
195
|
+
-c, [--config=<config file path>] # Path to the Tapioca configuration file
|
196
|
+
# Default: sorbet/tapioca/config.yml
|
197
|
+
-V, [--verbose], [--no-verbose] # Verbose output for debugging purposes
|
196
198
|
|
197
199
|
generate RBIs from gems
|
198
200
|
```
|
@@ -347,16 +349,16 @@ Usage:
|
|
347
349
|
tapioca annotations
|
348
350
|
|
349
351
|
Options:
|
350
|
-
|
352
|
+
[--sources=one two three] # URIs of the sources to pull gem RBI annotations from
|
351
353
|
# Default: ["https://raw.githubusercontent.com/Shopify/rbi-central/main"]
|
352
|
-
|
354
|
+
[--netrc], [--no-netrc] # Use .netrc to authenticate to private sources
|
353
355
|
# Default: true
|
354
|
-
|
355
|
-
|
356
|
+
[--netrc-file=NETRC_FILE] # Path to .netrc file
|
357
|
+
[--auth=AUTH] # HTTP authorization header for private sources
|
356
358
|
--typed, -t, [--typed-overrides=gem:level [gem:level ...]] # Override for typed sigils for pulled annotations
|
357
|
-
-c,
|
359
|
+
-c, [--config=<config file path>] # Path to the Tapioca configuration file
|
358
360
|
# Default: sorbet/tapioca/config.yml
|
359
|
-
-V,
|
361
|
+
-V, [--verbose], [--no-verbose] # Verbose output for debugging purposes
|
360
362
|
|
361
363
|
Pull gem RBI annotations from remote sources
|
362
364
|
```
|
@@ -458,26 +460,28 @@ Usage:
|
|
458
460
|
tapioca dsl [constant...]
|
459
461
|
|
460
462
|
Options:
|
461
|
-
--out, -o, [--outdir=directory]
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
-q,
|
469
|
-
-w,
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
-e,
|
474
|
-
|
475
|
-
-l,
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
-
|
463
|
+
--out, -o, [--outdir=directory] # The output directory for generated DSL RBI files
|
464
|
+
# Default: sorbet/rbi/dsl
|
465
|
+
[--file-header], [--no-file-header] # Add a "This file is generated" header on top of each generated RBI file
|
466
|
+
# Default: true
|
467
|
+
[--only=compiler [compiler ...]] # Only run supplied DSL compiler(s)
|
468
|
+
[--exclude=compiler [compiler ...]] # Exclude supplied DSL compiler(s)
|
469
|
+
[--verify], [--no-verify] # Verifies RBIs are up-to-date
|
470
|
+
-q, [--quiet], [--no-quiet] # Suppresses file creation output
|
471
|
+
-w, [--workers=N] # Number of parallel workers to use when generating RBIs (default: 2)
|
472
|
+
# Default: 2
|
473
|
+
[--rbi-max-line-length=N] # Set the max line length of generated RBIs. Signatures longer than the max line length will be wrapped
|
474
|
+
# Default: 120
|
475
|
+
-e, [--environment=ENVIRONMENT] # The Rack/Rails environment to use when generating RBIs
|
476
|
+
# Default: development
|
477
|
+
-l, [--list-compilers], [--no-list-compilers] # List all loaded compilers
|
478
|
+
[--app-root=APP_ROOT] # The path to the Rails application
|
479
|
+
# Default: .
|
480
|
+
[--halt-upon-load-error], [--no-halt-upon-load-error] # Halt upon a load error while loading the Rails application
|
481
|
+
# Default: true
|
482
|
+
-c, [--config=<config file path>] # Path to the Tapioca configuration file
|
483
|
+
# Default: sorbet/tapioca/config.yml
|
484
|
+
-V, [--verbose], [--no-verbose] # Verbose output for debugging purposes
|
481
485
|
|
482
486
|
generate RBIs for dynamic methods
|
483
487
|
```
|
@@ -827,6 +831,7 @@ dsl:
|
|
827
831
|
environment: development
|
828
832
|
list_compilers: false
|
829
833
|
app_root: "."
|
834
|
+
halt_upon_load_error: true
|
830
835
|
gem:
|
831
836
|
outdir: sorbet/rbi/gems
|
832
837
|
file_header: true
|
@@ -845,6 +850,7 @@ gem:
|
|
845
850
|
dsl_dir: sorbet/rbi/dsl
|
846
851
|
rbi_max_line_length: 120
|
847
852
|
environment: development
|
853
|
+
halt_upon_load_error: true
|
848
854
|
check_shims:
|
849
855
|
gem_rbi_dir: sorbet/rbi/gems
|
850
856
|
dsl_rbi_dir: sorbet/rbi/dsl
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Tapioca
|
5
|
+
module BundlerExt
|
6
|
+
# This is a module that gets prepended to `Bundler::Dependency` and
|
7
|
+
# makes sure even gems marked as `require: false` are required during
|
8
|
+
# `Bundler.require`.
|
9
|
+
module AutoRequireHook
|
10
|
+
extend T::Sig
|
11
|
+
extend T::Helpers
|
12
|
+
|
13
|
+
requires_ancestor { ::Bundler::Dependency }
|
14
|
+
|
15
|
+
@exclude = T.let([], T::Array[String])
|
16
|
+
@enabled = T.let(false, T::Boolean)
|
17
|
+
|
18
|
+
class << self
|
19
|
+
extend T::Sig
|
20
|
+
|
21
|
+
sig { params(name: T.untyped).returns(T::Boolean) }
|
22
|
+
def excluded?(name)
|
23
|
+
@exclude.include?(name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def enabled?
|
27
|
+
@enabled
|
28
|
+
end
|
29
|
+
|
30
|
+
sig do
|
31
|
+
type_parameters(:Result).params(
|
32
|
+
exclude: T::Array[String],
|
33
|
+
blk: T.proc.returns(T.type_parameter(:Result)),
|
34
|
+
).returns(T.type_parameter(:Result))
|
35
|
+
end
|
36
|
+
def override_require_false(exclude:, &blk)
|
37
|
+
@enabled = true
|
38
|
+
@exclude = exclude
|
39
|
+
blk.call
|
40
|
+
ensure
|
41
|
+
@enabled = false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
sig { returns(T.untyped).checked(:never) }
|
46
|
+
def autorequire
|
47
|
+
value = super
|
48
|
+
|
49
|
+
# If autorequire is not enabled, we don't want to force require gems
|
50
|
+
return value unless AutoRequireHook.enabled?
|
51
|
+
|
52
|
+
# If the gem is excluded, we don't want to force require it, in case
|
53
|
+
# it has side-effects users don't want. For example, `fakefs` gem, if
|
54
|
+
# loaded, takes over filesystem operations.
|
55
|
+
return value if AutoRequireHook.excluded?(name)
|
56
|
+
|
57
|
+
# If a gem is marked as `require: false`, then its `autorequire`
|
58
|
+
# value will be `[]`. But, we want those gems to be loaded for our
|
59
|
+
# purposes as well, so we return `nil` in those cases, instead, which
|
60
|
+
# means `require: true`.
|
61
|
+
return if value == []
|
62
|
+
|
63
|
+
value
|
64
|
+
end
|
65
|
+
|
66
|
+
::Bundler::Dependency.prepend(self)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/tapioca/cli.rb
CHANGED
@@ -130,6 +130,10 @@ module Tapioca
|
|
130
130
|
type: :string,
|
131
131
|
desc: "The path to the Rails application",
|
132
132
|
default: "."
|
133
|
+
option :halt_upon_load_error,
|
134
|
+
type: :boolean,
|
135
|
+
desc: "Halt upon a load error while loading the Rails application",
|
136
|
+
default: true
|
133
137
|
def dsl(*constant_or_paths)
|
134
138
|
set_environment(options)
|
135
139
|
|
@@ -150,6 +154,7 @@ module Tapioca
|
|
150
154
|
number_of_workers: options[:workers],
|
151
155
|
rbi_formatter: rbi_formatter(options),
|
152
156
|
app_root: options[:app_root],
|
157
|
+
halt_upon_load_error: options[:halt_upon_load_error],
|
153
158
|
)
|
154
159
|
|
155
160
|
Tapioca.silence_warnings do
|
@@ -235,6 +240,10 @@ module Tapioca
|
|
235
240
|
type: :string,
|
236
241
|
desc: "The Rack/Rails environment to use when generating RBIs",
|
237
242
|
default: DEFAULT_ENVIRONMENT
|
243
|
+
option :halt_upon_load_error,
|
244
|
+
type: :boolean,
|
245
|
+
desc: "Halt upon a load error while loading the Rails application",
|
246
|
+
default: true
|
238
247
|
def gem(*gems)
|
239
248
|
Tapioca.silence_warnings do
|
240
249
|
set_environment(options)
|
@@ -257,6 +266,7 @@ module Tapioca
|
|
257
266
|
auto_strictness: options[:auto_strictness],
|
258
267
|
dsl_dir: options[:dsl_dir],
|
259
268
|
rbi_formatter: rbi_formatter(options),
|
269
|
+
halt_upon_load_error: options[:halt_upon_load_error],
|
260
270
|
)
|
261
271
|
|
262
272
|
raise MalformattedArgumentError, "Options '--all' and '--verify' are mutually exclusive" if all && verify
|
@@ -98,7 +98,7 @@ module Tapioca
|
|
98
98
|
def fetch_index(repo_uri, repo_number:)
|
99
99
|
say("Retrieving index from central repository#{repo_number ? " ##{repo_number}" : ""}... ", [:blue, :bold])
|
100
100
|
content = fetch_file(repo_uri, CENTRAL_REPO_INDEX_PATH)
|
101
|
-
return
|
101
|
+
return unless content
|
102
102
|
|
103
103
|
index = RepoIndex.from_json(content)
|
104
104
|
say("Done", :green)
|
@@ -221,7 +221,7 @@ module Tapioca
|
|
221
221
|
|
222
222
|
sig { params(gem_name: String, contents: T::Array[String]).returns(T.nilable(String)) }
|
223
223
|
def merge_files(gem_name, contents)
|
224
|
-
return
|
224
|
+
return if contents.empty?
|
225
225
|
|
226
226
|
rewriter = RBI::Rewriters::Merge.new(keep: RBI::Rewriters::Merge::Keep::NONE)
|
227
227
|
|
@@ -260,16 +260,16 @@ module Tapioca
|
|
260
260
|
|
261
261
|
sig { params(repo_uri: String).returns(T.nilable(String)) }
|
262
262
|
def token_for(repo_uri)
|
263
|
-
return
|
263
|
+
return unless @netrc_info
|
264
264
|
|
265
265
|
host = URI(repo_uri).host
|
266
|
-
return
|
266
|
+
return unless host
|
267
267
|
|
268
268
|
creds = @netrc_info[host]
|
269
|
-
return
|
269
|
+
return unless creds
|
270
270
|
|
271
271
|
token = creds.to_a.last
|
272
|
-
return
|
272
|
+
return unless token
|
273
273
|
|
274
274
|
"token #{token}"
|
275
275
|
end
|
data/lib/tapioca/commands/dsl.rb
CHANGED
@@ -24,6 +24,7 @@ module Tapioca
|
|
24
24
|
gem_dir: String,
|
25
25
|
rbi_formatter: RBIFormatter,
|
26
26
|
app_root: String,
|
27
|
+
halt_upon_load_error: T::Boolean,
|
27
28
|
).void
|
28
29
|
end
|
29
30
|
def initialize(
|
@@ -41,7 +42,8 @@ module Tapioca
|
|
41
42
|
auto_strictness: true,
|
42
43
|
gem_dir: DEFAULT_GEM_DIR,
|
43
44
|
rbi_formatter: DEFAULT_RBI_FORMATTER,
|
44
|
-
app_root: "."
|
45
|
+
app_root: ".",
|
46
|
+
halt_upon_load_error: true
|
45
47
|
)
|
46
48
|
@requested_constants = requested_constants
|
47
49
|
@requested_paths = requested_paths
|
@@ -58,6 +60,7 @@ module Tapioca
|
|
58
60
|
@gem_dir = gem_dir
|
59
61
|
@rbi_formatter = rbi_formatter
|
60
62
|
@app_root = app_root
|
63
|
+
@halt_upon_load_error = halt_upon_load_error
|
61
64
|
|
62
65
|
super()
|
63
66
|
end
|
@@ -68,6 +71,7 @@ module Tapioca
|
|
68
71
|
tapioca_path: @tapioca_path,
|
69
72
|
eager_load: @requested_constants.empty? && @requested_paths.empty?,
|
70
73
|
app_root: @app_root,
|
74
|
+
halt_upon_load_error: @halt_upon_load_error,
|
71
75
|
)
|
72
76
|
|
73
77
|
pipeline = create_pipeline
|
@@ -95,6 +99,7 @@ module Tapioca
|
|
95
99
|
tapioca_path: @tapioca_path,
|
96
100
|
eager_load: @requested_constants.empty? && @requested_paths.empty?,
|
97
101
|
app_root: @app_root,
|
102
|
+
halt_upon_load_error: @halt_upon_load_error,
|
98
103
|
)
|
99
104
|
|
100
105
|
if @should_verify
|
data/lib/tapioca/commands/gem.rb
CHANGED
@@ -23,6 +23,7 @@ module Tapioca
|
|
23
23
|
auto_strictness: T::Boolean,
|
24
24
|
dsl_dir: String,
|
25
25
|
rbi_formatter: RBIFormatter,
|
26
|
+
halt_upon_load_error: T::Boolean,
|
26
27
|
).void
|
27
28
|
end
|
28
29
|
def initialize(
|
@@ -39,7 +40,8 @@ module Tapioca
|
|
39
40
|
number_of_workers: nil,
|
40
41
|
auto_strictness: true,
|
41
42
|
dsl_dir: DEFAULT_DSL_DIR,
|
42
|
-
rbi_formatter: DEFAULT_RBI_FORMATTER
|
43
|
+
rbi_formatter: DEFAULT_RBI_FORMATTER,
|
44
|
+
halt_upon_load_error: true
|
43
45
|
)
|
44
46
|
@gem_names = gem_names
|
45
47
|
@exclude = exclude
|
@@ -61,6 +63,7 @@ module Tapioca
|
|
61
63
|
@include_doc = T.let(include_doc, T::Boolean)
|
62
64
|
@include_loc = T.let(include_loc, T::Boolean)
|
63
65
|
@include_exported_rbis = include_exported_rbis
|
66
|
+
@halt_upon_load_error = halt_upon_load_error
|
64
67
|
end
|
65
68
|
|
66
69
|
sig { override.void }
|
@@ -70,6 +73,7 @@ module Tapioca
|
|
70
73
|
prerequire: @prerequire,
|
71
74
|
postrequire: @postrequire,
|
72
75
|
default_command: default_command(:require),
|
76
|
+
halt_upon_load_error: @halt_upon_load_error,
|
73
77
|
)
|
74
78
|
|
75
79
|
gem_queue = gems_to_generate(@gem_names).reject { |gem| @exclude.include?(gem.name) }
|
@@ -245,6 +249,7 @@ module Tapioca
|
|
245
249
|
prerequire: @prerequire,
|
246
250
|
postrequire: @postrequire,
|
247
251
|
default_command: default_command(:require),
|
252
|
+
halt_upon_load_error: @halt_upon_load_error,
|
248
253
|
)
|
249
254
|
|
250
255
|
Executor.new(gems, number_of_workers: @number_of_workers).run_in_parallel do |gem_name|
|
data/lib/tapioca/dsl/compiler.rb
CHANGED
@@ -43,10 +43,10 @@ module Tapioca
|
|
43
43
|
|
44
44
|
private
|
45
45
|
|
46
|
-
sig { returns(T::Enumerable[Class]) }
|
46
|
+
sig { returns(T::Enumerable[T::Class[T.anything]]) }
|
47
47
|
def all_classes
|
48
|
-
@all_classes = T.let(@all_classes, T.nilable(T::Enumerable[Class]))
|
49
|
-
@all_classes ||= T.cast(ObjectSpace.each_object(Class), T::Enumerable[Class]).each
|
48
|
+
@all_classes = T.let(@all_classes, T.nilable(T::Enumerable[T::Class[T.anything]]))
|
49
|
+
@all_classes ||= T.cast(ObjectSpace.each_object(Class), T::Enumerable[T::Class[T.anything]]).each
|
50
50
|
end
|
51
51
|
|
52
52
|
sig { returns(T::Enumerable[Module]) }
|
@@ -39,7 +39,9 @@ module Tapioca
|
|
39
39
|
class ActiveModelAttributes < Compiler
|
40
40
|
extend T::Sig
|
41
41
|
|
42
|
-
ConstantType = type_member
|
42
|
+
ConstantType = type_member do
|
43
|
+
{ fixed: T.all(T::Class[::ActiveModel::Attributes], ::ActiveModel::Attributes::ClassMethods) }
|
44
|
+
end
|
43
45
|
|
44
46
|
sig { override.void }
|
45
47
|
def decorate
|
@@ -60,7 +60,9 @@ module Tapioca
|
|
60
60
|
class ActiveModelSecurePassword < Compiler
|
61
61
|
extend T::Sig
|
62
62
|
|
63
|
-
ConstantType = type_member
|
63
|
+
ConstantType = type_member do
|
64
|
+
{ fixed: T.all(T::Class[::ActiveModel::SecurePassword], ::ActiveModel::SecurePassword::ClassMethods) }
|
65
|
+
end
|
64
66
|
|
65
67
|
sig { override.void }
|
66
68
|
def decorate
|
@@ -110,10 +110,11 @@ module Tapioca
|
|
110
110
|
return_type: "ActiveSupport::StringInquirer",
|
111
111
|
)
|
112
112
|
|
113
|
+
return_type = sorbet_supports?(:generic_class) ? "T::Class[T.anything]" : "Class"
|
113
114
|
mod.create_method(
|
114
115
|
"#{role}_class",
|
115
116
|
parameters: [],
|
116
|
-
return_type:
|
117
|
+
return_type: return_type,
|
117
118
|
)
|
118
119
|
|
119
120
|
mod.create_method(
|
@@ -70,15 +70,24 @@ module Tapioca
|
|
70
70
|
|
71
71
|
private
|
72
72
|
|
73
|
-
sig { returns(Class) }
|
73
|
+
sig { returns(T::Class[ActiveRecord::TestFixtures]) }
|
74
74
|
def fixture_loader
|
75
75
|
@fixture_loader ||= T.let(
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
76
|
+
T.cast(
|
77
|
+
Class.new do
|
78
|
+
T.unsafe(self).include(ActiveRecord::TestFixtures)
|
79
|
+
|
80
|
+
T.unsafe(self).fixture_path = Rails.root.join("test", "fixtures")
|
81
|
+
# https://github.com/rails/rails/blob/7c70791470fc517deb7c640bead9f1b47efb5539/activerecord/lib/active_record/test_fixtures.rb#L46
|
82
|
+
singleton_class.define_method(:file_fixture_path) do
|
83
|
+
Rails.root.join("test", "fixtures", "files")
|
84
|
+
end
|
85
|
+
|
86
|
+
T.unsafe(self).fixtures(:all)
|
87
|
+
end,
|
88
|
+
T::Class[ActiveRecord::TestFixtures],
|
89
|
+
),
|
90
|
+
T.nilable(T::Class[ActiveRecord::TestFixtures]),
|
82
91
|
)
|
83
92
|
end
|
84
93
|
|
@@ -70,7 +70,9 @@ module Tapioca
|
|
70
70
|
class Kredis < Compiler
|
71
71
|
extend T::Sig
|
72
72
|
|
73
|
-
ConstantType = type_member
|
73
|
+
ConstantType = type_member do
|
74
|
+
{ fixed: T.all(T::Class[::Kredis::Attributes], ::Kredis::Attributes::ClassMethods, Extensions::Kredis) }
|
75
|
+
end
|
74
76
|
|
75
77
|
sig { override.void }
|
76
78
|
def decorate
|
@@ -78,7 +78,7 @@ module Tapioca
|
|
78
78
|
|
79
79
|
extend T::Sig
|
80
80
|
|
81
|
-
ConstantType = type_member { { fixed:
|
81
|
+
ConstantType = type_member { { fixed: T::Class[T.anything] } }
|
82
82
|
|
83
83
|
FIELD_RE = /^[a-z_][a-zA-Z0-9_]*$/
|
84
84
|
|
@@ -206,7 +206,7 @@ module Tapioca
|
|
206
206
|
# > field, even if it was not defined in the enum.
|
207
207
|
"T.any(Symbol, Integer)"
|
208
208
|
when :message
|
209
|
-
descriptor.subtype.msgclass.name
|
209
|
+
descriptor.subtype.msgclass.name || "T.untyped"
|
210
210
|
when :int32, :int64, :uint32, :uint64
|
211
211
|
"Integer"
|
212
212
|
when :double, :float
|
@@ -225,14 +225,24 @@ module Tapioca
|
|
225
225
|
descriptor.label == :optional && descriptor.type == :message
|
226
226
|
end
|
227
227
|
|
228
|
+
sig { params(descriptor: Google::Protobuf::FieldDescriptor).returns(T::Boolean) }
|
229
|
+
def map_type?(descriptor)
|
230
|
+
# Defensively make sure that we are dealing with a repeated field
|
231
|
+
return false unless descriptor.label == :repeated
|
232
|
+
|
233
|
+
# Try to create a new instance with the field that maps to the descriptor name
|
234
|
+
# being assinged a hash value. If this goes through, then it's a map type.
|
235
|
+
constant.new(**{ descriptor.name => {} })
|
236
|
+
true
|
237
|
+
rescue ArgumentError
|
238
|
+
# This means the descriptor is not a map type
|
239
|
+
false
|
240
|
+
end
|
241
|
+
|
228
242
|
sig { params(descriptor: Google::Protobuf::FieldDescriptor).returns(Field) }
|
229
243
|
def field_of(descriptor)
|
230
244
|
if descriptor.label == :repeated
|
231
|
-
|
232
|
-
# how Google names map entries.
|
233
|
-
# https://github.com/protocolbuffers/protobuf/blob/f82e26/ruby/ext/google/protobuf_c/defs.c#L1963-L1966
|
234
|
-
if descriptor.submsg_name.to_s.end_with?("_MapEntry_#{descriptor.name}") ||
|
235
|
-
descriptor.submsg_name.to_s.end_with?("FieldsEntry")
|
245
|
+
if map_type?(descriptor)
|
236
246
|
key = descriptor.subtype.lookup("key")
|
237
247
|
value = descriptor.subtype.lookup("value")
|
238
248
|
|
@@ -240,27 +250,21 @@ module Tapioca
|
|
240
250
|
value_type = type_of(value)
|
241
251
|
type = "Google::Protobuf::Map[#{key_type}, #{value_type}]"
|
242
252
|
|
243
|
-
default_args = [key.type.inspect, value.type.inspect]
|
244
|
-
default_args << value_type if [:enum, :message].include?(value.type)
|
245
|
-
|
246
253
|
Field.new(
|
247
254
|
name: descriptor.name,
|
248
255
|
type: type,
|
249
256
|
init_type: "T.nilable(T.any(#{type}, T::Hash[#{key_type}, #{value_type}]))",
|
250
|
-
default: "
|
257
|
+
default: "T.unsafe(nil)",
|
251
258
|
)
|
252
259
|
else
|
253
260
|
elem_type = type_of(descriptor)
|
254
261
|
type = "Google::Protobuf::RepeatedField[#{elem_type}]"
|
255
262
|
|
256
|
-
default_args = [descriptor.type.inspect]
|
257
|
-
default_args << elem_type if [:enum, :message].include?(descriptor.type)
|
258
|
-
|
259
263
|
Field.new(
|
260
264
|
name: descriptor.name,
|
261
265
|
type: type,
|
262
266
|
init_type: "T.nilable(T.any(#{type}, T::Array[#{elem_type}]))",
|
263
|
-
default: "
|
267
|
+
default: "T.unsafe(nil)",
|
264
268
|
)
|
265
269
|
end
|
266
270
|
else
|
@@ -20,7 +20,7 @@ module Tapioca
|
|
20
20
|
|
21
21
|
compile_method(node, symbol, constant, initialize_method_for(constant))
|
22
22
|
compile_directly_owned_methods(node, symbol, constant)
|
23
|
-
compile_directly_owned_methods(node, symbol, singleton_class_of(constant))
|
23
|
+
compile_directly_owned_methods(node, symbol, singleton_class_of(constant), attached_class: constant)
|
24
24
|
end
|
25
25
|
|
26
26
|
sig do
|
@@ -29,14 +29,22 @@ module Tapioca
|
|
29
29
|
module_name: String,
|
30
30
|
mod: Module,
|
31
31
|
for_visibility: T::Array[Symbol],
|
32
|
+
attached_class: T.nilable(Module),
|
32
33
|
).void
|
33
34
|
end
|
34
|
-
def compile_directly_owned_methods(
|
35
|
+
def compile_directly_owned_methods(
|
36
|
+
tree,
|
37
|
+
module_name,
|
38
|
+
mod,
|
39
|
+
for_visibility = [:public, :protected, :private],
|
40
|
+
attached_class: nil
|
41
|
+
)
|
35
42
|
method_names_by_visibility(mod)
|
36
43
|
.delete_if { |visibility, _method_list| !for_visibility.include?(visibility) }
|
37
44
|
.each do |visibility, method_list|
|
38
45
|
method_list.sort!.map do |name|
|
39
46
|
next if name == :initialize
|
47
|
+
next if method_new_in_abstract_class?(attached_class, name)
|
40
48
|
|
41
49
|
vis = case visibility
|
42
50
|
when :protected
|
@@ -180,6 +188,19 @@ module Tapioca
|
|
180
188
|
.include?(method_name.gsub(/=$/, "").to_sym)
|
181
189
|
end
|
182
190
|
|
191
|
+
sig do
|
192
|
+
params(
|
193
|
+
attached_class: T.nilable(Module),
|
194
|
+
method_name: Symbol,
|
195
|
+
).returns(T.nilable(T::Boolean))
|
196
|
+
end
|
197
|
+
def method_new_in_abstract_class?(attached_class, method_name)
|
198
|
+
attached_class &&
|
199
|
+
method_name == :new &&
|
200
|
+
!!abstract_type_of(attached_class) &&
|
201
|
+
Class === attached_class.singleton_class
|
202
|
+
end
|
203
|
+
|
183
204
|
sig { params(constant: Module).returns(T.nilable(UnboundMethod)) }
|
184
205
|
def initialize_method_for(constant)
|
185
206
|
constant.instance_method(:initialize)
|
@@ -16,12 +16,11 @@ module Tapioca
|
|
16
16
|
constant = event.constant
|
17
17
|
node = event.node
|
18
18
|
|
19
|
-
abstract_type =
|
20
|
-
T::Private::Abstract::Data.get(singleton_class_of(constant), :abstract_type)
|
19
|
+
abstract_type = abstract_type_of(constant)
|
21
20
|
|
22
21
|
node << RBI::Helper.new(abstract_type.to_s) if abstract_type
|
23
|
-
node << RBI::Helper.new("final") if
|
24
|
-
node << RBI::Helper.new("sealed") if
|
22
|
+
node << RBI::Helper.new("final") if final_module?(constant)
|
23
|
+
node << RBI::Helper.new("sealed") if sealed_module?(constant)
|
25
24
|
end
|
26
25
|
|
27
26
|
sig { override.params(event: NodeAdded).returns(T::Boolean) }
|
@@ -31,14 +31,14 @@ module Tapioca
|
|
31
31
|
|
32
32
|
# Map each type variable to its string representation.
|
33
33
|
#
|
34
|
-
# Each entry of `type_variables` maps a Module to a String,
|
35
|
-
#
|
36
|
-
# defined in the source code.
|
37
|
-
type_variable_declarations = type_variables.
|
38
|
-
|
39
|
-
next unless
|
34
|
+
# Each entry of `type_variables` maps a Module to a String, or
|
35
|
+
# is a `has_attached_class!` declaration, and the order they are inserted
|
36
|
+
# into the hash is the order they should be defined in the source code.
|
37
|
+
type_variable_declarations = type_variables.filter_map do |type_variable|
|
38
|
+
node = node_from_type_variable(type_variable)
|
39
|
+
next unless node
|
40
40
|
|
41
|
-
tree <<
|
41
|
+
tree << node
|
42
42
|
end
|
43
43
|
|
44
44
|
return if type_variable_declarations.empty?
|
@@ -46,6 +46,19 @@ module Tapioca
|
|
46
46
|
tree << RBI::Extend.new("T::Generic")
|
47
47
|
end
|
48
48
|
|
49
|
+
sig { params(type_variable: Tapioca::TypeVariableModule).returns(T.nilable(RBI::Node)) }
|
50
|
+
def node_from_type_variable(type_variable)
|
51
|
+
case type_variable.type
|
52
|
+
when Tapioca::TypeVariableModule::Type::HasAttachedClass
|
53
|
+
RBI::Send.new(type_variable.serialize)
|
54
|
+
else
|
55
|
+
type_variable_name = type_variable.name
|
56
|
+
return unless type_variable_name
|
57
|
+
|
58
|
+
RBI::TypeMember.new(type_variable_name, type_variable.serialize)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
49
62
|
sig { override.params(event: NodeAdded).returns(T::Boolean) }
|
50
63
|
def ignore?(event)
|
51
64
|
event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
|
data/lib/tapioca/gem/pipeline.rb
CHANGED
@@ -304,9 +304,9 @@ module Tapioca
|
|
304
304
|
@root << scope
|
305
305
|
end
|
306
306
|
|
307
|
-
sig { params(constant: Class).returns(T.nilable(String)) }
|
307
|
+
sig { params(constant: T::Class[T.anything]).returns(T.nilable(String)) }
|
308
308
|
def compile_superclass(constant)
|
309
|
-
superclass = T.let(nil, T.nilable(Class)) # rubocop:disable Lint/UselessAssignment
|
309
|
+
superclass = T.let(nil, T.nilable(T::Class[T.anything])) # rubocop:disable Lint/UselessAssignment
|
310
310
|
|
311
311
|
while (superclass = superclass_of(constant))
|
312
312
|
constant_name = name_of(constant)
|
data/lib/tapioca/gemfile.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "tapioca/bundler_ext/auto_require_hook"
|
5
|
+
|
4
6
|
module Tapioca
|
5
7
|
class Gemfile
|
6
8
|
extend(T::Sig)
|
@@ -12,50 +14,6 @@ module Tapioca
|
|
12
14
|
)
|
13
15
|
end
|
14
16
|
|
15
|
-
# This is a module that gets prepended to `Bundler::Dependency` and
|
16
|
-
# makes sure even gems marked as `require: false` are required during
|
17
|
-
# `Bundler.require`.
|
18
|
-
module AutoRequireHook
|
19
|
-
extend T::Sig
|
20
|
-
extend T::Helpers
|
21
|
-
|
22
|
-
requires_ancestor { ::Bundler::Dependency }
|
23
|
-
|
24
|
-
@exclude = T.let([], T::Array[String])
|
25
|
-
|
26
|
-
class << self
|
27
|
-
extend T::Sig
|
28
|
-
|
29
|
-
sig { params(exclude: T::Array[String]).returns(T::Array[String]) }
|
30
|
-
attr_writer :exclude
|
31
|
-
|
32
|
-
sig { params(name: T.untyped).returns(T::Boolean) }
|
33
|
-
def excluded?(name)
|
34
|
-
@exclude.include?(name)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
sig { returns(T.untyped).checked(:never) }
|
39
|
-
def autorequire
|
40
|
-
value = super
|
41
|
-
|
42
|
-
# If the gem is excluded, we don't want to force require it, in case
|
43
|
-
# it has side-effects users don't want. For example, `fakefs` gem, if
|
44
|
-
# loaded, takes over filesystem operations.
|
45
|
-
return value if AutoRequireHook.excluded?(name)
|
46
|
-
|
47
|
-
# If a gem is marked as `require: false`, then its `autorequire`
|
48
|
-
# value will be `[]`. But, we want those gems to be loaded for our
|
49
|
-
# purposes as well, so we return `nil` in those cases, instead, which
|
50
|
-
# means `require: true`.
|
51
|
-
return nil if value == []
|
52
|
-
|
53
|
-
value
|
54
|
-
end
|
55
|
-
|
56
|
-
::Bundler::Dependency.prepend(self)
|
57
|
-
end
|
58
|
-
|
59
17
|
sig { returns(Bundler::Definition) }
|
60
18
|
attr_reader(:definition)
|
61
19
|
|
@@ -65,13 +23,15 @@ module Tapioca
|
|
65
23
|
sig { returns(T::Array[String]) }
|
66
24
|
attr_reader(:missing_specs)
|
67
25
|
|
68
|
-
sig { params(
|
69
|
-
def initialize(
|
70
|
-
AutoRequireHook.exclude = exclude
|
26
|
+
sig { params(excluded_gems: T::Array[String]).void }
|
27
|
+
def initialize(excluded_gems)
|
71
28
|
@gemfile = T.let(File.new(Bundler.default_gemfile), File)
|
72
29
|
@lockfile = T.let(File.new(Bundler.default_lockfile), File)
|
73
30
|
@definition = T.let(Bundler::Dsl.evaluate(gemfile, lockfile, {}), Bundler::Definition)
|
31
|
+
@excluded_gems = excluded_gems
|
32
|
+
|
74
33
|
dependencies, missing_specs = load_dependencies
|
34
|
+
|
75
35
|
@dependencies = T.let(dependencies, T::Array[GemSpec])
|
76
36
|
@missing_specs = T.let(missing_specs, T::Array[String])
|
77
37
|
end
|
@@ -83,7 +43,9 @@ module Tapioca
|
|
83
43
|
|
84
44
|
sig { void }
|
85
45
|
def require_bundle
|
86
|
-
|
46
|
+
BundlerExt::AutoRequireHook.override_require_false(exclude: @excluded_gems) do
|
47
|
+
T.unsafe(runtime).require(*groups)
|
48
|
+
end
|
87
49
|
end
|
88
50
|
|
89
51
|
private
|
@@ -31,8 +31,8 @@ module Tapioca
|
|
31
31
|
|
32
32
|
sig { params(options: T::Hash[Symbol, T.untyped]).returns(T.nilable(String)) }
|
33
33
|
def netrc_file(options)
|
34
|
-
return
|
35
|
-
return
|
34
|
+
return if options[:auth]
|
35
|
+
return unless options[:netrc]
|
36
36
|
|
37
37
|
options[:netrc_file] || ENV["TAPIOCA_NETRC_FILE"] || File.join(ENV["HOME"].to_s, ".netrc")
|
38
38
|
end
|
@@ -80,7 +80,7 @@ module Tapioca
|
|
80
80
|
dsl_dir: String,
|
81
81
|
auto_strictness: T::Boolean,
|
82
82
|
gems: T::Array[Gemfile::GemSpec],
|
83
|
-
compilers: T::Enumerable[
|
83
|
+
compilers: T::Enumerable[T.class_of(Dsl::Compiler)],
|
84
84
|
).void
|
85
85
|
end
|
86
86
|
def validate_rbi_files(command:, gem_dir:, dsl_dir:, auto_strictness:, gems: [], compilers: [])
|
@@ -25,6 +25,7 @@ module Tapioca
|
|
25
25
|
{
|
26
26
|
# feature_name: ::Gem::Requirement.new(">= ___"), # https://github.com/sorbet/sorbet/pull/___
|
27
27
|
non_generic_weak_map: ::Gem::Requirement.new(">= 0.5.10587"), # https://github.com/sorbet/sorbet/pull/6610
|
28
|
+
generic_class: ::Gem::Requirement.new(">= 0.5.10820"), # https://github.com/sorbet/sorbet/pull/6781
|
28
29
|
}.freeze,
|
29
30
|
T::Hash[Symbol, ::Gem::Requirement],
|
30
31
|
)
|
@@ -29,7 +29,9 @@ module Tapioca
|
|
29
29
|
|
30
30
|
module Forking
|
31
31
|
extend T::Sig
|
32
|
-
|
32
|
+
extend T::Helpers
|
33
|
+
|
34
|
+
requires_ancestor { Kernel }
|
33
35
|
|
34
36
|
sig { params(_blk: T.untyped).returns(String) }
|
35
37
|
def run_in_isolation(&_blk)
|
@@ -72,7 +74,10 @@ module Tapioca
|
|
72
74
|
|
73
75
|
module Subprocess
|
74
76
|
extend T::Sig
|
75
|
-
|
77
|
+
extend T::Helpers
|
78
|
+
|
79
|
+
requires_ancestor { Kernel }
|
80
|
+
|
76
81
|
ORIG_ARGV = T.let(ARGV.dup, T::Array[T.untyped]) unless defined?(ORIG_ARGV)
|
77
82
|
|
78
83
|
# Crazy H4X to get this working in windows / jruby with
|
data/lib/tapioca/internal.rb
CHANGED
@@ -30,6 +30,7 @@ require "tapioca/helpers/gem_helper"
|
|
30
30
|
|
31
31
|
require "tapioca/helpers/sorbet_helper"
|
32
32
|
require "tapioca/helpers/rbi_helper"
|
33
|
+
require "tapioca/sorbet_ext/backcompat_patches"
|
33
34
|
require "tapioca/sorbet_ext/fixed_hash_patch"
|
34
35
|
require "tapioca/sorbet_ext/name_patch"
|
35
36
|
require "tapioca/sorbet_ext/generic_name_patch"
|
data/lib/tapioca/loaders/dsl.rb
CHANGED
@@ -9,9 +9,16 @@ module Tapioca
|
|
9
9
|
class << self
|
10
10
|
extend T::Sig
|
11
11
|
|
12
|
-
sig
|
13
|
-
|
14
|
-
|
12
|
+
sig do
|
13
|
+
params(tapioca_path: String, eager_load: T::Boolean, app_root: String, halt_upon_load_error: T::Boolean).void
|
14
|
+
end
|
15
|
+
def load_application(tapioca_path:, eager_load: true, app_root: ".", halt_upon_load_error: true)
|
16
|
+
loader = new(
|
17
|
+
tapioca_path: tapioca_path,
|
18
|
+
eager_load: eager_load,
|
19
|
+
app_root: app_root,
|
20
|
+
halt_upon_load_error: halt_upon_load_error,
|
21
|
+
)
|
15
22
|
loader.load
|
16
23
|
end
|
17
24
|
end
|
@@ -25,13 +32,16 @@ module Tapioca
|
|
25
32
|
|
26
33
|
protected
|
27
34
|
|
28
|
-
sig
|
29
|
-
|
35
|
+
sig do
|
36
|
+
params(tapioca_path: String, eager_load: T::Boolean, app_root: String, halt_upon_load_error: T::Boolean).void
|
37
|
+
end
|
38
|
+
def initialize(tapioca_path:, eager_load: true, app_root: ".", halt_upon_load_error: true)
|
30
39
|
super()
|
31
40
|
|
32
41
|
@tapioca_path = tapioca_path
|
33
42
|
@eager_load = eager_load
|
34
43
|
@app_root = app_root
|
44
|
+
@halt_upon_load_error = halt_upon_load_error
|
35
45
|
end
|
36
46
|
|
37
47
|
sig { void }
|
@@ -65,6 +75,7 @@ module Tapioca
|
|
65
75
|
environment_load: true,
|
66
76
|
eager_load: @eager_load,
|
67
77
|
app_root: @app_root,
|
78
|
+
halt_upon_load_error: @halt_upon_load_error,
|
68
79
|
)
|
69
80
|
|
70
81
|
say("Done", :green)
|
data/lib/tapioca/loaders/gem.rb
CHANGED
@@ -15,14 +15,16 @@ module Tapioca
|
|
15
15
|
prerequire: T.nilable(String),
|
16
16
|
postrequire: String,
|
17
17
|
default_command: String,
|
18
|
+
halt_upon_load_error: T::Boolean,
|
18
19
|
).void
|
19
20
|
end
|
20
|
-
def load_application(bundle:, prerequire:, postrequire:, default_command:)
|
21
|
+
def load_application(bundle:, prerequire:, postrequire:, default_command:, halt_upon_load_error:)
|
21
22
|
loader = new(
|
22
23
|
bundle: bundle,
|
23
24
|
prerequire: prerequire,
|
24
25
|
postrequire: postrequire,
|
25
26
|
default_command: default_command,
|
27
|
+
halt_upon_load_error: halt_upon_load_error,
|
26
28
|
)
|
27
29
|
loader.load
|
28
30
|
end
|
@@ -41,22 +43,24 @@ module Tapioca
|
|
41
43
|
prerequire: T.nilable(String),
|
42
44
|
postrequire: String,
|
43
45
|
default_command: String,
|
46
|
+
halt_upon_load_error: T::Boolean,
|
44
47
|
).void
|
45
48
|
end
|
46
|
-
def initialize(bundle:, prerequire:, postrequire:, default_command:)
|
49
|
+
def initialize(bundle:, prerequire:, postrequire:, default_command:, halt_upon_load_error:)
|
47
50
|
super()
|
48
51
|
|
49
52
|
@bundle = bundle
|
50
53
|
@prerequire = prerequire
|
51
54
|
@postrequire = postrequire
|
52
55
|
@default_command = default_command
|
56
|
+
@halt_upon_load_error = halt_upon_load_error
|
53
57
|
end
|
54
58
|
|
55
59
|
sig { void }
|
56
60
|
def require_gem_file
|
57
61
|
say("Requiring all gems to prepare for compiling... ")
|
58
62
|
begin
|
59
|
-
load_bundle(@bundle, @prerequire, @postrequire)
|
63
|
+
load_bundle(@bundle, @prerequire, @postrequire, @halt_upon_load_error)
|
60
64
|
rescue LoadError => e
|
61
65
|
explain_failed_require(@postrequire, e)
|
62
66
|
exit(1)
|
@@ -19,12 +19,17 @@ module Tapioca
|
|
19
19
|
private
|
20
20
|
|
21
21
|
sig do
|
22
|
-
params(
|
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
|
23
28
|
end
|
24
|
-
def load_bundle(gemfile, initialize_file, require_file)
|
29
|
+
def load_bundle(gemfile, initialize_file, require_file, halt_upon_load_error)
|
25
30
|
require_helper(initialize_file)
|
26
31
|
|
27
|
-
load_rails_application
|
32
|
+
load_rails_application(halt_upon_load_error: halt_upon_load_error)
|
28
33
|
|
29
34
|
gemfile.require_bundle
|
30
35
|
|
@@ -33,8 +38,15 @@ module Tapioca
|
|
33
38
|
load_rails_engines
|
34
39
|
end
|
35
40
|
|
36
|
-
sig
|
37
|
-
|
41
|
+
sig do
|
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
|
49
|
+
def load_rails_application(environment_load: false, eager_load: false, app_root: ".", halt_upon_load_error: true)
|
38
50
|
return unless File.exist?("#{app_root}/config/application.rb")
|
39
51
|
|
40
52
|
silence_deprecations
|
@@ -50,9 +62,13 @@ module Tapioca
|
|
50
62
|
say(
|
51
63
|
"\nTapioca attempted to load the Rails application after encountering a `config/application.rb` file, " \
|
52
64
|
"but it failed. If your application uses Rails please ensure it can be loaded correctly before " \
|
53
|
-
"generating RBIs
|
65
|
+
"generating RBIs. If your application does not use Rails and you wish to continue RBI generation " \
|
66
|
+
"please pass `--no-halt-upon-load-error` to the tapioca command in sorbet/tapioca/config.yml or in CLI." \
|
67
|
+
"\n#{e}",
|
54
68
|
:yellow,
|
55
69
|
)
|
70
|
+
raise e if halt_upon_load_error
|
71
|
+
|
56
72
|
if e.backtrace
|
57
73
|
backtrace = T.must(e.backtrace).join("\n")
|
58
74
|
say(backtrace, :cyan) # TODO: Check verbose flag to print backtrace.
|
@@ -151,7 +151,7 @@ module Tapioca
|
|
151
151
|
generic_type
|
152
152
|
end
|
153
153
|
|
154
|
-
sig { params(constant: Class).returns(Class) }
|
154
|
+
sig { params(constant: T::Class[T.anything]).returns(T::Class[T.anything]) }
|
155
155
|
def create_safe_subclass(constant)
|
156
156
|
# Lookup the "inherited" class method
|
157
157
|
inherited_method = constant.method(:inherited)
|
@@ -52,7 +52,7 @@ module Tapioca
|
|
52
52
|
UNDEFINED_CONSTANT
|
53
53
|
end
|
54
54
|
|
55
|
-
sig { params(object: BasicObject).returns(Class).checked(:never) }
|
55
|
+
sig { params(object: BasicObject).returns(T::Class[T.anything]).checked(:never) }
|
56
56
|
def class_of(object)
|
57
57
|
CLASS_METHOD.bind_call(object)
|
58
58
|
end
|
@@ -68,7 +68,7 @@ module Tapioca
|
|
68
68
|
name&.start_with?("#<") ? nil : name
|
69
69
|
end
|
70
70
|
|
71
|
-
sig { params(constant: Module).returns(Class) }
|
71
|
+
sig { params(constant: Module).returns(T::Class[T.anything]) }
|
72
72
|
def singleton_class_of(constant)
|
73
73
|
SINGLETON_CLASS_METHOD.bind_call(constant)
|
74
74
|
end
|
@@ -78,7 +78,7 @@ module Tapioca
|
|
78
78
|
ANCESTORS_METHOD.bind_call(constant)
|
79
79
|
end
|
80
80
|
|
81
|
-
sig { params(constant: Class).returns(T.nilable(Class)) }
|
81
|
+
sig { params(constant: T::Class[T.anything]).returns(T.nilable(T::Class[T.anything])) }
|
82
82
|
def superclass_of(constant)
|
83
83
|
SUPERCLASS_METHOD.bind_call(constant)
|
84
84
|
end
|
@@ -113,7 +113,7 @@ module Tapioca
|
|
113
113
|
if Class === constant
|
114
114
|
ancestors_of(superclass_of(constant) || Object)
|
115
115
|
else
|
116
|
-
Module.ancestors
|
116
|
+
Module.new.ancestors
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
@@ -161,7 +161,7 @@ module Tapioca
|
|
161
161
|
# descendants_of(C) # => [B, A, D]
|
162
162
|
sig do
|
163
163
|
type_parameters(:U)
|
164
|
-
.params(klass: T.all(Class, T.type_parameter(:U)))
|
164
|
+
.params(klass: T.all(T::Class[T.anything], T.type_parameter(:U)))
|
165
165
|
.returns(T::Array[T.type_parameter(:U)])
|
166
166
|
end
|
167
167
|
def descendants_of(klass)
|
@@ -192,6 +192,22 @@ module Tapioca
|
|
192
192
|
end.to_set
|
193
193
|
end
|
194
194
|
|
195
|
+
sig { params(constant: Module).returns(T.untyped) }
|
196
|
+
def abstract_type_of(constant)
|
197
|
+
T::Private::Abstract::Data.get(constant, :abstract_type) ||
|
198
|
+
T::Private::Abstract::Data.get(singleton_class_of(constant), :abstract_type)
|
199
|
+
end
|
200
|
+
|
201
|
+
sig { params(constant: Module).returns(T::Boolean) }
|
202
|
+
def final_module?(constant)
|
203
|
+
T::Private::Final.final_module?(constant)
|
204
|
+
end
|
205
|
+
|
206
|
+
sig { params(constant: Module).returns(T::Boolean) }
|
207
|
+
def sealed_module?(constant)
|
208
|
+
T::Private::Sealed.sealed_module?(constant)
|
209
|
+
end
|
210
|
+
|
195
211
|
private
|
196
212
|
|
197
213
|
sig { params(constant: Module).returns(T::Array[UnboundMethod]) }
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
unless defined?(T.anything)
|
5
|
+
module T
|
6
|
+
class << self
|
7
|
+
def anything
|
8
|
+
T.untyped
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
unless defined?(T::Class)
|
15
|
+
module T
|
16
|
+
module Class
|
17
|
+
class << self
|
18
|
+
def [](type)
|
19
|
+
T.untyped
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -49,6 +49,21 @@ module T
|
|
49
49
|
Tapioca::Runtime::GenericTypeRegistry.register_type_variable(self, type_variable)
|
50
50
|
end
|
51
51
|
end
|
52
|
+
|
53
|
+
def has_attached_class!(variance = :invariant, &bounds_proc)
|
54
|
+
Tapioca::Runtime::GenericTypeRegistry.register_type_variable(
|
55
|
+
self,
|
56
|
+
Tapioca::TypeVariableModule.new(
|
57
|
+
T.cast(self, Module),
|
58
|
+
Tapioca::TypeVariableModule::Type::HasAttachedClass,
|
59
|
+
variance,
|
60
|
+
nil,
|
61
|
+
nil,
|
62
|
+
nil,
|
63
|
+
bounds_proc,
|
64
|
+
),
|
65
|
+
)
|
66
|
+
end
|
52
67
|
end
|
53
68
|
|
54
69
|
prepend TypeStoragePatch
|
@@ -140,9 +155,13 @@ module Tapioca
|
|
140
155
|
enums do
|
141
156
|
Member = new("type_member")
|
142
157
|
Template = new("type_template")
|
158
|
+
HasAttachedClass = new("has_attached_class!")
|
143
159
|
end
|
144
160
|
end
|
145
161
|
|
162
|
+
sig { returns(Type) }
|
163
|
+
attr_reader :type
|
164
|
+
|
146
165
|
# rubocop:disable Metrics/ParameterLists
|
147
166
|
sig do
|
148
167
|
params(
|
data/lib/tapioca/version.rb
CHANGED
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.
|
4
|
+
version: 0.11.8
|
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-
|
14
|
+
date: 2023-07-12 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -149,6 +149,7 @@ files:
|
|
149
149
|
- README.md
|
150
150
|
- exe/tapioca
|
151
151
|
- lib/tapioca.rb
|
152
|
+
- lib/tapioca/bundler_ext/auto_require_hook.rb
|
152
153
|
- lib/tapioca/cli.rb
|
153
154
|
- lib/tapioca/commands.rb
|
154
155
|
- lib/tapioca/commands/annotations.rb
|
@@ -253,6 +254,7 @@ files:
|
|
253
254
|
- lib/tapioca/runtime/trackers/mixin.rb
|
254
255
|
- lib/tapioca/runtime/trackers/required_ancestor.rb
|
255
256
|
- lib/tapioca/runtime/trackers/tracker.rb
|
257
|
+
- lib/tapioca/sorbet_ext/backcompat_patches.rb
|
256
258
|
- lib/tapioca/sorbet_ext/fixed_hash_patch.rb
|
257
259
|
- lib/tapioca/sorbet_ext/generic_name_patch.rb
|
258
260
|
- lib/tapioca/sorbet_ext/name_patch.rb
|
@@ -281,7 +283,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
281
283
|
- !ruby/object:Gem::Version
|
282
284
|
version: '0'
|
283
285
|
requirements: []
|
284
|
-
rubygems_version: 3.4.
|
286
|
+
rubygems_version: 3.4.16
|
285
287
|
signing_key:
|
286
288
|
specification_version: 4
|
287
289
|
summary: A Ruby Interface file generator for gems, core types and the Ruby standard
|