tapioca 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/lib/tapioca/compilers/dsl/active_record_columns.rb +17 -9
- data/lib/tapioca/compilers/dsl/base.rb +2 -0
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +1 -1
- data/lib/tapioca/gemfile.rb +32 -9
- data/lib/tapioca/generator.rb +14 -4
- data/lib/tapioca/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46bdcc628673ddc597495e267b471e3a6f4c705b8f8d8d32dffba17c69470c21
|
4
|
+
data.tar.gz: 4a2e597d03ea9354835e73f52034d088b1c15ac65f445d0f6963bbbca09c2b23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51c134a7948c262721672f61105e08e1e31146b70d982fac0944b0d42be91d5e2210a110775596d11704e60eac68d6b2e27c016587777c658fab2b64131f7a1e
|
7
|
+
data.tar.gz: 1f048066d59bc2cc08a62fb93de96afdb7146d8e1c987c2a98677edd4920b08896096f9beaa658466ebd54be729c2bf6947ef1c409ab7329dac5ac27f7847dbc
|
data/README.md
CHANGED
@@ -8,6 +8,8 @@ As yet, no gem exports type information in a consumable format and it would be a
|
|
8
8
|
|
9
9
|
When you run `tapioca sync` in a project, `tapioca` loads all the gems that are in your dependency list from the Gemfile into memory. It then performs runtime introspection on the loaded types to understand their structure and generates an appropriate RBI file for each gem with a versioned filename.
|
10
10
|
|
11
|
+
## Manual gem requires
|
12
|
+
|
11
13
|
For gems that have a normal default `require` and load all of their constants through such a require, everything works seamlessly. However, for gems that are marked as `require: false` in the Gemfile, or for gems that export optionally loaded types via different requires, where a single require does not load the whole gem code into memory, `tapioca` will not be able to load some of the types into memory and, thus, won't be able to generate complete RBIs for them. For this reason, we need to keep a small external file named `sorbet/tapioca/require.rb` that is executed after all the gems in the Gemfile have been required and before generation of gem RBIs have started. This file is responsible for adding the requires for additional files from gems, which are not covered by the default require.
|
12
14
|
|
13
15
|
For example, suppose you are using the class `BetterHtml::Parser` exported from the `better_html` gem. Just doing a `require "better_html"` (which is the default require) does not load that type:
|
@@ -349,9 +349,9 @@ module Tapioca
|
|
349
349
|
!(constant.singleton_class < Object.const_get(:StrongTypeGeneration))
|
350
350
|
end
|
351
351
|
|
352
|
-
sig { params(column_type:
|
352
|
+
sig { params(column_type: Object).returns(String) }
|
353
353
|
def handle_unknown_type(column_type)
|
354
|
-
return "T.untyped" unless
|
354
|
+
return "T.untyped" unless ActiveModel::Type::Value === column_type
|
355
355
|
|
356
356
|
lookup_return_type_of_method(column_type, :deserialize) ||
|
357
357
|
lookup_return_type_of_method(column_type, :cast) ||
|
@@ -359,19 +359,27 @@ module Tapioca
|
|
359
359
|
"T.untyped"
|
360
360
|
end
|
361
361
|
|
362
|
-
sig { params(column_type:
|
362
|
+
sig { params(column_type: ActiveModel::Type::Value, method: Symbol).returns(T.nilable(String)) }
|
363
363
|
def lookup_return_type_of_method(column_type, method)
|
364
|
-
signature = T::Private::Methods.signature_for_method(column_type.
|
364
|
+
signature = T::Private::Methods.signature_for_method(column_type.method(method))
|
365
365
|
return unless signature
|
366
366
|
|
367
|
-
return_type = signature.return_type
|
368
|
-
|
367
|
+
return_type = signature.return_type
|
368
|
+
return if T::Types::Simple === return_type && T::Generic === return_type.raw_type
|
369
|
+
return if return_type == T::Private::Types::Void || return_type == T::Private::Types::NotTyped
|
370
|
+
|
371
|
+
return_type.to_s
|
369
372
|
end
|
370
373
|
|
371
|
-
sig { params(column_type:
|
374
|
+
sig { params(column_type: ActiveModel::Type::Value, method: Symbol).returns(T.nilable(String)) }
|
372
375
|
def lookup_arg_type_of_method(column_type, method)
|
373
|
-
signature = T::Private::Methods.signature_for_method(column_type.
|
374
|
-
|
376
|
+
signature = T::Private::Methods.signature_for_method(column_type.method(method))
|
377
|
+
return unless signature
|
378
|
+
|
379
|
+
arg_type = signature.arg_types.first.last
|
380
|
+
return if T::Types::Simple === arg_type && T::Generic === arg_type.raw_type
|
381
|
+
|
382
|
+
arg_type.to_s
|
375
383
|
end
|
376
384
|
end
|
377
385
|
end
|
data/lib/tapioca/gemfile.rb
CHANGED
@@ -28,7 +28,7 @@ module Tapioca
|
|
28
28
|
sig { returns(T::Array[Gem]) }
|
29
29
|
def dependencies
|
30
30
|
@dependencies ||= begin
|
31
|
-
specs = definition.specs.to_a
|
31
|
+
specs = definition.locked_gems.specs.to_a
|
32
32
|
|
33
33
|
definition
|
34
34
|
.resolve
|
@@ -79,17 +79,18 @@ module Tapioca
|
|
79
79
|
extend(T::Sig)
|
80
80
|
|
81
81
|
IGNORED_GEMS = T.let(%w{
|
82
|
-
sorbet sorbet-static sorbet-runtime
|
82
|
+
sorbet sorbet-static sorbet-runtime
|
83
83
|
}.freeze, T::Array[String])
|
84
84
|
|
85
85
|
sig { returns(String) }
|
86
|
-
attr_reader :full_gem_path
|
86
|
+
attr_reader :full_gem_path, :version
|
87
87
|
|
88
88
|
sig { params(spec: Spec).void }
|
89
89
|
def initialize(spec)
|
90
90
|
@spec = T.let(spec, Tapioca::Gemfile::Spec)
|
91
91
|
real_gem_path = to_realpath(@spec.full_gem_path)
|
92
92
|
@full_gem_path = T.let(real_gem_path, String)
|
93
|
+
@version = T.let(version_string, String)
|
93
94
|
end
|
94
95
|
|
95
96
|
sig { params(gemfile_dir: String).returns(T::Boolean) }
|
@@ -109,11 +110,6 @@ module Tapioca
|
|
109
110
|
@spec.name
|
110
111
|
end
|
111
112
|
|
112
|
-
sig { returns(::Gem::Version) }
|
113
|
-
def version
|
114
|
-
@spec.version
|
115
|
-
end
|
116
|
-
|
117
113
|
sig { returns(String) }
|
118
114
|
def rbi_file_name
|
119
115
|
"#{name}@#{version}.rbi"
|
@@ -121,11 +117,38 @@ module Tapioca
|
|
121
117
|
|
122
118
|
sig { params(path: String).returns(T::Boolean) }
|
123
119
|
def contains_path?(path)
|
124
|
-
to_realpath(path).start_with?(full_gem_path)
|
120
|
+
to_realpath(path).start_with?(full_gem_path) || has_parent_gemspec?(path)
|
125
121
|
end
|
126
122
|
|
127
123
|
private
|
128
124
|
|
125
|
+
sig { returns(String) }
|
126
|
+
def version_string
|
127
|
+
version = @spec.version.to_s
|
128
|
+
version += "-#{@spec.source.revision}" if Bundler::Source::Git === @spec.source
|
129
|
+
version
|
130
|
+
end
|
131
|
+
|
132
|
+
sig { params(path: String).returns(T::Boolean) }
|
133
|
+
def has_parent_gemspec?(path)
|
134
|
+
# For some Git installed gems the location of the loaded file can
|
135
|
+
# be different from the gem path as indicated by the spec file
|
136
|
+
#
|
137
|
+
# To compensate for these cases, we walk up the directory hierarchy
|
138
|
+
# from the given file and try to match a <gem-name.gemspec> file in
|
139
|
+
# one of those folders to see if the path really belongs in the given gem
|
140
|
+
# or not.
|
141
|
+
return false unless Bundler::Source::Git === @spec.source
|
142
|
+
parent = Pathname.new(path)
|
143
|
+
|
144
|
+
until parent.root?
|
145
|
+
parent = parent.parent.expand_path
|
146
|
+
return true if parent.join("#{name}.gemspec").file?
|
147
|
+
end
|
148
|
+
|
149
|
+
false
|
150
|
+
end
|
151
|
+
|
129
152
|
sig { params(path: T.any(String, Pathname)).returns(String) }
|
130
153
|
def to_realpath(path)
|
131
154
|
path_string = path.to_s
|
data/lib/tapioca/generator.rb
CHANGED
@@ -162,6 +162,11 @@ module Tapioca
|
|
162
162
|
|
163
163
|
private
|
164
164
|
|
165
|
+
EMPTY_RBI_COMMENT = <<~CONTENT
|
166
|
+
# THIS IS AN EMPTY RBI FILE.
|
167
|
+
# see https://github.com/Shopify/tapioca/blob/master/README.md#manual-gem-requires
|
168
|
+
CONTENT
|
169
|
+
|
165
170
|
sig { returns(Gemfile) }
|
166
171
|
def bundle
|
167
172
|
@bundle ||= Gemfile.new
|
@@ -422,20 +427,25 @@ module Tapioca
|
|
422
427
|
say("Compiling #{gem_name}, this may take a few seconds... ")
|
423
428
|
|
424
429
|
strictness = config.typed_overrides[gem.name] || "true"
|
425
|
-
|
430
|
+
rbi_body_content = compiler.compile(gem)
|
426
431
|
content = String.new
|
427
432
|
content << rbi_header(
|
428
433
|
config.generate_command,
|
429
434
|
reason: "types exported from the `#{gem.name}` gem",
|
430
435
|
strictness: strictness
|
431
436
|
)
|
432
|
-
content << compiler.compile(gem)
|
433
437
|
|
434
438
|
FileUtils.mkdir_p(config.outdir)
|
435
439
|
filename = config.outpath / gem.rbi_file_name
|
436
|
-
File.write(filename.to_s, content)
|
437
440
|
|
438
|
-
|
441
|
+
if rbi_body_content.strip.empty?
|
442
|
+
content << EMPTY_RBI_COMMENT
|
443
|
+
say("Done (empty output)", :yellow)
|
444
|
+
else
|
445
|
+
content << rbi_body_content
|
446
|
+
say("Done", :green)
|
447
|
+
end
|
448
|
+
File.write(filename.to_s, content)
|
439
449
|
|
440
450
|
Pathname.glob((config.outpath / "#{gem.name}@*.rbi").to_s) do |file|
|
441
451
|
remove(file) unless file.basename.to_s == gem.rbi_file_name
|
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.2
|
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: 2020-
|
14
|
+
date: 2020-08-18 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: pry
|