tapioca 0.1.5 → 0.2.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: 8843a601bd4e5a685e116ee6c85e4045d1373efa827a74d0a81fdfbf010e81b5
4
- data.tar.gz: 4692376ebaa71712f5979cf9dbdfe926556011ab49c237dde05c7ef59817da12
3
+ metadata.gz: 2940efd480d72f9450f46e91e6be68bb7f7a8fe84f22d090f7919a1b119a144e
4
+ data.tar.gz: c1820c41b279cd4691b610da32ec539e909578e4ea7c65314769ee128a72bf76
5
5
  SHA512:
6
- metadata.gz: bdb00333afc55d6de709d6f211859dee1e1c6ed04c7b535b32f1860f1fc2717293c68d3cf542dbfe36a26fb62c406d7a63de6f7296b50cebf2579984d3b3af1a
7
- data.tar.gz: d6199e46bf54ba1907186f27478449ba6431ec26b346028acff456dc54ea78ef58c18e6281901b9f6e1224e1cda0250ac7c66879b3286ff38cea407f6673475c
6
+ metadata.gz: 956798852b6962e0029ddcddb70e56595acb45f94d4d8d26b57635c90d175ed63fe77a3c5e223cadf9cc0ae780ceecb449163804771267db55f289c5e421e468
7
+ data.tar.gz: 663e38a25d3d0a6093c369fae234bc7daa49d17e618605db23328df4a2820d57245c040bcdb05b535c9abece857ce0e2ce6f6eb5710fb30f1c94643ad122e471
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Tapioca
2
2
 
3
- [![Build Status](https://travis-ci.com/Shopify/tapioca.svg?token=AuiMGLmuYDrK2mb81pyq&branch=master)](https://travis-ci.com/Shopify/tapioca)
3
+ [![Build Status](https://travis-ci.org/Shopify/tapioca.svg?branch=master)](https://travis-ci.org/Shopify/tapioca)
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
 
@@ -19,9 +19,9 @@ and do not forget to execute `tapioca` using `bundler`:
19
19
  ```shell
20
20
  $ bundle exec tapioca
21
21
  Commands:
22
- tapioca bundle # sync RBIs to Gemfile
23
22
  tapioca generate [gem...] # generate RBIs from gems
24
23
  tapioca help [COMMAND] # Describe available commands or one specific command
24
+ tapioca sync # sync RBIs to Gemfile
25
25
 
26
26
  Options:
27
27
  --pre, -b, [--prerequire=file] # A file to be required before Bundler.require is called
@@ -42,7 +42,7 @@ This will generate RBIs for the specified gems and place them in the RBI directo
42
42
 
43
43
  ### Generate for all gems in Gemfile
44
44
 
45
- Command: `tapioca bundle`
45
+ Command: `tapioca sync`
46
46
 
47
47
  This will sync the RBIs with the gems in the Gemfile and will add, update, and remove RBIs as necessary.
48
48
 
@@ -36,8 +36,8 @@ module Tapioca
36
36
  end
37
37
  end
38
38
 
39
- desc "bundle", "sync RBIs to Gemfile"
40
- def bundle
39
+ desc "sync", "sync RBIs to Gemfile"
40
+ def sync
41
41
  Tapioca.silence_warnings do
42
42
  generator.sync_rbis_with_gemfile
43
43
  end
@@ -131,11 +131,7 @@ module Tapioca
131
131
  def type_name_of(value)
132
132
  klass = class_of(value)
133
133
 
134
- type_name = public_module?(klass) && name_of(klass) || "T.untyped"
135
- # Range needs to be processed separately to be put in the T::Range[] form
136
- type_name = "T::Range[#{type_name_of(T.cast(value, T::Range[T.untyped]).first)}]" if klass == Range
137
-
138
- type_name
134
+ public_module?(klass) && name_of(klass) || "T.untyped"
139
135
  end
140
136
 
141
137
  sig { params(name: String, constant: Module).returns(T.nilable(String)) }
@@ -7,7 +7,15 @@ module Tapioca
7
7
  class Gemfile
8
8
  extend(T::Sig)
9
9
 
10
- Spec = T.type_alias(T.any(::Bundler::StubSpecification, ::Gem::Specification))
10
+ Spec = T.type_alias(
11
+ T.any(
12
+ T.all(
13
+ ::Bundler::StubSpecification,
14
+ ::Bundler::RemoteSpecification
15
+ ),
16
+ ::Gem::Specification
17
+ )
18
+ )
11
19
 
12
20
  sig { void }
13
21
  def initialize
@@ -37,17 +45,9 @@ module Tapioca
37
45
  dependencies.detect { |dep| dep.name == gem_name }
38
46
  end
39
47
 
40
- sig { params(initialize_file: T.nilable(String), require_file: T.nilable(String)).void }
41
- def require_bundle(initialize_file, require_file)
42
- require(initialize_file) if initialize_file && File.exist?(initialize_file)
43
-
44
- runtime = Bundler::Runtime.new(File.dirname(gemfile.path), definition)
45
- groups = Bundler.definition.groups
46
- runtime.setup(*groups).require(*groups)
47
-
48
- require(require_file) if require_file && File.exist?(require_file)
49
-
50
- load_rails_engines
48
+ sig { void }
49
+ def require
50
+ T.unsafe(runtime).setup(*groups).require(*groups)
51
51
  end
52
52
 
53
53
  private
@@ -55,14 +55,28 @@ module Tapioca
55
55
  sig { returns(File) }
56
56
  attr_reader(:gemfile, :lockfile)
57
57
 
58
+ sig { returns(Bundler::Runtime) }
59
+ def runtime
60
+ Bundler::Runtime.new(File.dirname(gemfile.path), definition)
61
+ end
62
+
63
+ sig { returns(T::Array[Symbol]) }
64
+ def groups
65
+ definition.groups
66
+ end
67
+
58
68
  sig { returns(Bundler::Definition) }
59
69
  def definition
60
70
  @definition ||= Bundler::Dsl.evaluate(gemfile, lockfile, {})
61
71
  end
62
72
 
73
+ IGNORED_GEMS = T.let(%w{
74
+ sorbet sorbet-static sorbet-runtime tapioca
75
+ }.freeze, T::Array[String])
76
+
63
77
  sig { params(spec: Spec).returns(T::Boolean) }
64
78
  def ignore_gem_spec?(spec)
65
- ["sorbet", "sorbet-static"].include?(spec.name) ||
79
+ IGNORED_GEMS.include?(spec.name) ||
66
80
  spec.full_gem_path.start_with?(gemfile_dir)
67
81
  end
68
82
 
@@ -71,45 +85,6 @@ module Tapioca
71
85
  File.expand_path(gemfile.path + "/..")
72
86
  end
73
87
 
74
- sig { returns(T::Array[T.untyped]) }
75
- def rails_engines
76
- engines = []
77
-
78
- return engines unless Object.const_defined?("Rails::Engine")
79
-
80
- base = Object.const_get("Rails::Engine")
81
- ObjectSpace.each_object(base.singleton_class) do |k|
82
- k = T.cast(k, Class)
83
- next if k.singleton_class?
84
- engines.unshift(k) unless k == base
85
- end
86
-
87
- engines.reject(&:abstract_railtie?)
88
- end
89
-
90
- sig { void }
91
- def load_rails_engines
92
- rails_engines.each do |engine|
93
- errored_files = []
94
-
95
- engine.config.eager_load_paths.each do |load_path|
96
- Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
97
- require(file)
98
- rescue LoadError, StandardError
99
- errored_files << file
100
- end
101
- end
102
-
103
- # Try files that have errored one more time
104
- # It might have been a load order problem
105
- errored_files.each do |file|
106
- require(file)
107
- rescue LoadError, StandardError
108
- nil
109
- end
110
- end
111
- end
112
-
113
88
  class Gem
114
89
  extend(T::Sig)
115
90
 
@@ -9,6 +9,11 @@ module Tapioca
9
9
  extend(T::Sig)
10
10
 
11
11
  DEFAULT_OUTDIR = "sorbet/rbi/gems"
12
+ DEFAULT_OVERRIDES = T.let({
13
+ # ActiveSupport overrides some core methods with different signatures
14
+ # so we generate a typed: false RBI for it to suppress errors
15
+ "activesupport" => "false",
16
+ }.freeze, T::Hash[String, String])
12
17
 
13
18
  sig { returns(Pathname) }
14
19
  attr_reader :outdir
@@ -37,6 +42,7 @@ module Tapioca
37
42
  @command = T.let(command || default_command, String)
38
43
  @typed_overrides = T.let(typed_overrides || {}, T::Hash[String, String])
39
44
  @bundle = T.let(nil, T.nilable(Gemfile))
45
+ @loader = T.let(nil, T.nilable(Loader))
40
46
  @compiler = T.let(nil, T.nilable(Compilers::SymbolTableCompiler))
41
47
  @existing_rbis = T.let(nil, T.nilable(T::Hash[String, String]))
42
48
  @expected_rbis = T.let(nil, T.nilable(T::Hash[String, String]))
@@ -91,6 +97,11 @@ module Tapioca
91
97
  @bundle ||= Gemfile.new
92
98
  end
93
99
 
100
+ sig { returns(Loader) }
101
+ def loader
102
+ @loader ||= Loader.new(bundle)
103
+ end
104
+
94
105
  sig { returns(Compilers::SymbolTableCompiler) }
95
106
  def compiler
96
107
  @compiler ||= Compilers::SymbolTableCompiler.new
@@ -99,7 +110,7 @@ module Tapioca
99
110
  sig { void }
100
111
  def require_gem_file
101
112
  say("Requiring all gems to prepare for compiling... ")
102
- bundle.require_bundle(prerequire, postrequire)
113
+ loader.load_bundle(prerequire, postrequire)
103
114
  say(" Done", :green)
104
115
  puts
105
116
  end
@@ -267,7 +278,7 @@ module Tapioca
267
278
  gem_name = set_color(gem.name, :yellow, :bold)
268
279
  say("Compiling #{gem_name}, this may take a few seconds... ")
269
280
 
270
- typed_sigil = typed_overrides.fetch(gem.name, "true")
281
+ typed_sigil = typed_overrides[gem.name] || DEFAULT_OVERRIDES[gem.name] || "true"
271
282
 
272
283
  content = compiler.compile(gem)
273
284
  content.prepend(rbi_header(command, typed_sigil))
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module Tapioca
5
+ class Loader
6
+ extend(T::Sig)
7
+
8
+ sig { params(gemfile: Tapioca::Gemfile).void }
9
+ def initialize(gemfile)
10
+ @gemfile = T.let(gemfile, Tapioca::Gemfile)
11
+ end
12
+
13
+ sig { params(initialize_file: T.nilable(String), require_file: T.nilable(String)).void }
14
+ def load_bundle(initialize_file, require_file)
15
+ require(initialize_file) if initialize_file && File.exist?(initialize_file)
16
+
17
+ load_rails
18
+ load_rake
19
+
20
+ require_bundle
21
+
22
+ require(require_file) if require_file && File.exist?(require_file)
23
+
24
+ load_rails_engines
25
+ end
26
+
27
+ private
28
+
29
+ sig { returns(Tapioca::Gemfile) }
30
+ attr_reader :gemfile
31
+
32
+ sig { void }
33
+ def require_bundle
34
+ gemfile.require
35
+ end
36
+
37
+ sig { returns(T::Array[T.untyped]) }
38
+ def rails_engines
39
+ engines = []
40
+
41
+ return engines unless Object.const_defined?("Rails::Engine")
42
+
43
+ base = Object.const_get("Rails::Engine")
44
+ ObjectSpace.each_object(base.singleton_class) do |k|
45
+ k = T.cast(k, Class)
46
+ next if k.singleton_class?
47
+ engines.unshift(k) unless k == base
48
+ end
49
+
50
+ engines.reject(&:abstract_railtie?)
51
+ end
52
+
53
+ sig { params(path: String).void }
54
+ def safe_require(path)
55
+ require path
56
+ rescue LoadError
57
+ nil
58
+ end
59
+
60
+ sig { void }
61
+ def load_rake
62
+ safe_require("rake")
63
+ end
64
+
65
+ sig { void }
66
+ def load_rails
67
+ return unless File.exist?("config/application.rb")
68
+
69
+ safe_require("rails")
70
+ safe_require("rails/generators/test_case")
71
+ safe_require("./config/application")
72
+ end
73
+
74
+ sig { void }
75
+ def load_rails_engines
76
+ rails_engines.each do |engine|
77
+ errored_files = []
78
+
79
+ engine.config.eager_load_paths.each do |load_path|
80
+ Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
81
+ require(file)
82
+ rescue LoadError, StandardError
83
+ errored_files << file
84
+ end
85
+ end
86
+
87
+ # Try files that have errored one more time
88
+ # It might have been a load order problem
89
+ errored_files.each do |file|
90
+ require(file)
91
+ rescue LoadError, StandardError
92
+ nil
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- VERSION = "0.1.5"
5
+ VERSION = "0.2.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.1.5
4
+ version: 0.2.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: 2019-07-24 00:00:00.000000000 Z
14
+ date: 2019-08-15 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: pry
@@ -33,14 +33,14 @@ dependencies:
33
33
  requirements:
34
34
  - - "~>"
35
35
  - !ruby/object:Gem::Version
36
- version: 0.4.4371
36
+ version: 0.4.4471
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - "~>"
42
42
  - !ruby/object:Gem::Version
43
- version: 0.4.4371
43
+ version: 0.4.4471
44
44
  - !ruby/object:Gem::Dependency
45
45
  name: sorbet-runtime
46
46
  requirement: !ruby/object:Gem::Requirement
@@ -187,6 +187,7 @@ files:
187
187
  - lib/tapioca/constant_locator.rb
188
188
  - lib/tapioca/gemfile.rb
189
189
  - lib/tapioca/generator.rb
190
+ - lib/tapioca/loader.rb
190
191
  - lib/tapioca/version.rb
191
192
  homepage: https://github.com/Shopify/tapioca
192
193
  licenses:
@@ -207,8 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
207
208
  - !ruby/object:Gem::Version
208
209
  version: '0'
209
210
  requirements: []
210
- rubyforge_project:
211
- rubygems_version: 2.7.6
211
+ rubygems_version: 3.0.3
212
212
  signing_key:
213
213
  specification_version: 4
214
214
  summary: A Ruby Interface file generator for gems, core types and the Ruby standard