tapioca 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +28 -1
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +10 -5
- 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: 344a5afaf8a19df78713917f87adf663691d9b3c1ffee9c9e565b1a583eb01f6
|
4
|
+
data.tar.gz: d8c867d006f9c37c06d96652f1dd5c7c0311f50dfedc18bab6366fb9b4458319
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 353e2c32784e7b4f318a5b2d63d2403b4893adee3623f0957bbf341d159fd77db12abf3a0f18c5f74453553cf62105daeca5c18daa5e5ea43e1ee2fcdd4ad3a6
|
7
|
+
data.tar.gz: cb22c7aaa370ca3a4a0d5b7accb907e1f91cac5f94d4161311151fbd1e2abe39662659284d10fde664e0fb92fa309f84dc3ce9feb320f45dbec8fa23417df966
|
data/README.md
CHANGED
@@ -4,13 +4,40 @@
|
|
4
4
|
|
5
5
|
Tapioca is a library used to generate RBI (Ruby interface) files for use with [Sorbet](https://sorbet.org). RBI files provide the structure (classes, modules, methods, parameters) of the gem/library to Sorbet to assist with typechecking.
|
6
6
|
|
7
|
+
As yet, no gem exports type information in a consumable format and it would be a huge effort to manually maintain such an interface file for all the gems that your codebase depends on. Thus, there is a need for an automated way to generate the appropriate RBI file for a given gem. The `tapioca` gem, developed at Shopify, is able to do exactly that to almost 99% accuracy. It can generate the definitions for all statically defined types and most of the runtime defined types exported from Ruby gems (non-Ruby gems are not handled yet).
|
8
|
+
|
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
|
+
|
11
|
+
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
|
+
|
13
|
+
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:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
$ bundle exec pry
|
17
|
+
[1] pry(main)> require 'better_html'
|
18
|
+
=> true
|
19
|
+
[2] pry(main)> BetterHtml
|
20
|
+
=> BetterHtml
|
21
|
+
[3] pry(main)> BetterHtml::Parser
|
22
|
+
NameError: uninitialized constant BetterHtml::Parser
|
23
|
+
from (pry):3:in `__pry__`
|
24
|
+
[4] pry(main)> require 'better_html/parser'
|
25
|
+
=> true
|
26
|
+
[5] pry(main)> BetterHtml::Parser
|
27
|
+
=> BetterHtml::Parser
|
28
|
+
```
|
29
|
+
|
30
|
+
In order to make sure that `tapioca` can reflect on that type, we need to add the line `require "better_html/parser"` to the `sorbet/tapioca/require.rb` file. This will make sure `BetterHtml::Parser` is loaded into memory and a type annotation is generated for it in the `better_html.rbi` file. If this extra `require` line is not added to `sorbet/tapioca/require.rb` file, then the definition for that type will be missing from the RBI file.
|
31
|
+
|
32
|
+
If you ever run into a case, where you add a gem or update the version of a gem and run `tapioca sync` but don't have some types you expect in the generated gem RBI files, you will need to make sure you have added the necessary requires to the `sorbet/tapioca/require.rb` file.
|
33
|
+
|
7
34
|
## Installation
|
8
35
|
|
9
36
|
Add this line to your application's `Gemfile`:
|
10
37
|
|
11
38
|
```ruby
|
12
39
|
group :development do
|
13
|
-
gem 'tapioca',
|
40
|
+
gem 'tapioca', require: false
|
14
41
|
end
|
15
42
|
```
|
16
43
|
|
@@ -257,7 +257,7 @@ module Tapioca
|
|
257
257
|
|
258
258
|
inherited_singleton_class_ancestors =
|
259
259
|
if constant.is_a?(Class)
|
260
|
-
Set.new(constant.superclass.
|
260
|
+
Set.new(singleton_class_of(constant.superclass).ancestors)
|
261
261
|
else
|
262
262
|
Module.ancestors
|
263
263
|
end
|
@@ -267,9 +267,9 @@ module Tapioca
|
|
267
267
|
|
268
268
|
prepend = interesting_ancestors.take_while { |c| !are_equal?(constant, c) }
|
269
269
|
include = interesting_ancestors.drop(prepend.size + 1)
|
270
|
-
extend = constant.
|
270
|
+
extend = singleton_class_of(constant).ancestors
|
271
271
|
.reject do |mod|
|
272
|
-
mod == constant
|
272
|
+
mod == singleton_class_of(constant) ||
|
273
273
|
inherited_singleton_class_ancestors.include?(mod) ||
|
274
274
|
!public_module?(mod) ||
|
275
275
|
Module != class_of(mod)
|
@@ -321,7 +321,7 @@ module Tapioca
|
|
321
321
|
)
|
322
322
|
|
323
323
|
instance_methods = compile_directly_owned_methods(name, constant)
|
324
|
-
singleton_methods = compile_directly_owned_methods(name, constant
|
324
|
+
singleton_methods = compile_directly_owned_methods(name, singleton_class_of(constant), [:public])
|
325
325
|
|
326
326
|
return if symbol_ignored?(name) && instance_methods.empty? && singleton_methods.empty?
|
327
327
|
|
@@ -400,7 +400,7 @@ module Tapioca
|
|
400
400
|
end
|
401
401
|
end.join(', ')
|
402
402
|
|
403
|
-
method_name
|
403
|
+
method_name = "#{'self.' if constant.singleton_class?}#{method_name}"
|
404
404
|
parameters = "(#{parameters})" if parameters != ""
|
405
405
|
|
406
406
|
indented("def #{method_name}#{parameters}; end")
|
@@ -543,6 +543,11 @@ module Tapioca
|
|
543
543
|
Module.instance_method(:name).bind(constant).call
|
544
544
|
end
|
545
545
|
|
546
|
+
sig { params(constant: BasicObject).returns(Class) }
|
547
|
+
def singleton_class_of(constant)
|
548
|
+
Object.instance_method(:singleton_class).bind(constant).call
|
549
|
+
end
|
550
|
+
|
546
551
|
sig { params(constant: Module).returns(T.nilable(String)) }
|
547
552
|
def name_of(constant)
|
548
553
|
name = name_of_proxy_target(constant)
|
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.2.
|
4
|
+
version: 0.2.4
|
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: 2019-10
|
14
|
+
date: 2019-12-10 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: pry
|