tapioca 0.4.22 → 0.4.26
Sign up to get free protection for your applications and to get access to all the features.
- 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
|