tapioca 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 81caba98bdbde19ffbb78a1860f994a8b5c39a82dcd48832ce0daabcd9f6d77b
4
- data.tar.gz: 803fe5c9b0ac3838f984455adf53fd2a470e13a877ea218d80bb74b2c309afbe
3
+ metadata.gz: 6aedd5a0415cca7e554021e114401254561649803acceed6caaa2cb24b9b4c8c
4
+ data.tar.gz: 376290c5b3cad6f082e9fc186cbb2ed32a9bb239c5c37bc8f9f464c78a2d951e
5
5
  SHA512:
6
- metadata.gz: 75c2b49c410a6b9f558470a5ab6b59f464b41e4b03a88344fd8967d06e3b36b8b29669bd92c8103d106e234a91fb4ead51d617a365059342e03542cfe113c497
7
- data.tar.gz: 4261f1657b92a65ba119f95e1e9be3211af056fe2ba5a5b225b0d920a2adda1fd7619d9e21bb8e034c3946b4cb931d8ef45beebd3bb429c2c5d8446bce09efa8
6
+ metadata.gz: e65c8822f8312788075a84f24d5b9c95221bba2ced2dd877f150a377696fd70eff96bc936fdd3cf482fa6d4ac1b2d86a0201ed91c386c1ee1ce0bd19e8defd9c
7
+ data.tar.gz: bace8a6fca5ca72789c5fdfa121fb7b30bf415e9f04d6c715f43237f4d022c4507a6d6182161c4928a7258f9759c957a22c2559cc73ebc56d093f5864dcd872f
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/Shopify/tapioca.svg?branch=master)](https://travis-ci.org/Shopify/tapioca)
4
4
 
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.
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
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
8
 
@@ -27,7 +27,7 @@ from (pry):3:in `__pry__`
27
27
  => BetterHtml::Parser
28
28
  ```
29
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.
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
31
 
32
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
33
 
@@ -50,6 +50,7 @@ Commands:
50
50
  tapioca help [COMMAND] # Describe available commands or one specific command
51
51
  tapioca init # initializes folder structure
52
52
  tapioca sync # sync RBIs to Gemfile
53
+ tapioca todo # generate the list of unresolved constants
53
54
 
54
55
  Options:
55
56
  --pre, -b, [--prerequire=file] # A file to be required before Bundler.require is called
@@ -80,6 +81,12 @@ Command: `tapioca sync`
80
81
 
81
82
  This will sync the RBIs with the gems in the Gemfile and will add, update, and remove RBIs as necessary.
82
83
 
84
+ ### Generate the list of all unresolved constants
85
+
86
+ Command: `tapioca todo`
87
+
88
+ This will generate the file `sorbet/rbi/todo.rbi` defining all unresolved constants as empty modules.
89
+
83
90
  ### Flags
84
91
 
85
92
  - `--prerequire [file]`: A file to be required before `Bundler.require` is called.
@@ -35,7 +35,9 @@ require "tapioca/config_builder"
35
35
  require "tapioca/generator"
36
36
  require "tapioca/cli"
37
37
  require "tapioca/gemfile"
38
+ require "tapioca/compilers/sorbet"
38
39
  require "tapioca/compilers/symbol_table_compiler"
39
40
  require "tapioca/compilers/symbol_table/symbol_generator"
40
41
  require "tapioca/compilers/symbol_table/symbol_loader"
42
+ require "tapioca/compilers/todos_compiler"
41
43
  require "tapioca/version"
@@ -52,6 +52,13 @@ module Tapioca
52
52
  end
53
53
  end
54
54
 
55
+ desc "todo", "generate the list of unresolved constants"
56
+ def todo
57
+ Tapioca.silence_warnings do
58
+ generator.build_todos
59
+ end
60
+ end
61
+
55
62
  desc "generate [gem...]", "generate RBIs from gems"
56
63
  def generate(*gems)
57
64
  Tapioca.silence_warnings do
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ require 'pathname'
5
+ require 'shellwords'
6
+
7
+ module Tapioca
8
+ module Compilers
9
+ module Sorbet
10
+ SORBET = Pathname.new(Gem::Specification.find_by_name("sorbet-static").full_gem_path) / "libexec" / "sorbet"
11
+
12
+ class << self
13
+ extend(T::Sig)
14
+
15
+ sig { params(args: String).returns(String) }
16
+ def run(*args)
17
+ IO.popen(
18
+ [
19
+ sorbet_path,
20
+ "--quiet",
21
+ *args,
22
+ ].join(' '),
23
+ err: "/dev/null"
24
+ ).read
25
+ end
26
+
27
+ sig { returns(String) }
28
+ def sorbet_path
29
+ SORBET.to_s.shellescape
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -287,6 +287,7 @@ module Tapioca
287
287
  end
288
288
 
289
289
  prepends = prepend
290
+ .reverse
290
291
  .select { |mod| (name = name_of(mod)) && !name.start_with?("T::") }
291
292
  .select(&method(:public_module?))
292
293
  .map do |mod|
@@ -297,6 +298,7 @@ module Tapioca
297
298
  end
298
299
 
299
300
  includes = include
301
+ .reverse
300
302
  .select { |mod| (name = name_of(mod)) && !name.start_with?("T::") }
301
303
  .select(&method(:public_module?))
302
304
  .map do |mod|
@@ -304,6 +306,7 @@ module Tapioca
304
306
  end
305
307
 
306
308
  extends = extend
309
+ .reverse
307
310
  .select { |mod| (name = name_of(mod)) && !name.start_with?("T::") }
308
311
  .select(&method(:public_module?))
309
312
  .map do |mod|
@@ -2,16 +2,12 @@
2
2
  # typed: true
3
3
 
4
4
  require 'json'
5
- require 'pathname'
6
5
  require 'tempfile'
7
- require 'shellwords'
8
6
 
9
7
  module Tapioca
10
8
  module Compilers
11
9
  module SymbolTable
12
10
  module SymbolLoader
13
- SORBET = Pathname.new(Gem::Specification.find_by_name("sorbet-static").full_gem_path) / "libexec" / "sorbet"
14
-
15
11
  class << self
16
12
  extend(T::Sig)
17
13
 
@@ -53,22 +49,7 @@ module Tapioca
53
49
  end
54
50
 
55
51
  def symbol_table_json_from(input, table_type: "symbol-table-json")
56
- IO.popen(
57
- [
58
- sorbet_path,
59
- # We don't want to pick up any sorbet/config files in cwd
60
- "--no-config",
61
- "--print=#{table_type}",
62
- "--quiet",
63
- input,
64
- ].join(' '),
65
- err: "/dev/null"
66
- ).read
67
- end
68
-
69
- sig { returns(String) }
70
- def sorbet_path
71
- SORBET.to_s.shellescape
52
+ Tapioca::Compilers::Sorbet.run("--no-config", "--print=#{table_type}", input)
72
53
  end
73
54
  end
74
55
 
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ # typed: strong
3
+
4
+ module Tapioca
5
+ module Compilers
6
+ # Taken from https://github.com/sorbet/sorbet/blob/master/gems/sorbet/lib/todo-rbi.rb
7
+ class TodosCompiler
8
+ extend(T::Sig)
9
+
10
+ sig do
11
+ returns(String)
12
+ end
13
+ def compile
14
+ list_todos.each_line.map do |line|
15
+ next if line.include?("<") || line.include?("class_of")
16
+ "module #{line.strip.gsub('T.untyped::', '')}; end"
17
+ end.compact.join("\n")
18
+ end
19
+
20
+ private
21
+
22
+ sig { returns(String) }
23
+ def list_todos
24
+ Tapioca::Compilers::Sorbet.run(
25
+ "--print=missing-constants",
26
+ "--stdout-hup-hack",
27
+ "--no-error-count"
28
+ ).strip
29
+ end
30
+ end
31
+ end
32
+ end
@@ -11,11 +11,12 @@ module Tapioca
11
11
  const(:generate_command, String)
12
12
  const(:exclude, T::Array[String])
13
13
  const(:typed_overrides, T::Hash[String, String])
14
+ const(:todos_path, String)
14
15
 
15
16
  sig { returns(Pathname) }
16
17
  def outpath
17
- @outpath ||= T.let(Pathname.new(outdir), T.nilable(Pathname))
18
- T.must(@outpath)
18
+ @outpath = T.let(@outpath, T.nilable(Pathname))
19
+ @outpath ||= Pathname.new(outdir)
19
20
  end
20
21
 
21
22
  private_class_method :new
@@ -24,11 +25,13 @@ module Tapioca
24
25
  SORBET_CONFIG = "sorbet/config"
25
26
 
26
27
  DEFAULT_POSTREQUIRE = "sorbet/tapioca/require.rb"
27
- DEFAULT_OUTDIR = "sorbet/rbi/gems"
28
+ DEFAULT_RBIDIR = "sorbet/rbi"
29
+ DEFAULT_OUTDIR = T.let("#{DEFAULT_RBIDIR}/gems", String)
28
30
  DEFAULT_OVERRIDES = T.let({
29
31
  # ActiveSupport overrides some core methods with different signatures
30
32
  # so we generate a typed: false RBI for it to suppress errors
31
33
  "activesupport" => "false",
32
34
  }.freeze, T::Hash[String, String])
35
+ DEFAULT_TODOSPATH = T.let("#{DEFAULT_RBIDIR}/todo.rbi", String)
33
36
  end
34
37
  end
@@ -1,6 +1,8 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'yaml'
5
+
4
6
  module Tapioca
5
7
  class ConfigBuilder
6
8
  class << self
@@ -57,6 +59,7 @@ module Tapioca
57
59
  "generate_command" => default_command,
58
60
  "exclude" => [],
59
61
  "typed_overrides" => Config::DEFAULT_OVERRIDES,
62
+ "todos_path" => Config::DEFAULT_TODOSPATH,
60
63
  }.freeze, T::Hash[String, T.untyped])
61
64
  end
62
65
  end
@@ -44,6 +44,38 @@ module Tapioca
44
44
  say("Please review changes and commit them.", [:green, :bold])
45
45
  end
46
46
 
47
+ sig { void }
48
+ def build_todos
49
+ todos_path = config.todos_path
50
+ compiler = Compilers::TodosCompiler.new
51
+ name = set_color(todos_path, :yellow, :bold)
52
+ say("Compiling #{name}, this may take a few seconds... ")
53
+
54
+ # Clean all existing unresolved constants before regenerating the list
55
+ # so Sorbet won't grab them as already resolved.
56
+ File.delete(todos_path) if File.exist?(todos_path)
57
+
58
+ rbi_string = compiler.compile
59
+ if rbi_string.empty?
60
+ say("Nothing to do", :green)
61
+ return
62
+ end
63
+
64
+ content = String.new
65
+ content << rbi_header(config.generate_command, "false")
66
+ content << rbi_string
67
+ content << "\n"
68
+
69
+ outdir = File.dirname(todos_path)
70
+ FileUtils.mkdir_p(outdir)
71
+ File.write(todos_path, content)
72
+
73
+ say("Done", :green)
74
+
75
+ say("All unresolved constants have been written to #{name}.", [:green, :bold])
76
+ say("Please review changes and commit them.", [:green, :bold])
77
+ end
78
+
47
79
  sig { void }
48
80
  def sync_rbis_with_gemfile
49
81
  anything_done = [
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- VERSION = "0.3.1"
5
+ VERSION = "0.4.0"
6
6
  end
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.3.1
4
+ version: 0.4.0
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-04-29 00:00:00.000000000 Z
14
+ date: 2020-05-08 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: pry
@@ -139,9 +139,11 @@ files:
139
139
  - exe/tapioca
140
140
  - lib/tapioca.rb
141
141
  - lib/tapioca/cli.rb
142
+ - lib/tapioca/compilers/sorbet.rb
142
143
  - lib/tapioca/compilers/symbol_table/symbol_generator.rb
143
144
  - lib/tapioca/compilers/symbol_table/symbol_loader.rb
144
145
  - lib/tapioca/compilers/symbol_table_compiler.rb
146
+ - lib/tapioca/compilers/todos_compiler.rb
145
147
  - lib/tapioca/config.rb
146
148
  - lib/tapioca/config_builder.rb
147
149
  - lib/tapioca/constant_locator.rb