spoom 1.5.4 → 1.6.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/lib/spoom/backtrace_filter/minitest.rb +2 -3
  3. data/lib/spoom/cli/deadcode.rb +1 -2
  4. data/lib/spoom/cli/helper.rb +36 -28
  5. data/lib/spoom/cli/srb/assertions.rb +48 -0
  6. data/lib/spoom/cli/srb/bump.rb +1 -2
  7. data/lib/spoom/cli/srb/sigs.rb +133 -18
  8. data/lib/spoom/cli/srb.rb +8 -4
  9. data/lib/spoom/cli.rb +1 -2
  10. data/lib/spoom/colors.rb +2 -6
  11. data/lib/spoom/context/bundle.rb +8 -9
  12. data/lib/spoom/context/exec.rb +2 -5
  13. data/lib/spoom/context/file_system.rb +12 -19
  14. data/lib/spoom/context/git.rb +14 -19
  15. data/lib/spoom/context/sorbet.rb +13 -26
  16. data/lib/spoom/context.rb +3 -7
  17. data/lib/spoom/coverage/d3/base.rb +6 -8
  18. data/lib/spoom/coverage/d3/circle_map.rb +6 -16
  19. data/lib/spoom/coverage/d3/pie.rb +14 -19
  20. data/lib/spoom/coverage/d3/timeline.rb +46 -47
  21. data/lib/spoom/coverage/d3.rb +2 -4
  22. data/lib/spoom/coverage/report.rb +38 -76
  23. data/lib/spoom/coverage/snapshot.rb +7 -13
  24. data/lib/spoom/coverage.rb +3 -5
  25. data/lib/spoom/deadcode/definition.rb +12 -14
  26. data/lib/spoom/deadcode/erb.rb +10 -8
  27. data/lib/spoom/deadcode/index.rb +19 -23
  28. data/lib/spoom/deadcode/indexer.rb +5 -6
  29. data/lib/spoom/deadcode/plugins/action_mailer.rb +2 -3
  30. data/lib/spoom/deadcode/plugins/action_mailer_preview.rb +2 -3
  31. data/lib/spoom/deadcode/plugins/actionpack.rb +4 -4
  32. data/lib/spoom/deadcode/plugins/active_model.rb +2 -3
  33. data/lib/spoom/deadcode/plugins/active_record.rb +2 -3
  34. data/lib/spoom/deadcode/plugins/active_support.rb +2 -1
  35. data/lib/spoom/deadcode/plugins/base.rb +29 -32
  36. data/lib/spoom/deadcode/plugins/graphql.rb +2 -3
  37. data/lib/spoom/deadcode/plugins/minitest.rb +4 -4
  38. data/lib/spoom/deadcode/plugins/namespaces.rb +5 -5
  39. data/lib/spoom/deadcode/plugins/rails.rb +5 -5
  40. data/lib/spoom/deadcode/plugins/rubocop.rb +4 -4
  41. data/lib/spoom/deadcode/plugins/ruby.rb +3 -4
  42. data/lib/spoom/deadcode/plugins/sorbet.rb +12 -6
  43. data/lib/spoom/deadcode/plugins/thor.rb +2 -3
  44. data/lib/spoom/deadcode/plugins.rb +2 -4
  45. data/lib/spoom/deadcode/remover.rb +37 -59
  46. data/lib/spoom/deadcode/send.rb +2 -8
  47. data/lib/spoom/file_collector.rb +10 -18
  48. data/lib/spoom/file_tree.rb +31 -46
  49. data/lib/spoom/location.rb +9 -20
  50. data/lib/spoom/model/builder.rb +60 -15
  51. data/lib/spoom/model/model.rb +65 -68
  52. data/lib/spoom/model/namespace_visitor.rb +3 -2
  53. data/lib/spoom/model/reference.rb +4 -8
  54. data/lib/spoom/model/references_visitor.rb +49 -29
  55. data/lib/spoom/parse.rb +17 -3
  56. data/lib/spoom/poset.rb +17 -19
  57. data/lib/spoom/printer.rb +10 -13
  58. data/lib/spoom/sorbet/assertions.rb +278 -0
  59. data/lib/spoom/sorbet/config.rb +8 -12
  60. data/lib/spoom/sorbet/errors.rb +16 -31
  61. data/lib/spoom/sorbet/lsp/base.rb +9 -15
  62. data/lib/spoom/sorbet/lsp/errors.rb +8 -16
  63. data/lib/spoom/sorbet/lsp/structures.rb +36 -59
  64. data/lib/spoom/sorbet/lsp.rb +15 -17
  65. data/lib/spoom/sorbet/metrics.rb +3 -5
  66. data/lib/spoom/sorbet/sigils.rb +7 -11
  67. data/lib/spoom/sorbet/sigs.rb +118 -25
  68. data/lib/spoom/sorbet.rb +3 -9
  69. data/lib/spoom/timeline.rb +4 -6
  70. data/lib/spoom/version.rb +1 -1
  71. data/lib/spoom/visitor.rb +298 -151
  72. data/lib/spoom.rb +0 -2
  73. data/rbi/spoom.rbi +3963 -0
  74. metadata +6 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9bc28693fcde4f611e66f65d11d3a33c99e99a3ecf9bc7c7446d42e0db193cda
4
- data.tar.gz: 7c5ef49d91e54b10dd435794e68497364473e7a977a84df5ba3229966a7ea77f
3
+ metadata.gz: ebcf07d1aa065b643270105e211a05e9698befb8a67cf307c87c2fb957cd69fa
4
+ data.tar.gz: 4de71559b8d0812d7ab2456404cdf1ec840bd7031c7138a04e3233208ab8f827
5
5
  SHA512:
6
- metadata.gz: 6e487003f4b3ff1b6250cfd91770a5b2aa0ecd06587e0f90f3a5b8955626f35fa98a6075f75ea35f2a49db78f38c019964d67777e2797635225ac9821c9e225d
7
- data.tar.gz: 6a21e1986075cf301e79e9b544c0fe30b0929eb328eaceef3ff079a5b92bbcce254f3d3dfbe75e36ef78b30bfac04be029f4078185ce42667423692be71227d8
6
+ metadata.gz: ffd0520b3dcce46ea2ee2e00f4f7de974cedf21eddc706bed67616696f3f23406cbee80aeb62715c7dbfa7562a88486e21b6424b84b62d9f9a13b0a2d2f287b9
7
+ data.tar.gz: 7a7256c1a7114e46254d0cd648306ee8b1e9565522671318c710af33a571461da14b40e0d99405e63a12481f05c29b35bc3d0e660c8e7129928f1a9c34264ca9
@@ -6,11 +6,10 @@ require "minitest"
6
6
  module Spoom
7
7
  module BacktraceFilter
8
8
  class Minitest < ::Minitest::BacktraceFilter
9
- extend T::Sig
10
-
11
9
  SORBET_PATHS = T.let(Gem.loaded_specs["sorbet-runtime"].full_require_paths.freeze, T::Array[String])
12
10
 
13
- sig { override.params(bt: T.nilable(T::Array[String])).returns(T::Array[String]) }
11
+ # @override
12
+ #: (Array[String]? bt) -> Array[String]
14
13
  def filter(bt)
15
14
  super.select do |line|
16
15
  SORBET_PATHS.none? { |path| line.include?(path) }
@@ -6,7 +6,6 @@ require_relative "../deadcode"
6
6
  module Spoom
7
7
  module Cli
8
8
  class Deadcode < Thor
9
- extend T::Sig
10
9
  include Helper
11
10
 
12
11
  default_task :deadcode
@@ -48,7 +47,7 @@ module Spoom
48
47
  default: "name",
49
48
  enum: ["name", "location"],
50
49
  desc: "Sort the output by name or location"
51
- sig { params(paths: String).void }
50
+ #: (*String paths) -> void
52
51
  def deadcode(*paths)
53
52
  context = self.context
54
53
 
@@ -8,7 +8,6 @@ require "stringio"
8
8
  module Spoom
9
9
  module Cli
10
10
  module Helper
11
- extend T::Sig
12
11
  extend T::Helpers
13
12
 
14
13
  include Colorize
@@ -16,7 +15,7 @@ module Spoom
16
15
  requires_ancestor { Thor }
17
16
 
18
17
  # Print `message` on `$stdout`
19
- sig { params(message: String).void }
18
+ #: (String message) -> void
20
19
  def say(message)
21
20
  buffer = StringIO.new
22
21
  buffer << highlight(message)
@@ -29,13 +28,7 @@ module Spoom
29
28
  # Print `message` on `$stderr`
30
29
  #
31
30
  # The message is prefixed by a status (default: `Error`).
32
- sig do
33
- params(
34
- message: String,
35
- status: T.nilable(String),
36
- nl: T::Boolean,
37
- ).void
38
- end
31
+ #: (String message, ?status: String?, ?nl: bool) -> void
39
32
  def say_error(message, status: "Error", nl: true)
40
33
  buffer = StringIO.new
41
34
  buffer << "#{red(status)}: " if status
@@ -49,13 +42,7 @@ module Spoom
49
42
  # Print `message` on `$stderr`
50
43
  #
51
44
  # The message is prefixed by a status (default: `Warning`).
52
- sig do
53
- params(
54
- message: String,
55
- status: T.nilable(String),
56
- nl: T::Boolean,
57
- ).void
58
- end
45
+ #: (String message, ?status: String?, ?nl: bool) -> void
59
46
  def say_warning(message, status: "Warning", nl: true)
60
47
  buffer = StringIO.new
61
48
  buffer << "#{yellow(status)}: " if status
@@ -67,13 +54,13 @@ module Spoom
67
54
  end
68
55
 
69
56
  # Returns the context at `--path` (by default the current working directory)
70
- sig { returns(Context) }
57
+ #: -> Context
71
58
  def context
72
59
  @context ||= T.let(Context.new(exec_path), T.nilable(Context))
73
60
  end
74
61
 
75
62
  # Raise if `spoom` is not ran inside a context with a `sorbet/config` file
76
- sig { returns(Context) }
63
+ #: -> Context
77
64
  def context_requiring_sorbet!
78
65
  context = self.context
79
66
  unless context.has_sorbet_config?
@@ -88,23 +75,44 @@ module Spoom
88
75
  end
89
76
 
90
77
  # Return the path specified through `--path`
91
- sig { returns(String) }
78
+ #: -> String
92
79
  def exec_path
93
80
  options[:path]
94
81
  end
95
82
 
83
+ # Collect files from `paths`, defaulting to `exec_path`
84
+ #: (Array[String] paths) -> Array[String]
85
+ def collect_files(paths)
86
+ paths << exec_path if paths.empty?
87
+
88
+ files = paths.flat_map do |path|
89
+ if File.file?(path)
90
+ path
91
+ else
92
+ Dir.glob("#{path}/**/*.rb")
93
+ end
94
+ end
95
+
96
+ if files.empty?
97
+ say_error("No files found")
98
+ exit(1)
99
+ end
100
+
101
+ files
102
+ end
103
+
96
104
  # Colors
97
105
 
98
106
  # Color used to highlight expressions in backticks
99
107
  HIGHLIGHT_COLOR = T.let(Spoom::Color::BLUE, Spoom::Color)
100
108
 
101
109
  # Is the `--color` option true?
102
- sig { returns(T::Boolean) }
110
+ #: -> bool
103
111
  def color?
104
112
  options[:color]
105
113
  end
106
114
 
107
- sig { params(string: String).returns(String) }
115
+ #: (String string) -> String
108
116
  def highlight(string)
109
117
  return string unless color?
110
118
 
@@ -128,39 +136,39 @@ module Spoom
128
136
  end
129
137
 
130
138
  # Colorize a string if `color?`
131
- sig { params(string: String, color: Color).returns(String) }
139
+ #: (String string, *Color color) -> String
132
140
  def colorize(string, *color)
133
141
  return string unless color?
134
142
 
135
143
  T.unsafe(self).set_color(string, *color)
136
144
  end
137
145
 
138
- sig { params(string: String).returns(String) }
146
+ #: (String string) -> String
139
147
  def blue(string)
140
148
  colorize(string, Color::BLUE)
141
149
  end
142
150
 
143
- sig { params(string: String).returns(String) }
151
+ #: (String string) -> String
144
152
  def cyan(string)
145
153
  colorize(string, Color::CYAN)
146
154
  end
147
155
 
148
- sig { params(string: String).returns(String) }
156
+ #: (String string) -> String
149
157
  def gray(string)
150
158
  colorize(string, Color::LIGHT_BLACK)
151
159
  end
152
160
 
153
- sig { params(string: String).returns(String) }
161
+ #: (String string) -> String
154
162
  def green(string)
155
163
  colorize(string, Color::GREEN)
156
164
  end
157
165
 
158
- sig { params(string: String).returns(String) }
166
+ #: (String string) -> String
159
167
  def red(string)
160
168
  colorize(string, Color::RED)
161
169
  end
162
170
 
163
- sig { params(string: String).returns(String) }
171
+ #: (String string) -> String
164
172
  def yellow(string)
165
173
  colorize(string, Color::YELLOW)
166
174
  end
@@ -0,0 +1,48 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Spoom
5
+ module Cli
6
+ module Srb
7
+ class Assertions < Thor
8
+ include Helper
9
+
10
+ desc "translate", "Translate type assertions from/to RBI and RBS"
11
+ option :from, type: :string, aliases: :f, desc: "From format", enum: ["rbi"], default: "rbi"
12
+ option :to, type: :string, aliases: :t, desc: "To format", enum: ["rbs"], default: "rbs"
13
+ def translate(*paths)
14
+ from = options[:from]
15
+ to = options[:to]
16
+ files = collect_files(paths)
17
+
18
+ say("Translating type assertions from `#{from}` to `#{to}` " \
19
+ "in `#{files.size}` file#{files.size == 1 ? "" : "s"}...\n\n")
20
+
21
+ transformed_files = transform_files(files) do |file, contents|
22
+ Spoom::Sorbet::Assertions.rbi_to_rbs(contents, file: file)
23
+ end
24
+
25
+ say("Translated type assertions in `#{transformed_files}` file#{transformed_files == 1 ? "" : "s"}.")
26
+ end
27
+
28
+ no_commands do
29
+ def transform_files(files, &block)
30
+ transformed_count = 0
31
+
32
+ files.each do |file|
33
+ contents = File.read(file)
34
+ contents = block.call(file, contents)
35
+ File.write(file, contents)
36
+ transformed_count += 1
37
+ rescue Spoom::ParseError => error
38
+ say_warning("Can't parse #{file}: #{error.message}")
39
+ next
40
+ end
41
+
42
+ transformed_count
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -8,7 +8,6 @@ module Spoom
8
8
  module Cli
9
9
  module Srb
10
10
  class Bump < Thor
11
- extend T::Sig
12
11
  include Helper
13
12
 
14
13
  default_task :bump
@@ -46,7 +45,7 @@ module Spoom
46
45
  default: false,
47
46
  desc: "Count the number of errors if all files were bumped"
48
47
  option :sorbet_options, type: :string, default: "", desc: "Pass options to Sorbet"
49
- sig { params(directory: String).void }
48
+ #: (?String directory) -> void
50
49
  def bump(directory = ".")
51
50
  context = context_requiring_sorbet!
52
51
  from = options[:from]
@@ -7,22 +7,34 @@ module Spoom
7
7
  module Cli
8
8
  module Srb
9
9
  class Sigs < Thor
10
- extend T::Sig
11
10
  include Helper
12
11
 
13
12
  desc "translate", "Translate signatures from/to RBI and RBS"
14
- option :from, type: :string, aliases: :f, desc: "From format", enum: ["rbi"], default: "rbi"
15
- option :to, type: :string, aliases: :t, desc: "To format", enum: ["rbs"], default: "rbs"
13
+ option :from, type: :string, aliases: :f, desc: "From format", enum: ["rbi", "rbs"], default: "rbi"
14
+ option :to, type: :string, aliases: :t, desc: "To format", enum: ["rbi", "rbs"], default: "rbs"
16
15
  def translate(*paths)
17
16
  from = options[:from]
18
17
  to = options[:to]
18
+
19
+ if from == to
20
+ say_error("Can't translate signatures from `#{from}` to `#{to}`")
21
+ exit(1)
22
+ end
23
+
19
24
  files = collect_files(paths)
20
25
 
21
26
  say("Translating signatures from `#{from}` to `#{to}` " \
22
27
  "in `#{files.size}` file#{files.size == 1 ? "" : "s"}...\n\n")
23
28
 
24
- transformed_files = transform_files(files) do |_file, contents|
25
- Spoom::Sorbet::Sigs.rbi_to_rbs(contents)
29
+ case from
30
+ when "rbi"
31
+ transformed_files = transform_files(files) do |_file, contents|
32
+ Spoom::Sorbet::Sigs.rbi_to_rbs(contents)
33
+ end
34
+ when "rbs"
35
+ transformed_files = transform_files(files) do |_file, contents|
36
+ Spoom::Sorbet::Sigs.rbs_to_rbi(contents)
37
+ end
26
38
  end
27
39
 
28
40
  say("Translated signatures in `#{transformed_files}` file#{transformed_files == 1 ? "" : "s"}.")
@@ -41,26 +53,119 @@ module Spoom
41
53
  say("Stripped signatures from `#{transformed_files}` file#{transformed_files == 1 ? "" : "s"}.")
42
54
  end
43
55
 
44
- no_commands do
45
- def collect_files(paths)
46
- paths << "." if paths.empty?
47
-
48
- files = paths.flat_map do |path|
49
- if File.file?(path)
50
- [path]
51
- else
52
- Dir.glob("#{path}/**/*.rb")
53
- end
56
+ # Extract signatures from gem's files and save them to the output file
57
+ #
58
+ # This command will use Tapioca to generate a `.rbi` file that contains the signatures of all the files listed
59
+ # in the gemspec.
60
+ desc "export", "Export gem files signatures"
61
+ option :gemspec, type: :string, desc: "Path to the gemspec file", optional: true, default: nil
62
+ option :check_sync, type: :boolean, desc: "Check the generated RBI is up to date", default: false
63
+ def export(output_path = nil)
64
+ gemspec = options[:gemspec]
65
+
66
+ unless gemspec
67
+ say("Locating gemspec file...")
68
+ gemspec = Dir.glob("*.gemspec").first
69
+ unless gemspec
70
+ say_error("No gemspec file found")
71
+ exit(1)
54
72
  end
73
+ say("Using `#{gemspec}` as gemspec file")
74
+ end
75
+
76
+ spec = Gem::Specification.load(gemspec)
77
+
78
+ # First, we copy the files to a temporary directory so we can rewrite them without messing with the
79
+ # original ones.
80
+ say("Copying files to a temporary directory...")
81
+ copy_context = Spoom::Context.mktmp!
82
+ FileUtils.cp_r(
83
+ ["Gemfile", "Gemfile.lock", gemspec, "lib/"],
84
+ copy_context.absolute_path,
85
+ )
86
+
87
+ # Then, we transform the copied files to translate all the RBS signatures into RBI signatures.
88
+ say("Translating signatures from RBS to RBI...")
89
+ files = collect_files([copy_context.absolute_path])
90
+ transform_files(files) do |_file, contents|
91
+ Spoom::Sorbet::Sigs.rbs_to_rbi(contents)
92
+ end
93
+
94
+ # We need to inject `extend T::Sig` to be sure all the classes can run the `sig{}` blocks.
95
+ # For this we find the entry point of the gem and inject the `extend T::Sig` line at the top of the file.
96
+ entry_point = "lib/#{spec.name}.rb"
97
+ unless copy_context.file?(entry_point)
98
+ say_error("No entry point found at `#{entry_point}`")
99
+ exit(1)
100
+ end
101
+
102
+ say("Injecting `extend T::Sig` to `#{entry_point}`...")
103
+ copy_context.write!(entry_point, <<~RB)
104
+ require "sorbet-runtime"
105
+
106
+ class Module; include T::Sig; end
107
+ extend T::Sig
108
+
109
+ #{copy_context.read(entry_point)}
110
+ RB
55
111
 
56
- if files.empty?
57
- say_error("No files to transform")
112
+ # Now we create a new context to import our modified gem and run tapioca
113
+ say("Running Tapioca...")
114
+ tapioca_context = Spoom::Context.mktmp!
115
+ tapioca_context.write!("Gemfile", <<~RB)
116
+ source "https://rubygems.org"
117
+
118
+ gem "tapioca"
119
+ gem "#{spec.name}", path: "#{copy_context.absolute_path}"
120
+ RB
121
+ exec(tapioca_context, "bundle install")
122
+ exec(tapioca_context, "bundle exec tapioca gem #{spec.name} --no-loc --no-file-header")
123
+
124
+ rbi_path = tapioca_context.glob("sorbet/rbi/gems/#{spec.name}@*.rbi").first
125
+ unless rbi_path && tapioca_context.file?(rbi_path)
126
+ say_error("No RBI file found at `sorbet/rbi/gems/#{spec.name}@*.rbi`")
127
+ exit(1)
128
+ end
129
+
130
+ tapioca_context.write!(rbi_path, tapioca_context.read(rbi_path).gsub(/^# typed: true/, <<~RB.rstrip))
131
+ # typed: true
132
+
133
+ # DO NOT EDIT MANUALLY
134
+ # This is an autogenerated file for types exported from the `#{spec.name}` gem.
135
+ # Please instead update this file by running `spoom srb sigs export`.
136
+ RB
137
+
138
+ output_path ||= "rbi/#{spec.name}.rbi"
139
+ generated_path = tapioca_context.absolute_path_to(rbi_path)
140
+
141
+ if options[:check_sync]
142
+ # If the check option is set, we just compare the generated RBI with the one in the gem.
143
+ # If they are different, we exit with a non-zero exit code.
144
+ unless system("diff -u -L 'generated' -L 'current' #{generated_path} #{output_path} >&2")
145
+ say_error(<<~ERR, status: "\nError")
146
+ The RBI file at `#{output_path}` is not up to date
147
+
148
+ Please run `spoom srb sigs export` to update it.
149
+ ERR
58
150
  exit(1)
59
151
  end
60
152
 
61
- files
153
+ say("The RBI file at `#{output_path}` is up to date")
154
+ exit(0)
155
+ else
156
+ output_dir = File.dirname(output_path)
157
+ FileUtils.rm_rf(output_dir)
158
+ FileUtils.mkdir_p(output_dir)
159
+ FileUtils.cp(generated_path, output_path)
160
+
161
+ say("Exported signatures to `#{output_path}`")
62
162
  end
163
+ ensure
164
+ copy_context&.destroy!
165
+ tapioca_context&.destroy!
166
+ end
63
167
 
168
+ no_commands do
64
169
  def transform_files(files, &block)
65
170
  transformed_count = 0
66
171
 
@@ -83,6 +188,16 @@ module Spoom
83
188
 
84
189
  transformed_count
85
190
  end
191
+
192
+ def exec(context, command)
193
+ res = context.exec(command)
194
+
195
+ unless res.status
196
+ $stderr.puts "Error: #{command} failed"
197
+ $stderr.puts res.err
198
+ exit(1)
199
+ end
200
+ end
86
201
  end
87
202
  end
88
203
  end
data/lib/spoom/cli/srb.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require_relative "srb/assertions"
4
5
  require_relative "srb/bump"
5
6
  require_relative "srb/coverage"
6
7
  require_relative "srb/lsp"
@@ -11,14 +12,17 @@ module Spoom
11
12
  module Cli
12
13
  module Srb
13
14
  class Main < Thor
14
- desc "lsp", "Send LSP requests to Sorbet"
15
- subcommand "lsp", Spoom::Cli::Srb::LSP
15
+ desc "assertions", "Translate type assertions from/to RBI and RBS"
16
+ subcommand "assertions", Spoom::Cli::Srb::Assertions
17
+
18
+ desc "bump", "Change Sorbet sigils from one strictness to another when no errors"
19
+ subcommand "bump", Spoom::Cli::Srb::Bump
16
20
 
17
21
  desc "coverage", "Collect metrics related to Sorbet coverage"
18
22
  subcommand "coverage", Spoom::Cli::Srb::Coverage
19
23
 
20
- desc "bump", "Change Sorbet sigils from one strictness to another when no errors"
21
- subcommand "bump", Spoom::Cli::Srb::Bump
24
+ desc "lsp", "Send LSP requests to Sorbet"
25
+ subcommand "lsp", Spoom::Cli::Srb::LSP
22
26
 
23
27
  desc "sigs", "Translate signatures from/to RBI and RBS"
24
28
  subcommand "sigs", Spoom::Cli::Srb::Sigs
data/lib/spoom/cli.rb CHANGED
@@ -10,7 +10,6 @@ require_relative "cli/srb"
10
10
  module Spoom
11
11
  module Cli
12
12
  class Main < Thor
13
- extend T::Sig
14
13
  include Helper
15
14
 
16
15
  class_option :color, type: :boolean, default: true, desc: "Use colors"
@@ -54,7 +53,7 @@ module Spoom
54
53
  default: false,
55
54
  desc: "Count the number of errors if all files were bumped"
56
55
  option :sorbet_options, type: :string, default: "", desc: "Pass options to Sorbet"
57
- sig { params(directory: String).void }
56
+ #: (?String directory) -> void
58
57
  def bump(directory = ".")
59
58
  say_warning("This command is deprecated. Please use `spoom srb bump` instead.")
60
59
 
data/lib/spoom/colors.rb CHANGED
@@ -3,8 +3,6 @@
3
3
 
4
4
  module Spoom
5
5
  class Color < T::Enum
6
- extend T::Sig
7
-
8
6
  enums do
9
7
  CLEAR = new("\e[0m")
10
8
  BOLD = new("\e[1m")
@@ -28,16 +26,14 @@ module Spoom
28
26
  LIGHT_WHITE = new("\e[97m")
29
27
  end
30
28
 
31
- sig { returns(String) }
29
+ #: -> String
32
30
  def ansi_code
33
31
  serialize
34
32
  end
35
33
  end
36
34
 
37
35
  module Colorize
38
- extend T::Sig
39
-
40
- sig { params(string: String, color: Color).returns(String) }
36
+ #: (String string, *Color color) -> String
41
37
  def set_color(string, *color)
42
38
  "#{color.map(&:ansi_code).join}#{string}#{Color::CLEAR.ansi_code}"
43
39
  end
@@ -5,49 +5,48 @@ module Spoom
5
5
  class Context
6
6
  # Bundle features for a context
7
7
  module Bundle
8
- extend T::Sig
9
8
  extend T::Helpers
10
9
 
11
10
  requires_ancestor { Context }
12
11
 
13
12
  # Read the contents of the Gemfile in this context directory
14
- sig { returns(T.nilable(String)) }
13
+ #: -> String?
15
14
  def read_gemfile
16
15
  read("Gemfile")
17
16
  end
18
17
 
19
18
  # Read the contents of the Gemfile.lock in this context directory
20
- sig { returns(T.nilable(String)) }
19
+ #: -> String?
21
20
  def read_gemfile_lock
22
21
  read("Gemfile.lock")
23
22
  end
24
23
 
25
24
  # Set the `contents` of the Gemfile in this context directory
26
- sig { params(contents: String, append: T::Boolean).void }
25
+ #: (String contents, ?append: bool) -> void
27
26
  def write_gemfile!(contents, append: false)
28
27
  write!("Gemfile", contents, append: append)
29
28
  end
30
29
 
31
30
  # Run a command with `bundle` in this context directory
32
- sig { params(command: String, version: T.nilable(String), capture_err: T::Boolean).returns(ExecResult) }
31
+ #: (String command, ?version: String?, ?capture_err: bool) -> ExecResult
33
32
  def bundle(command, version: nil, capture_err: true)
34
33
  command = "_#{version}_ #{command}" if version
35
34
  exec("bundle #{command}", capture_err: capture_err)
36
35
  end
37
36
 
38
37
  # Run `bundle install` in this context directory
39
- sig { params(version: T.nilable(String), capture_err: T::Boolean).returns(ExecResult) }
38
+ #: (?version: String?, ?capture_err: bool) -> ExecResult
40
39
  def bundle_install!(version: nil, capture_err: true)
41
40
  bundle("install", version: version, capture_err: capture_err)
42
41
  end
43
42
 
44
43
  # Run a command `bundle exec` in this context directory
45
- sig { params(command: String, version: T.nilable(String), capture_err: T::Boolean).returns(ExecResult) }
44
+ #: (String command, ?version: String?, ?capture_err: bool) -> ExecResult
46
45
  def bundle_exec(command, version: nil, capture_err: true)
47
46
  bundle("exec #{command}", version: version, capture_err: capture_err)
48
47
  end
49
48
 
50
- sig { returns(T::Hash[String, Bundler::LazySpecification]) }
49
+ #: -> Hash[String, Bundler::LazySpecification]
51
50
  def gemfile_lock_specs
52
51
  return {} unless file?("Gemfile.lock")
53
52
 
@@ -58,7 +57,7 @@ module Spoom
58
57
  # Get `gem` version from the `Gemfile.lock` content
59
58
  #
60
59
  # Returns `nil` if `gem` cannot be found in the Gemfile.
61
- sig { params(gem: String).returns(T.nilable(Gem::Version)) }
60
+ #: (String gem) -> Gem::Version?
62
61
  def gem_version_from_gemfile_lock(gem)
63
62
  gemfile_lock_specs[gem]&.version
64
63
  end
@@ -3,14 +3,12 @@
3
3
 
4
4
  module Spoom
5
5
  class ExecResult < T::Struct
6
- extend T::Sig
7
-
8
6
  const :out, String
9
7
  const :err, T.nilable(String)
10
8
  const :status, T::Boolean
11
9
  const :exit_code, Integer
12
10
 
13
- sig { returns(String) }
11
+ #: -> String
14
12
  def to_s
15
13
  <<~STR
16
14
  ########## STDOUT ##########
@@ -25,13 +23,12 @@ module Spoom
25
23
  class Context
26
24
  # Execution features for a context
27
25
  module Exec
28
- extend T::Sig
29
26
  extend T::Helpers
30
27
 
31
28
  requires_ancestor { Context }
32
29
 
33
30
  # Run a command in this context directory
34
- sig { params(command: String, capture_err: T::Boolean).returns(ExecResult) }
31
+ #: (String command, ?capture_err: bool) -> ExecResult
35
32
  def exec(command, capture_err: true)
36
33
  Bundler.with_unbundled_env do
37
34
  opts = T.let({ chdir: absolute_path }, T::Hash[Symbol, T.untyped])