tapioca 0.2.8 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/tapioca.rb +11 -9
- data/lib/tapioca/cli.rb +13 -13
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +8 -16
- data/lib/tapioca/config.rb +34 -0
- data/lib/tapioca/config_builder.rb +62 -0
- data/lib/tapioca/gemfile.rb +13 -1
- data/lib/tapioca/generator.rb +22 -52
- data/lib/tapioca/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbb47e890388bfea9f9413a20cc6768d16175f9b962291d04d35eaaf3e94e109
|
4
|
+
data.tar.gz: eb041465b3237e6f87872c1aeaf172fb0c28ebb445f1855f837dd1759888362f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 703f76a6df75973603aebc4e2589a81d124b98196372dccc170da3e720dd02676749a6439e9538862a327945b182f71f826beecd1b9b99d032c4e6067b9afb66
|
7
|
+
data.tar.gz: 7a86ffe6ef50693f8f22fdc9bd4c853b0d7d5d4296d85f6ba7e0207471f6a1654d561f9a97a148e48e8bec80559c0c68c9afd95374e1b5a40ec2785172e7e43c
|
data/lib/tapioca.rb
CHANGED
@@ -28,12 +28,14 @@ rescue
|
|
28
28
|
nil
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
require "tapioca/loader"
|
32
|
+
require "tapioca/constant_locator"
|
33
|
+
require "tapioca/config"
|
34
|
+
require "tapioca/config_builder"
|
35
|
+
require "tapioca/generator"
|
36
|
+
require "tapioca/cli"
|
37
|
+
require "tapioca/gemfile"
|
38
|
+
require "tapioca/compilers/symbol_table_compiler"
|
39
|
+
require "tapioca/compilers/symbol_table/symbol_generator"
|
40
|
+
require "tapioca/compilers/symbol_table/symbol_loader"
|
41
|
+
require "tapioca/version"
|
data/lib/tapioca/cli.rb
CHANGED
@@ -13,34 +13,36 @@ module Tapioca
|
|
13
13
|
desc: "A file to be required before Bundler.require is called"
|
14
14
|
class_option :postrequire,
|
15
15
|
aliases: ["--post", "-a"],
|
16
|
-
default: Generator::DEFAULT_POSTREQUIRE,
|
17
16
|
banner: "file",
|
18
17
|
desc: "A file to be required after Bundler.require is called"
|
19
18
|
class_option :outdir,
|
20
19
|
aliases: ["--out", "-o"],
|
21
|
-
default: Generator::DEFAULT_OUTDIR,
|
22
20
|
banner: "directory",
|
23
21
|
desc: "The output directory for generated RBI files"
|
24
22
|
class_option :generate_command,
|
25
23
|
aliases: ["--cmd", "-c"],
|
26
24
|
banner: "command",
|
27
25
|
desc: "The command to run to regenerate RBI files"
|
26
|
+
class_option :exclude,
|
27
|
+
aliases: ["-x"],
|
28
|
+
type: :array,
|
29
|
+
banner: "gem [gem ...]",
|
30
|
+
desc: "Excludes the given gem(s) from RBI generation"
|
28
31
|
class_option :typed_overrides,
|
29
32
|
aliases: ["--typed", "-t"],
|
30
33
|
type: :hash,
|
31
|
-
|
32
|
-
banner: "gem:level",
|
34
|
+
banner: "gem:level [gem:level ...]",
|
33
35
|
desc: "Overrides for typed sigils for generated gem RBIs"
|
34
36
|
|
35
37
|
desc "init", "initializes folder structure"
|
36
38
|
def init
|
37
|
-
create_file(
|
39
|
+
create_file(Config::SORBET_CONFIG, skip: true) do
|
38
40
|
<<~CONTENT
|
39
41
|
--dir
|
40
42
|
.
|
41
43
|
CONTENT
|
42
44
|
end
|
43
|
-
create_file(
|
45
|
+
create_file(Config::DEFAULT_POSTREQUIRE, skip: true) do
|
44
46
|
<<~CONTENT
|
45
47
|
# frozen_string_literal: true
|
46
48
|
# typed: false
|
@@ -65,14 +67,12 @@ module Tapioca
|
|
65
67
|
end
|
66
68
|
|
67
69
|
no_commands do
|
70
|
+
def self.exit_on_failure?
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
68
74
|
def generator
|
69
|
-
@generator ||= Generator.new(
|
70
|
-
outdir: options[:outdir],
|
71
|
-
prerequire: options[:prerequire],
|
72
|
-
postrequire: options[:postrequire],
|
73
|
-
command: options[:generate_command],
|
74
|
-
typed_overrides: options[:typed_overrides]
|
75
|
-
)
|
75
|
+
@generator ||= Generator.new(ConfigBuilder.from_options(options))
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
@@ -137,14 +137,11 @@ module Tapioca
|
|
137
137
|
end
|
138
138
|
def compile_object(name, value)
|
139
139
|
return if symbol_ignored?(name)
|
140
|
-
indented("#{name} = T.let(T.unsafe(nil), #{type_name_of(value)})")
|
141
|
-
end
|
142
|
-
|
143
|
-
sig { params(value: BasicObject).returns(String).checked(:never) }
|
144
|
-
def type_name_of(value)
|
145
140
|
klass = class_of(value)
|
141
|
+
return if name_of(klass)&.start_with?("T::Types::", "T::Private::")
|
146
142
|
|
147
|
-
public_module?(klass) && name_of(klass) || "T.untyped"
|
143
|
+
type_name = public_module?(klass) && name_of(klass) || "T.untyped"
|
144
|
+
indented("#{name} = T.let(T.unsafe(nil), #{type_name})")
|
148
145
|
end
|
149
146
|
|
150
147
|
sig { params(name: String, constant: Module).returns(T.nilable(String)) }
|
@@ -289,7 +286,7 @@ module Tapioca
|
|
289
286
|
end
|
290
287
|
|
291
288
|
prepends = prepend
|
292
|
-
.select(
|
289
|
+
.select { |mod| (name = name_of(mod)) && !name.start_with?("T::") }
|
293
290
|
.select(&method(:public_module?))
|
294
291
|
.map do |mod|
|
295
292
|
# TODO: Sorbet currently does not handle prepend
|
@@ -299,14 +296,14 @@ module Tapioca
|
|
299
296
|
end
|
300
297
|
|
301
298
|
includes = include
|
302
|
-
.select(
|
299
|
+
.select { |mod| (name = name_of(mod)) && !name.start_with?("T::") }
|
303
300
|
.select(&method(:public_module?))
|
304
301
|
.map do |mod|
|
305
302
|
indented("include(#{qualified_name_of(mod)})")
|
306
303
|
end
|
307
304
|
|
308
305
|
extends = extend
|
309
|
-
.select(
|
306
|
+
.select { |mod| (name = name_of(mod)) && !name.start_with?("T::") }
|
310
307
|
.select(&method(:public_module?))
|
311
308
|
.map do |mod|
|
312
309
|
indented("extend(#{qualified_name_of(mod)})")
|
@@ -424,11 +421,6 @@ module Tapioca
|
|
424
421
|
SymbolLoader.ignore_symbol?(symbol_name)
|
425
422
|
end
|
426
423
|
|
427
|
-
sig { params(path: String).returns(T::Boolean) }
|
428
|
-
def path_in_gem?(path)
|
429
|
-
File.realpath(path).start_with?(gem.full_gem_path)
|
430
|
-
end
|
431
|
-
|
432
424
|
SPECIAL_METHOD_NAMES = %w[! ~ +@ ** -@ * / % + - << >> & | ^ < <= => > >= == === != =~ !~ <=> [] []= `]
|
433
425
|
|
434
426
|
sig { params(name: String).returns(T::Boolean) }
|
@@ -462,7 +454,7 @@ module Tapioca
|
|
462
454
|
source_location = method.source_location&.first
|
463
455
|
return false if source_location.nil?
|
464
456
|
|
465
|
-
|
457
|
+
gem.contains_path?(source_location)
|
466
458
|
end
|
467
459
|
|
468
460
|
sig { params(constant: Module, strict: T::Boolean).returns(T::Boolean) }
|
@@ -473,7 +465,7 @@ module Tapioca
|
|
473
465
|
return !strict if files.empty?
|
474
466
|
|
475
467
|
files.any? do |file|
|
476
|
-
|
468
|
+
gem.contains_path?(file)
|
477
469
|
end
|
478
470
|
end
|
479
471
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Tapioca
|
5
|
+
class Config < T::Struct
|
6
|
+
extend(T::Sig)
|
7
|
+
|
8
|
+
const(:outdir, String)
|
9
|
+
const(:prerequire, T.nilable(String))
|
10
|
+
const(:postrequire, String)
|
11
|
+
const(:generate_command, String)
|
12
|
+
const(:exclude, T::Array[String])
|
13
|
+
const(:typed_overrides, T::Hash[String, String])
|
14
|
+
|
15
|
+
sig { returns(Pathname) }
|
16
|
+
def outpath
|
17
|
+
@outpath ||= T.let(Pathname.new(outdir), T.nilable(Pathname))
|
18
|
+
T.must(@outpath)
|
19
|
+
end
|
20
|
+
|
21
|
+
private_class_method :new
|
22
|
+
|
23
|
+
CONFIG_FILE_PATH = "sorbet/tapioca/config.yml"
|
24
|
+
SORBET_CONFIG = "sorbet/config"
|
25
|
+
|
26
|
+
DEFAULT_POSTREQUIRE = "sorbet/tapioca/require.rb"
|
27
|
+
DEFAULT_OUTDIR = "sorbet/rbi/gems"
|
28
|
+
DEFAULT_OVERRIDES = T.let({
|
29
|
+
# ActiveSupport overrides some core methods with different signatures
|
30
|
+
# so we generate a typed: false RBI for it to suppress errors
|
31
|
+
"activesupport" => "false",
|
32
|
+
}.freeze, T::Hash[String, String])
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Tapioca
|
5
|
+
class ConfigBuilder
|
6
|
+
class << self
|
7
|
+
extend(T::Sig)
|
8
|
+
|
9
|
+
sig { params(options: T::Hash[String, T.untyped]).returns(Config) }
|
10
|
+
def from_options(options)
|
11
|
+
Config.from_hash(
|
12
|
+
merge_options(default_options, config_options, options)
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
19
|
+
def config_options
|
20
|
+
if File.exist?(Config::CONFIG_FILE_PATH)
|
21
|
+
YAML.load_file(Config::CONFIG_FILE_PATH, fallback: {})
|
22
|
+
else
|
23
|
+
{}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
28
|
+
def default_options
|
29
|
+
DEFAULT_OPTIONS
|
30
|
+
end
|
31
|
+
|
32
|
+
sig { returns(String) }
|
33
|
+
def default_command
|
34
|
+
command = File.basename($PROGRAM_NAME)
|
35
|
+
args = ARGV.join(" ")
|
36
|
+
|
37
|
+
"#{command} #{args}".strip
|
38
|
+
end
|
39
|
+
|
40
|
+
sig { params(options: T::Hash[String, T.untyped]).returns(T::Hash[String, T.untyped]) }
|
41
|
+
def merge_options(*options)
|
42
|
+
options.each_with_object({}) do |option, result|
|
43
|
+
result.merge!(option) do |_, this_val, other_val|
|
44
|
+
if this_val.is_a?(Hash) && other_val.is_a?(Hash)
|
45
|
+
this_val.merge(other_val)
|
46
|
+
else
|
47
|
+
other_val
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
DEFAULT_OPTIONS = T.let({
|
55
|
+
"postrequire" => Config::DEFAULT_POSTREQUIRE,
|
56
|
+
"outdir" => Config::DEFAULT_OUTDIR,
|
57
|
+
"generate_command" => default_command,
|
58
|
+
"exclude" => [],
|
59
|
+
"typed_overrides" => Config::DEFAULT_OVERRIDES,
|
60
|
+
}.freeze, T::Hash[String, T.untyped])
|
61
|
+
end
|
62
|
+
end
|
data/lib/tapioca/gemfile.rb
CHANGED
@@ -88,7 +88,7 @@ module Tapioca
|
|
88
88
|
sig { params(spec: Spec).void }
|
89
89
|
def initialize(spec)
|
90
90
|
@spec = T.let(spec, Tapioca::Gemfile::Spec)
|
91
|
-
real_gem_path =
|
91
|
+
real_gem_path = to_realpath(@spec.full_gem_path)
|
92
92
|
@full_gem_path = T.let(real_gem_path, String)
|
93
93
|
end
|
94
94
|
|
@@ -119,8 +119,20 @@ module Tapioca
|
|
119
119
|
"#{name}@#{version}.rbi"
|
120
120
|
end
|
121
121
|
|
122
|
+
sig { params(path: String).returns(T::Boolean) }
|
123
|
+
def contains_path?(path)
|
124
|
+
to_realpath(path).start_with?(full_gem_path)
|
125
|
+
end
|
126
|
+
|
122
127
|
private
|
123
128
|
|
129
|
+
sig { params(path: T.any(String, Pathname)).returns(String) }
|
130
|
+
def to_realpath(path)
|
131
|
+
path_string = path.to_s
|
132
|
+
path_string = File.realpath(path_string) if File.exist?(path_string)
|
133
|
+
path_string
|
134
|
+
end
|
135
|
+
|
124
136
|
sig { returns(T::Boolean) }
|
125
137
|
def gem_ignored?
|
126
138
|
IGNORED_GEMS.include?(name)
|
data/lib/tapioca/generator.rb
CHANGED
@@ -8,41 +8,16 @@ module Tapioca
|
|
8
8
|
class Generator < ::Thor::Shell::Color
|
9
9
|
extend(T::Sig)
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
DEFAULT_OUTDIR = "sorbet/rbi/gems"
|
14
|
-
DEFAULT_OVERRIDES = T.let({
|
15
|
-
# ActiveSupport overrides some core methods with different signatures
|
16
|
-
# so we generate a typed: false RBI for it to suppress errors
|
17
|
-
"activesupport" => "false",
|
18
|
-
}.freeze, T::Hash[String, String])
|
19
|
-
|
20
|
-
sig { returns(Pathname) }
|
21
|
-
attr_reader :outdir
|
22
|
-
sig { returns(T.nilable(String)) }
|
23
|
-
attr_reader :prerequire
|
24
|
-
sig { returns(T.nilable(String)) }
|
25
|
-
attr_reader :postrequire
|
26
|
-
sig { returns(String) }
|
27
|
-
attr_reader :command
|
28
|
-
sig { returns(T::Hash[String, String]) }
|
29
|
-
attr_reader :typed_overrides
|
11
|
+
sig { returns(Config) }
|
12
|
+
attr_reader :config
|
30
13
|
|
31
14
|
sig do
|
32
15
|
params(
|
33
|
-
|
34
|
-
prerequire: T.nilable(String),
|
35
|
-
postrequire: T.nilable(String),
|
36
|
-
command: T.nilable(String),
|
37
|
-
typed_overrides: T.nilable(T::Hash[String, String])
|
16
|
+
config: Config
|
38
17
|
).void
|
39
18
|
end
|
40
|
-
def initialize(
|
41
|
-
@
|
42
|
-
@prerequire = T.let(prerequire, T.nilable(String))
|
43
|
-
@postrequire = T.let(postrequire || DEFAULT_POSTREQUIRE, T.nilable(String))
|
44
|
-
@command = T.let(command || default_command, String)
|
45
|
-
@typed_overrides = T.let(typed_overrides || {}, T::Hash[String, String])
|
19
|
+
def initialize(config)
|
20
|
+
@config = config
|
46
21
|
@bundle = T.let(nil, T.nilable(Gemfile))
|
47
22
|
@loader = T.let(nil, T.nilable(Loader))
|
48
23
|
@compiler = T.let(nil, T.nilable(Compilers::SymbolTableCompiler))
|
@@ -55,13 +30,15 @@ module Tapioca
|
|
55
30
|
def build_gem_rbis(gem_names)
|
56
31
|
require_gem_file
|
57
32
|
|
58
|
-
gems_to_generate(gem_names)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
33
|
+
gems_to_generate(gem_names)
|
34
|
+
.reject { |gem| config.exclude.include?(gem.name) }
|
35
|
+
.each do |gem|
|
36
|
+
say("Processing '#{gem.name}' gem:", :green)
|
37
|
+
indent do
|
38
|
+
compile_rbi(gem)
|
39
|
+
puts
|
40
|
+
end
|
63
41
|
end
|
64
|
-
end
|
65
42
|
|
66
43
|
say("All operations performed in working directory.", [:green, :bold])
|
67
44
|
say("Please review changes and commit them.", [:green, :bold])
|
@@ -86,14 +63,6 @@ module Tapioca
|
|
86
63
|
|
87
64
|
private
|
88
65
|
|
89
|
-
sig { returns(String) }
|
90
|
-
def default_command
|
91
|
-
command = File.basename($PROGRAM_NAME)
|
92
|
-
args = ARGV.join(" ")
|
93
|
-
|
94
|
-
"#{command} #{args}"
|
95
|
-
end
|
96
|
-
|
97
66
|
sig { returns(Gemfile) }
|
98
67
|
def bundle
|
99
68
|
@bundle ||= Gemfile.new
|
@@ -112,14 +81,14 @@ module Tapioca
|
|
112
81
|
sig { void }
|
113
82
|
def require_gem_file
|
114
83
|
say("Requiring all gems to prepare for compiling... ")
|
115
|
-
loader.load_bundle(prerequire, postrequire)
|
84
|
+
loader.load_bundle(config.prerequire, config.postrequire)
|
116
85
|
say(" Done", :green)
|
117
86
|
puts
|
118
87
|
end
|
119
88
|
|
120
89
|
sig { returns(T::Hash[String, String]) }
|
121
90
|
def existing_rbis
|
122
|
-
@existing_rbis ||= Pathname.glob((
|
91
|
+
@existing_rbis ||= Pathname.glob((config.outpath / "*@*.rbi").to_s)
|
123
92
|
.map { |f| f.basename(".*").to_s.split('@') }
|
124
93
|
.to_h
|
125
94
|
end
|
@@ -127,13 +96,14 @@ module Tapioca
|
|
127
96
|
sig { returns(T::Hash[String, String]) }
|
128
97
|
def expected_rbis
|
129
98
|
@expected_rbis ||= bundle.dependencies
|
99
|
+
.reject { |gem| config.exclude.include?(gem.name) }
|
130
100
|
.map { |gem| [gem.name, gem.version.to_s] }
|
131
101
|
.to_h
|
132
102
|
end
|
133
103
|
|
134
104
|
sig { params(gem_name: String, version: String).returns(Pathname) }
|
135
105
|
def rbi_filename(gem_name, version)
|
136
|
-
|
106
|
+
config.outpath / "#{gem_name}@#{version}.rbi"
|
137
107
|
end
|
138
108
|
|
139
109
|
sig { params(gem_name: String).returns(Pathname) }
|
@@ -280,18 +250,18 @@ module Tapioca
|
|
280
250
|
gem_name = set_color(gem.name, :yellow, :bold)
|
281
251
|
say("Compiling #{gem_name}, this may take a few seconds... ")
|
282
252
|
|
283
|
-
typed_sigil = typed_overrides[gem.name] ||
|
253
|
+
typed_sigil = config.typed_overrides[gem.name] || "true"
|
284
254
|
|
285
255
|
content = compiler.compile(gem)
|
286
|
-
content.prepend(rbi_header(
|
256
|
+
content.prepend(rbi_header(config.generate_command, typed_sigil))
|
287
257
|
|
288
|
-
FileUtils.mkdir_p(outdir)
|
289
|
-
filename =
|
258
|
+
FileUtils.mkdir_p(config.outdir)
|
259
|
+
filename = config.outpath / gem.rbi_file_name
|
290
260
|
File.write(filename.to_s, content)
|
291
261
|
|
292
262
|
say("Done", :green)
|
293
263
|
|
294
|
-
Pathname.glob((
|
264
|
+
Pathname.glob((config.outpath / "#{gem.name}@*.rbi").to_s) do |file|
|
295
265
|
remove(file) unless file.basename.to_s == gem.rbi_file_name
|
296
266
|
end
|
297
267
|
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
|
+
version: 0.3.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-03-
|
14
|
+
date: 2020-03-26 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: pry
|
@@ -142,6 +142,8 @@ files:
|
|
142
142
|
- lib/tapioca/compilers/symbol_table/symbol_generator.rb
|
143
143
|
- lib/tapioca/compilers/symbol_table/symbol_loader.rb
|
144
144
|
- lib/tapioca/compilers/symbol_table_compiler.rb
|
145
|
+
- lib/tapioca/config.rb
|
146
|
+
- lib/tapioca/config_builder.rb
|
145
147
|
- lib/tapioca/constant_locator.rb
|
146
148
|
- lib/tapioca/gemfile.rb
|
147
149
|
- lib/tapioca/generator.rb
|