tapioca 0.4.22 → 0.4.26
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/exe/tapioca +2 -0
- data/lib/tapioca/compilers/dsl/active_job.rb +19 -11
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +23 -4
- data/lib/tapioca/compilers/symbol_table_compiler.rb +1 -1
- data/lib/tapioca/gemfile.rb +48 -19
- data/lib/tapioca/generator.rb +3 -3
- data/lib/tapioca/internal.rb +1 -0
- data/lib/tapioca/loader.rb +3 -17
- data/lib/tapioca/rbi/rewriters/sort_nodes.rb +16 -12
- data/lib/tapioca/sorbet_ext/fixed_hash_patch.rb +20 -0
- data/lib/tapioca/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f5e0d26fdadddd8d95b78403ee2cd71240d8d43475bffec2af018b543c2114b
|
4
|
+
data.tar.gz: '0746977c9a6501ea37011cde413597191822d3cc6e7cbd5258b65acab8ce81e0'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80cf81f29ba50819ddba39cd388aa6f59d93bf99ac02c0a596f888793191e85b48fa9537f258fcd188b73b92ceb30268eb56d1aadac2f9026b9ba101196e24b4
|
7
|
+
data.tar.gz: a78072381e07709ebc2331e6cf988510e2e7a52c4cf24c66e4fb46a08293042cfb3b86619b5176fa023ae317107f741ed668fe8684042f50e927c760aab22612
|
data/exe/tapioca
CHANGED
@@ -5,6 +5,8 @@ require 'sorbet-runtime'
|
|
5
5
|
|
6
6
|
begin
|
7
7
|
T::Configuration.default_checked_level = :never
|
8
|
+
# Suppresses call validation errors
|
9
|
+
T::Configuration.call_validation_error_handler = ->(*) {}
|
8
10
|
# Suppresses errors caused by T.cast, T.let, T.must, etc.
|
9
11
|
T::Configuration.inline_type_error_handler = ->(*) {}
|
10
12
|
# Suppresses errors caused by incorrect parameter ordering
|
@@ -19,6 +19,7 @@ module Tapioca
|
|
19
19
|
#
|
20
20
|
# ~~~rb
|
21
21
|
# class NotifyUserJob < ActiveJob::Base
|
22
|
+
# sig { params(user: User).returns(Mail) }
|
22
23
|
# def perform(user)
|
23
24
|
# # ...
|
24
25
|
# end
|
@@ -31,10 +32,10 @@ module Tapioca
|
|
31
32
|
# # notify_user_job.rbi
|
32
33
|
# # typed: true
|
33
34
|
# class NotifyUserJob
|
34
|
-
# sig { params(user:
|
35
|
+
# sig { params(user: User).returns(T.any(NotifyUserJob, FalseClass)) }
|
35
36
|
# def self.perform_later(user); end
|
36
37
|
#
|
37
|
-
# sig { params(user:
|
38
|
+
# sig { params(user: User).returns(Mail) }
|
38
39
|
# def self.perform_now(user); end
|
39
40
|
# end
|
40
41
|
# ~~~
|
@@ -48,16 +49,23 @@ module Tapioca
|
|
48
49
|
|
49
50
|
method = constant.instance_method(:perform)
|
50
51
|
parameters = compile_method_parameters_to_parlour(method)
|
52
|
+
return_type = compile_method_return_type_to_parlour(method)
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
54
|
+
create_method(
|
55
|
+
job,
|
56
|
+
"perform_later",
|
57
|
+
parameters: parameters,
|
58
|
+
return_type: "T.any(#{constant.name}, FalseClass)",
|
59
|
+
class_method: true
|
60
|
+
)
|
61
|
+
|
62
|
+
create_method(
|
63
|
+
job,
|
64
|
+
"perform_now",
|
65
|
+
parameters: parameters,
|
66
|
+
return_type: return_type,
|
67
|
+
class_method: true
|
68
|
+
)
|
61
69
|
end
|
62
70
|
end
|
63
71
|
|
@@ -17,7 +17,7 @@ module Tapioca
|
|
17
17
|
|
18
18
|
attr_reader(:gem, :indent)
|
19
19
|
|
20
|
-
sig { params(gem: Gemfile::
|
20
|
+
sig { params(gem: Gemfile::GemSpec, indent: Integer).void }
|
21
21
|
def initialize(gem, indent = 0)
|
22
22
|
@gem = gem
|
23
23
|
@indent = indent
|
@@ -145,7 +145,15 @@ module Tapioca
|
|
145
145
|
def compile_object(tree, name, value)
|
146
146
|
return if symbol_ignored?(name)
|
147
147
|
klass = class_of(value)
|
148
|
-
|
148
|
+
|
149
|
+
klass_name = if klass == ObjectSpace::WeakMap
|
150
|
+
# WeakMap is an implicit generic with one type variable
|
151
|
+
"ObjectSpace::WeakMap[T.untyped]"
|
152
|
+
elsif T::Generic === klass
|
153
|
+
generic_name_of(klass)
|
154
|
+
else
|
155
|
+
name_of(klass)
|
156
|
+
end
|
149
157
|
|
150
158
|
if klass_name == "T::Private::Types::TypeAlias"
|
151
159
|
tree << RBI::Const.new(name, "T.type_alias { #{T.unsafe(value).aliased_type} }")
|
@@ -155,8 +163,6 @@ module Tapioca
|
|
155
163
|
return if klass_name&.start_with?("T::Types::", "T::Private::")
|
156
164
|
|
157
165
|
type_name = klass_name || "T.untyped"
|
158
|
-
# TODO: Do this in a more generic and clean way.
|
159
|
-
type_name = "#{type_name}[T.untyped]" if type_name == "ObjectSpace::WeakMap"
|
160
166
|
|
161
167
|
tree << RBI::Const.new(name, "T.let(T.unsafe(nil), #{type_name})")
|
162
168
|
end
|
@@ -774,6 +780,19 @@ module Tapioca
|
|
774
780
|
name
|
775
781
|
end
|
776
782
|
|
783
|
+
sig { params(constant: T.all(Module, T::Generic)).returns(String) }
|
784
|
+
def generic_name_of(constant)
|
785
|
+
type_name = T.must(constant.name)
|
786
|
+
return type_name if type_name =~ /\[.*\]$/
|
787
|
+
|
788
|
+
type_variables = Tapioca::GenericTypeRegistry.lookup_type_variables(constant)
|
789
|
+
return type_name unless type_variables
|
790
|
+
|
791
|
+
type_variable_names = type_variables.map { "T.untyped" }.join(", ")
|
792
|
+
|
793
|
+
"#{type_name}[#{type_variable_names}]"
|
794
|
+
end
|
795
|
+
|
777
796
|
sig { params(constant: Module).returns(T.nilable(String)) }
|
778
797
|
def name_of_proxy_target(constant)
|
779
798
|
klass = class_of(constant)
|
data/lib/tapioca/gemfile.rb
CHANGED
@@ -20,7 +20,7 @@ module Tapioca
|
|
20
20
|
sig { returns(Bundler::Definition) }
|
21
21
|
attr_reader(:definition)
|
22
22
|
|
23
|
-
sig { returns(T::Array[
|
23
|
+
sig { returns(T::Array[GemSpec]) }
|
24
24
|
attr_reader(:dependencies)
|
25
25
|
|
26
26
|
sig { returns(T::Array[String]) }
|
@@ -32,18 +32,18 @@ module Tapioca
|
|
32
32
|
@lockfile = T.let(File.new(Bundler.default_lockfile), File)
|
33
33
|
@definition = T.let(Bundler::Dsl.evaluate(gemfile, lockfile, {}), Bundler::Definition)
|
34
34
|
dependencies, missing_specs = load_dependencies
|
35
|
-
@dependencies = T.let(dependencies, T::Array[
|
35
|
+
@dependencies = T.let(dependencies, T::Array[GemSpec])
|
36
36
|
@missing_specs = T.let(missing_specs, T::Array[String])
|
37
37
|
end
|
38
38
|
|
39
|
-
sig { params(gem_name: String).returns(T.nilable(
|
39
|
+
sig { params(gem_name: String).returns(T.nilable(GemSpec)) }
|
40
40
|
def gem(gem_name)
|
41
41
|
dependencies.detect { |dep| dep.name == gem_name }
|
42
42
|
end
|
43
43
|
|
44
44
|
sig { void }
|
45
|
-
def
|
46
|
-
T.unsafe(runtime).
|
45
|
+
def require_bundle
|
46
|
+
T.unsafe(runtime).require(*groups)
|
47
47
|
end
|
48
48
|
|
49
49
|
private
|
@@ -51,23 +51,32 @@ module Tapioca
|
|
51
51
|
sig { returns(File) }
|
52
52
|
attr_reader(:gemfile, :lockfile)
|
53
53
|
|
54
|
-
sig { returns([T::Array[
|
54
|
+
sig { returns([T::Array[GemSpec], T::Array[String]]) }
|
55
55
|
def load_dependencies
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
dependencies = definition
|
61
|
-
.resolve
|
62
|
-
.materialize(deps, missing_specs)
|
63
|
-
.map { |spec| Gem.new(spec) }
|
56
|
+
materialized_dependencies, missing_specs = materialize_deps
|
57
|
+
dependencies = materialized_dependencies
|
58
|
+
.map { |spec| GemSpec.new(spec) }
|
64
59
|
.reject { |gem| gem.ignore?(dir) }
|
65
60
|
.uniq(&:rbi_file_name)
|
66
61
|
.sort_by(&:rbi_file_name)
|
67
|
-
|
68
62
|
[dependencies, missing_specs]
|
69
63
|
end
|
70
64
|
|
65
|
+
sig { returns([T::Array[::Gem::Specification], T::Array[String]]) }
|
66
|
+
def materialize_deps
|
67
|
+
deps = definition.locked_gems.dependencies.values
|
68
|
+
missing_specs = T::Array[String].new
|
69
|
+
materialized_dependencies = if definition.resolve.method(:materialize).arity == 1 # Support bundler >= v2.2.25
|
70
|
+
md = definition.resolve.materialize(deps)
|
71
|
+
missing_spec_names = md.missing_specs.map(&:name)
|
72
|
+
missing_specs = T.cast(md.missing_specs.map { |spec| "#{spec.name} (#{spec.version})" }, T::Array[String])
|
73
|
+
md.to_a.reject { |spec| missing_spec_names.include?(spec.name) }
|
74
|
+
else
|
75
|
+
definition.resolve.materialize(deps, missing_specs)
|
76
|
+
end
|
77
|
+
[materialized_dependencies, missing_specs]
|
78
|
+
end
|
79
|
+
|
71
80
|
sig { returns(Bundler::Runtime) }
|
72
81
|
def runtime
|
73
82
|
Bundler::Runtime.new(File.dirname(gemfile.path), definition)
|
@@ -83,7 +92,7 @@ module Tapioca
|
|
83
92
|
File.expand_path(gemfile.path + "/..")
|
84
93
|
end
|
85
94
|
|
86
|
-
class
|
95
|
+
class GemSpec
|
87
96
|
extend(T::Sig)
|
88
97
|
|
89
98
|
IGNORED_GEMS = T.let(%w{
|
@@ -108,8 +117,14 @@ module Tapioca
|
|
108
117
|
|
109
118
|
sig { returns(T::Array[Pathname]) }
|
110
119
|
def files
|
111
|
-
|
112
|
-
|
120
|
+
if default_gem?
|
121
|
+
@spec.files.map do |file|
|
122
|
+
ruby_lib_dir.join(file)
|
123
|
+
end
|
124
|
+
else
|
125
|
+
@spec.full_require_paths.flat_map do |path|
|
126
|
+
Pathname.glob((Pathname.new(path) / "**/*.rb").to_s)
|
127
|
+
end
|
113
128
|
end
|
114
129
|
end
|
115
130
|
|
@@ -125,11 +140,25 @@ module Tapioca
|
|
125
140
|
|
126
141
|
sig { params(path: String).returns(T::Boolean) }
|
127
142
|
def contains_path?(path)
|
128
|
-
|
143
|
+
if default_gem?
|
144
|
+
files.any? { |file| file.to_s == to_realpath(path) }
|
145
|
+
else
|
146
|
+
to_realpath(path).start_with?(full_gem_path) || has_parent_gemspec?(path)
|
147
|
+
end
|
129
148
|
end
|
130
149
|
|
131
150
|
private
|
132
151
|
|
152
|
+
sig { returns(T::Boolean) }
|
153
|
+
def default_gem?
|
154
|
+
@spec.respond_to?(:default_gem?) && @spec.default_gem?
|
155
|
+
end
|
156
|
+
|
157
|
+
sig { returns(Pathname) }
|
158
|
+
def ruby_lib_dir
|
159
|
+
Pathname.new(RbConfig::CONFIG["rubylibdir"])
|
160
|
+
end
|
161
|
+
|
133
162
|
sig { returns(String) }
|
134
163
|
def version_string
|
135
164
|
version = @spec.version.to_s
|
data/lib/tapioca/generator.rb
CHANGED
@@ -260,7 +260,7 @@ module Tapioca
|
|
260
260
|
def load_application(eager_load:)
|
261
261
|
say("Loading Rails application... ")
|
262
262
|
|
263
|
-
loader.
|
263
|
+
loader.load_rails_application(
|
264
264
|
environment_load: true,
|
265
265
|
eager_load: eager_load
|
266
266
|
)
|
@@ -456,7 +456,7 @@ module Tapioca
|
|
456
456
|
|
457
457
|
sig do
|
458
458
|
params(gem_names: T::Array[String])
|
459
|
-
.returns(T::Array[Gemfile::
|
459
|
+
.returns(T::Array[Gemfile::GemSpec])
|
460
460
|
end
|
461
461
|
def gems_to_generate(gem_names)
|
462
462
|
return bundle.dependencies if gem_names.empty?
|
@@ -486,7 +486,7 @@ module Tapioca
|
|
486
486
|
[statement, sigil].compact.join("\n").strip.concat("\n\n")
|
487
487
|
end
|
488
488
|
|
489
|
-
sig { params(gem: Gemfile::
|
489
|
+
sig { params(gem: Gemfile::GemSpec).void }
|
490
490
|
def compile_gem_rbi(gem)
|
491
491
|
compiler = Compilers::SymbolTableCompiler.new
|
492
492
|
gem_name = set_color(gem.name, :yellow, :bold)
|
data/lib/tapioca/internal.rb
CHANGED
@@ -6,6 +6,7 @@ require "tapioca/loader"
|
|
6
6
|
require "tapioca/constant_locator"
|
7
7
|
require "tapioca/generic_type_registry"
|
8
8
|
require "tapioca/sorbet_ext/generic_name_patch"
|
9
|
+
require "tapioca/sorbet_ext/fixed_hash_patch"
|
9
10
|
require "tapioca/config"
|
10
11
|
require "tapioca/config_builder"
|
11
12
|
require "tapioca/generator"
|
data/lib/tapioca/loader.rb
CHANGED
@@ -14,10 +14,9 @@ module Tapioca
|
|
14
14
|
def load_bundle(initialize_file, require_file)
|
15
15
|
require_helper(initialize_file)
|
16
16
|
|
17
|
-
|
18
|
-
load_rake
|
17
|
+
gemfile.require_bundle
|
19
18
|
|
20
|
-
|
19
|
+
load_rails_application
|
21
20
|
|
22
21
|
require_helper(require_file)
|
23
22
|
|
@@ -25,14 +24,11 @@ module Tapioca
|
|
25
24
|
end
|
26
25
|
|
27
26
|
sig { params(environment_load: T::Boolean, eager_load: T::Boolean).void }
|
28
|
-
def
|
27
|
+
def load_rails_application(environment_load: false, eager_load: false)
|
29
28
|
return unless File.exist?("config/application.rb")
|
30
29
|
|
31
|
-
safe_require("rails")
|
32
|
-
|
33
30
|
silence_deprecations
|
34
31
|
|
35
|
-
safe_require("rails/generators/test_case")
|
36
32
|
if environment_load
|
37
33
|
safe_require("./config/environment")
|
38
34
|
else
|
@@ -56,11 +52,6 @@ module Tapioca
|
|
56
52
|
require(file)
|
57
53
|
end
|
58
54
|
|
59
|
-
sig { void }
|
60
|
-
def require_bundle
|
61
|
-
gemfile.require
|
62
|
-
end
|
63
|
-
|
64
55
|
sig { returns(T::Array[T.untyped]) }
|
65
56
|
def rails_engines
|
66
57
|
engines = []
|
@@ -84,11 +75,6 @@ module Tapioca
|
|
84
75
|
nil
|
85
76
|
end
|
86
77
|
|
87
|
-
sig { void }
|
88
|
-
def load_rake
|
89
|
-
safe_require("rake")
|
90
|
-
end
|
91
|
-
|
92
78
|
sig { void }
|
93
79
|
def silence_deprecations
|
94
80
|
# Stop any ActiveSupport Deprecations from being reported
|
@@ -11,9 +11,11 @@ module Tapioca
|
|
11
11
|
def visit(node)
|
12
12
|
return unless node.is_a?(Tree)
|
13
13
|
visit_all(node.nodes)
|
14
|
+
original_order = node.nodes.map.with_index.to_h
|
14
15
|
node.nodes.sort! do |a, b|
|
15
16
|
res = node_rank(a) <=> node_rank(b)
|
16
17
|
res = node_name(a) <=> node_name(b) if res == 0
|
18
|
+
res = (original_order[a] || 0) <=> (original_order[b] || 0) if res == 0
|
17
19
|
res || 0
|
18
20
|
end
|
19
21
|
end
|
@@ -23,27 +25,29 @@ module Tapioca
|
|
23
25
|
sig { params(node: Node).returns(Integer) }
|
24
26
|
def node_rank(node)
|
25
27
|
case node
|
26
|
-
when Group then
|
27
|
-
when Include, Extend then
|
28
|
-
when Helper then
|
29
|
-
when TypeMember then
|
30
|
-
when MixesInClassMethods then
|
31
|
-
when TStructField then
|
32
|
-
when TEnumBlock then
|
28
|
+
when Group then group_rank(node.kind)
|
29
|
+
when Include, Extend then 10
|
30
|
+
when Helper then 20
|
31
|
+
when TypeMember then 30
|
32
|
+
when MixesInClassMethods then 40
|
33
|
+
when TStructField then 50
|
34
|
+
when TEnumBlock then 60
|
33
35
|
when Method
|
34
36
|
if node.name == "initialize"
|
35
|
-
|
37
|
+
71
|
38
|
+
elsif !node.is_singleton
|
39
|
+
72
|
36
40
|
else
|
37
|
-
|
41
|
+
73
|
38
42
|
end
|
39
|
-
when Scope, Const then
|
43
|
+
when Scope, Const then 80
|
40
44
|
else
|
41
|
-
|
45
|
+
100
|
42
46
|
end
|
43
47
|
end
|
44
48
|
|
45
49
|
sig { params(kind: Group::Kind).returns(Integer) }
|
46
|
-
def
|
50
|
+
def group_rank(kind)
|
47
51
|
case kind
|
48
52
|
when Group::Kind::Mixins then 0
|
49
53
|
when Group::Kind::Helpers then 1
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module T
|
5
|
+
module Types
|
6
|
+
class FixedHash
|
7
|
+
def name
|
8
|
+
entries = @types.map do |(k, v)|
|
9
|
+
if Symbol === k && ":#{k}" == k.inspect
|
10
|
+
"#{k}: #{v}"
|
11
|
+
else
|
12
|
+
"#{k.inspect} => #{v}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
"{#{entries.join(', ')}}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
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.4.
|
4
|
+
version: 0.4.26
|
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: 2021-
|
14
|
+
date: 2021-09-06 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -168,6 +168,7 @@ files:
|
|
168
168
|
- lib/tapioca/rbi/rewriters/nest_singleton_methods.rb
|
169
169
|
- lib/tapioca/rbi/rewriters/sort_nodes.rb
|
170
170
|
- lib/tapioca/rbi/visitor.rb
|
171
|
+
- lib/tapioca/sorbet_ext/fixed_hash_patch.rb
|
171
172
|
- lib/tapioca/sorbet_ext/generic_name_patch.rb
|
172
173
|
- lib/tapioca/sorbet_ext/name_patch.rb
|
173
174
|
- lib/tapioca/version.rb
|
@@ -191,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
191
192
|
- !ruby/object:Gem::Version
|
192
193
|
version: '0'
|
193
194
|
requirements: []
|
194
|
-
rubygems_version: 3.2.
|
195
|
+
rubygems_version: 3.2.20
|
195
196
|
signing_key:
|
196
197
|
specification_version: 4
|
197
198
|
summary: A Ruby Interface file generator for gems, core types and the Ruby standard
|