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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3bd7a0a3f7cb0bbb9ed158cd446ae76a2d89f5872c620f1dce5ecc41e898d330
4
- data.tar.gz: e66cc1b09f4c7b47bf493a9a1966c9cc6dd05c2f12f4d29e6a1900949554c3b0
3
+ metadata.gz: fbb47e890388bfea9f9413a20cc6768d16175f9b962291d04d35eaaf3e94e109
4
+ data.tar.gz: eb041465b3237e6f87872c1aeaf172fb0c28ebb445f1855f837dd1759888362f
5
5
  SHA512:
6
- metadata.gz: 8e12cfbd5404421a8ab57a0c85c8ee503bc0f87cfc569edac3e97da1f86d420aa137a91c79dae3d86220cdd5ea817476387613068e05fd7986fa8284e2b5da97
7
- data.tar.gz: 85603c8f06e73f214dac2c31b389ea1e4ac63c513e209da649a657e33951e7d2d0c7f9208a5c4eee597ba953937397bc3d630a4a0a01a29c092ed60d7aa935c5
6
+ metadata.gz: 703f76a6df75973603aebc4e2589a81d124b98196372dccc170da3e720dd02676749a6439e9538862a327945b182f71f826beecd1b9b99d032c4e6067b9afb66
7
+ data.tar.gz: 7a86ffe6ef50693f8f22fdc9bd4c853b0d7d5d4296d85f6ba7e0207471f6a1654d561f9a97a148e48e8bec80559c0c68c9afd95374e1b5a40ec2785172e7e43c
@@ -28,12 +28,14 @@ rescue
28
28
  nil
29
29
  end
30
30
 
31
- require_relative "tapioca/loader"
32
- require_relative "tapioca/constant_locator"
33
- require_relative "tapioca/generator"
34
- require_relative "tapioca/cli"
35
- require_relative "tapioca/gemfile"
36
- require_relative "tapioca/compilers/symbol_table_compiler"
37
- require_relative "tapioca/compilers/symbol_table/symbol_generator"
38
- require_relative "tapioca/compilers/symbol_table/symbol_loader"
39
- require_relative "tapioca/version"
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"
@@ -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
- default: {},
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(Generator::SORBET_CONFIG, skip: true) do
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(Generator::DEFAULT_POSTREQUIRE, skip: true) do
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(&method(:name_of))
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(&method(:name_of))
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(&method(:name_of))
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
- path_in_gem?(source_location)
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
- path_in_gem?(file)
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
@@ -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 = File.realpath(@spec.full_gem_path.to_s)
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)
@@ -8,41 +8,16 @@ module Tapioca
8
8
  class Generator < ::Thor::Shell::Color
9
9
  extend(T::Sig)
10
10
 
11
- SORBET_CONFIG = "sorbet/config"
12
- DEFAULT_POSTREQUIRE = "sorbet/tapioca/require.rb"
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
- outdir: T.nilable(String),
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(outdir: nil, prerequire: nil, postrequire: nil, command: nil, typed_overrides: nil)
41
- @outdir = T.let(Pathname.new(outdir || DEFAULT_OUTDIR), Pathname)
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).map do |gem|
59
- say("Processing '#{gem.name}' gem:", :green)
60
- indent do
61
- compile_rbi(gem)
62
- puts
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((Pathname.new(outdir) / "*@*.rbi").to_s)
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
- outdir / "#{gem_name}@#{version}.rbi"
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] || DEFAULT_OVERRIDES[gem.name] || "true"
253
+ typed_sigil = config.typed_overrides[gem.name] || "true"
284
254
 
285
255
  content = compiler.compile(gem)
286
- content.prepend(rbi_header(command, typed_sigil))
256
+ content.prepend(rbi_header(config.generate_command, typed_sigil))
287
257
 
288
- FileUtils.mkdir_p(outdir)
289
- filename = outdir / gem.rbi_file_name
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((outdir / "#{gem.name}@*.rbi").to_s) do |file|
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
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- VERSION = "0.2.8"
5
+ VERSION = "0.3.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.2.8
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-24 00:00:00.000000000 Z
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