spoom 1.2.2 → 1.2.3

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: 5154e37a81129c70e93925cc2a545a0d7861fd645a3ec2422e6549efc0cb76b5
4
- data.tar.gz: 30c9ecdc3599a37309180fea890a7888d53b430c8701e0970f503bf5731979f9
3
+ metadata.gz: 8e7ef8ebef70bc8827cdcb4b2c0e49ed6c53686e0db409908354f3762ad07c10
4
+ data.tar.gz: a6adb405f0379cbe040e743f177e758e2bdaadcdea13ee9c7f75d84f764434b1
5
5
  SHA512:
6
- metadata.gz: a3246a42fa965e3ef75d0178ffe958a8cc5723812ecb86799b5e2e406d5da7487ffd738696ccb3f6d76ae140de281dab73dba3ec3d8af9fdef696820654ed869
7
- data.tar.gz: ba4c8ab2d87ff4451f420e2d062c7cebdd19202bc91226fd131ff9ab9f838e7494fa43560ffa317fc0565d023ecceef184c02f762e215ba6451d3ec164e3c75a
6
+ metadata.gz: 86d74bc7d9554d67c1421908116bbab7615d77e9cb096d461f7885429d495f2b02f19d6024117f7083423cfe7c48165b18918c143f29574896bfbb76a4fb651f
7
+ data.tar.gz: 754d41e8f26425a42288388879fe1658214adea03002421495297486343a827d6dc79a395e895553ed15f67cdc766a16f4a174aab2a3671bd2455e305a8c6f13
@@ -187,7 +187,7 @@ module Spoom
187
187
 
188
188
  no_commands do
189
189
  def parse_time(string, option)
190
- return nil unless string
190
+ return unless string
191
191
 
192
192
  Time.parse(string)
193
193
  rescue ArgumentError
@@ -13,7 +13,7 @@ module Spoom
13
13
  sig { params(string: String).returns(T.nilable(Commit)) }
14
14
  def parse_line(string)
15
15
  sha, epoch = string.split(" ", 2)
16
- return nil unless sha && epoch
16
+ return unless sha && epoch
17
17
 
18
18
  time = Time.strptime(epoch, "%s")
19
19
  Commit.new(sha: sha, time: time)
@@ -88,7 +88,7 @@ module Spoom
88
88
  sig { returns(T.nilable(String)) }
89
89
  def git_current_branch
90
90
  res = git("branch --show-current")
91
- return nil unless res.status
91
+ return unless res.status
92
92
 
93
93
  res.out.strip
94
94
  end
@@ -103,10 +103,10 @@ module Spoom
103
103
  sig { params(short_sha: T::Boolean).returns(T.nilable(Spoom::Git::Commit)) }
104
104
  def git_last_commit(short_sha: true)
105
105
  res = git_log("HEAD --format='%#{short_sha ? "h" : "H"} %at' -1")
106
- return nil unless res.status
106
+ return unless res.status
107
107
 
108
108
  out = res.out.strip
109
- return nil if out.empty?
109
+ return if out.empty?
110
110
 
111
111
  Spoom::Git::Commit.parse_line(out)
112
112
  end
@@ -52,7 +52,7 @@ module Spoom
52
52
  sorbet_bin: sorbet_bin,
53
53
  capture_err: capture_err,
54
54
  )
55
- return nil unless file?(metrics_file)
55
+ return unless file?(metrics_file)
56
56
 
57
57
  metrics_path = absolute_path_to(metrics_file)
58
58
  metrics = Spoom::Sorbet::MetricsParser.parse_file(metrics_path)
@@ -109,7 +109,7 @@ module Spoom
109
109
  sig { params(arg: String, sorbet_bin: T.nilable(String), capture_err: T::Boolean).returns(T.nilable(String)) }
110
110
  def srb_version(*arg, sorbet_bin: nil, capture_err: true)
111
111
  res = T.unsafe(self).srb_tc("--no-config", "--version", *arg, sorbet_bin: sorbet_bin, capture_err: capture_err)
112
- return nil unless res.status
112
+ return unless res.status
113
113
 
114
114
  res.out.split(" ")[2]
115
115
  end
@@ -147,10 +147,10 @@ module Spoom
147
147
  sig { returns(T.nilable(Spoom::Git::Commit)) }
148
148
  def sorbet_intro_commit
149
149
  res = git_log("--diff-filter=A --format='%h %at' -1 -- sorbet/config")
150
- return nil unless res.status
150
+ return unless res.status
151
151
 
152
152
  out = res.out.strip
153
- return nil if out.empty?
153
+ return if out.empty?
154
154
 
155
155
  Spoom::Git::Commit.parse_line(out)
156
156
  end
@@ -159,10 +159,10 @@ module Spoom
159
159
  sig { returns(T.nilable(Spoom::Git::Commit)) }
160
160
  def sorbet_removal_commit
161
161
  res = git_log("--diff-filter=D --format='%h %at' -1 -- sorbet/config")
162
- return nil unless res.status
162
+ return unless res.status
163
163
 
164
164
  out = res.out.strip
165
- return nil if out.empty?
165
+ return if out.empty?
166
166
 
167
167
  Spoom::Git::Commit.parse_line(out)
168
168
  end
@@ -12,14 +12,15 @@ module Spoom
12
12
  sig { returns(Index) }
13
13
  attr_reader :index
14
14
 
15
- sig { params(path: String, source: String, index: Index).void }
16
- def initialize(path, source, index)
15
+ sig { params(path: String, source: String, index: Index, plugins: T::Array[Plugins::Base]).void }
16
+ def initialize(path, source, index, plugins: [])
17
17
  super()
18
18
 
19
19
  @path = path
20
20
  @file_name = T.let(File.basename(path), String)
21
21
  @source = source
22
22
  @index = index
23
+ @plugins = plugins
23
24
  @previous_node = T.let(nil, T.nilable(SyntaxTree::Node))
24
25
  @names_nesting = T.let([], T::Array[String])
25
26
  @nodes_nesting = T.let([], T::Array[SyntaxTree::Node])
@@ -228,6 +229,10 @@ module Spoom
228
229
  define_attr_writer("#{name}=", "#{full_name}=", arg)
229
230
  end
230
231
  else
232
+ @plugins.each do |plugin|
233
+ plugin.on_send(self, send)
234
+ end
235
+
231
236
  reference_method(send.name, send.node)
232
237
  visit_all(send.args)
233
238
  visit(send.block)
@@ -270,8 +275,6 @@ module Spoom
270
275
  visit_send(Send.new(node: node, name: node_string(node.value)))
271
276
  end
272
277
 
273
- private
274
-
275
278
  # Definition indexing
276
279
 
277
280
  sig { params(name: String, full_name: String, node: SyntaxTree::Node).void }
@@ -283,6 +286,7 @@ module Spoom
283
286
  location: node_location(node),
284
287
  )
285
288
  @index.define(definition)
289
+ @plugins.each { |plugin| plugin.on_define_accessor(self, definition) }
286
290
  end
287
291
 
288
292
  sig { params(name: String, full_name: String, node: SyntaxTree::Node).void }
@@ -294,6 +298,7 @@ module Spoom
294
298
  location: node_location(node),
295
299
  )
296
300
  @index.define(definition)
301
+ @plugins.each { |plugin| plugin.on_define_accessor(self, definition) }
297
302
  end
298
303
 
299
304
  sig { params(name: String, full_name: String, node: SyntaxTree::Node).void }
@@ -305,6 +310,7 @@ module Spoom
305
310
  location: node_location(node),
306
311
  )
307
312
  @index.define(definition)
313
+ @plugins.each { |plugin| plugin.on_define_class(self, definition) }
308
314
  end
309
315
 
310
316
  sig { params(name: String, full_name: String, node: SyntaxTree::Node).void }
@@ -316,6 +322,7 @@ module Spoom
316
322
  location: node_location(node),
317
323
  )
318
324
  @index.define(definition)
325
+ @plugins.each { |plugin| plugin.on_define_constant(self, definition) }
319
326
  end
320
327
 
321
328
  sig { params(name: String, full_name: String, node: SyntaxTree::Node).void }
@@ -327,6 +334,7 @@ module Spoom
327
334
  location: node_location(node),
328
335
  )
329
336
  @index.define(definition)
337
+ @plugins.each { |plugin| plugin.on_define_method(self, definition) }
330
338
  end
331
339
 
332
340
  sig { params(name: String, full_name: String, node: SyntaxTree::Node).void }
@@ -338,6 +346,7 @@ module Spoom
338
346
  location: node_location(node),
339
347
  )
340
348
  @index.define(definition)
349
+ @plugins.each { |plugin| plugin.on_define_module(self, definition) }
341
350
  end
342
351
 
343
352
  # Reference indexing
@@ -44,7 +44,7 @@ module Spoom
44
44
 
45
45
  sig { override.params(other: BasicObject).returns(T.nilable(Integer)) }
46
46
  def <=>(other)
47
- return nil unless Location === other
47
+ return unless Location === other
48
48
 
49
49
  to_s <=> other.to_s
50
50
  end
@@ -0,0 +1,201 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "set"
5
+
6
+ module Spoom
7
+ module Deadcode
8
+ module Plugins
9
+ class Base
10
+ extend T::Sig
11
+ extend T::Helpers
12
+
13
+ abstract!
14
+
15
+ class << self
16
+ extend T::Sig
17
+
18
+ # Plugins DSL
19
+
20
+ # Mark methods matching `names` as ignored.
21
+ #
22
+ # Names can be either strings or regexps:
23
+ #
24
+ # ~~~rb
25
+ # class MyPlugin < Spoom::Deadcode::Plugins::Base
26
+ # ignore_method_names(
27
+ # "foo",
28
+ # "bar",
29
+ # /baz.*/,
30
+ # )
31
+ # end
32
+ # ~~~
33
+ sig { params(names: T.any(String, Regexp)).void }
34
+ def ignore_method_names(*names)
35
+ save_names_and_patterns(names, :@ignored_method_names, :@ignored_method_patterns)
36
+ end
37
+
38
+ private
39
+
40
+ sig { params(names: T::Array[T.any(String, Regexp)], names_variable: Symbol, patterns_variable: Symbol).void }
41
+ def save_names_and_patterns(names, names_variable, patterns_variable)
42
+ ignored_names = instance_variable_set(names_variable, Set.new)
43
+ ignored_patterns = instance_variable_set(patterns_variable, [])
44
+
45
+ names.each do |name|
46
+ case name
47
+ when String
48
+ ignored_names << name
49
+ when Regexp
50
+ ignored_patterns << name
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ # Indexing event methods
57
+
58
+ # Called when an accessor is defined.
59
+ #
60
+ # Will be called when the indexer processes a `attr_reader`, `attr_writer` or `attr_accessor` node.
61
+ # Note that when this method is called, the definition for the node has already been added to the index.
62
+ # It is still possible to ignore it from the plugin:
63
+ #
64
+ # ~~~rb
65
+ # class MyPlugin < Spoom::Deadcode::Plugins::Base
66
+ # def on_define_accessor(indexer, definition)
67
+ # definition.ignored! if definition.name == "foo"
68
+ # end
69
+ # end
70
+ # ~~~
71
+ sig { params(indexer: Indexer, definition: Definition).void }
72
+ def on_define_accessor(indexer, definition)
73
+ # no-op
74
+ end
75
+
76
+ # Called when a class is defined.
77
+ #
78
+ # Will be called when the indexer processes a `class` node.
79
+ # Note that when this method is called, the definition for the node has already been added to the index.
80
+ # It is still possible to ignore it from the plugin:
81
+ #
82
+ # ~~~rb
83
+ # class MyPlugin < Spoom::Deadcode::Plugins::Base
84
+ # def on_define_class(indexer, definition)
85
+ # definition.ignored! if definition.name == "Foo"
86
+ # end
87
+ # end
88
+ # ~~~
89
+ sig { params(indexer: Indexer, definition: Definition).void }
90
+ def on_define_class(indexer, definition)
91
+ # no-op
92
+ end
93
+
94
+ # Called when a constant is defined.
95
+ #
96
+ # Will be called when the indexer processes a `CONST =` node.
97
+ # Note that when this method is called, the definition for the node has already been added to the index.
98
+ # It is still possible to ignore it from the plugin:
99
+ #
100
+ # ~~~rb
101
+ # class MyPlugin < Spoom::Deadcode::Plugins::Base
102
+ # def on_define_constant(indexer, definition)
103
+ # definition.ignored! if definition.name == "FOO"
104
+ # end
105
+ # end
106
+ # ~~~
107
+ sig { params(indexer: Indexer, definition: Definition).void }
108
+ def on_define_constant(indexer, definition)
109
+ # no-op
110
+ end
111
+
112
+ # Called when a method is defined.
113
+ #
114
+ # Will be called when the indexer processes a `def` or `defs` node.
115
+ # Note that when this method is called, the definition for the node has already been added to the index.
116
+ # It is still possible to ignore it from the plugin:
117
+ #
118
+ # ~~~rb
119
+ # class MyPlugin < Spoom::Deadcode::Plugins::Base
120
+ # def on_define_method(indexer, definition)
121
+ # super # So the `ignore_method_names` DSL is still applied
122
+ #
123
+ # definition.ignored! if definition.name == "foo"
124
+ # end
125
+ # end
126
+ # ~~~
127
+ sig { params(indexer: Indexer, definition: Definition).void }
128
+ def on_define_method(indexer, definition)
129
+ definition.ignored! if ignored_method_name?(definition.name)
130
+ end
131
+
132
+ # Called when a module is defined.
133
+ #
134
+ # Will be called when the indexer processes a `module` node.
135
+ # Note that when this method is called, the definition for the node has already been added to the index.
136
+ # It is still possible to ignore it from the plugin:
137
+ #
138
+ # ~~~rb
139
+ # class MyPlugin < Spoom::Deadcode::Plugins::Base
140
+ # def on_define_module(indexer, definition)
141
+ # definition.ignored! if definition.name == "Foo"
142
+ # end
143
+ # end
144
+ # ~~~
145
+ sig { params(indexer: Indexer, definition: Definition).void }
146
+ def on_define_module(indexer, definition)
147
+ # no-op
148
+ end
149
+
150
+ # Called when a send is being processed
151
+ #
152
+ # ~~~rb
153
+ # class MyPlugin < Spoom::Deadcode::Plugins::Base
154
+ # def on_send(indexer, send)
155
+ # return unless send.name == "dsl_method"
156
+ # return if send.args.empty?
157
+ #
158
+ # method_name = indexer.node_string(send.args.first).delete_prefix(":")
159
+ # indexer.reference_method(method_name, send.node)
160
+ # end
161
+ # end
162
+ # ~~~
163
+ sig { params(indexer: Indexer, send: Send).void }
164
+ def on_send(indexer, send)
165
+ # no-op
166
+ end
167
+
168
+ private
169
+
170
+ sig { params(name: String).returns(T::Boolean) }
171
+ def ignored_method_name?(name)
172
+ ignored_name?(name, :@ignored_method_names, :@ignored_method_patterns)
173
+ end
174
+
175
+ sig { params(const: Symbol).returns(T::Set[String]) }
176
+ def names(const)
177
+ self.class.instance_variable_get(const) || Set.new
178
+ end
179
+
180
+ sig { params(name: String, names_variable: Symbol, patterns_variable: Symbol).returns(T::Boolean) }
181
+ def ignored_name?(name, names_variable, patterns_variable)
182
+ names(names_variable).include?(name) || patterns(patterns_variable).any? { |pattern| pattern.match?(name) }
183
+ end
184
+
185
+ sig { params(const: Symbol).returns(T::Array[Regexp]) }
186
+ def patterns(const)
187
+ self.class.instance_variable_get(const) || []
188
+ end
189
+
190
+ sig { params(indexer: Indexer, send: Send).void }
191
+ def reference_send_first_symbol_as_method(indexer, send)
192
+ first_arg = send.args.first
193
+ return unless first_arg.is_a?(SyntaxTree::SymbolLiteral)
194
+
195
+ name = indexer.node_string(first_arg.value)
196
+ indexer.reference_method(name, send.node)
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,64 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Spoom
5
+ module Deadcode
6
+ module Plugins
7
+ class Ruby < Base
8
+ extend T::Sig
9
+
10
+ ignore_method_names(
11
+ "==",
12
+ "extended",
13
+ "included",
14
+ "inherited",
15
+ "initialize",
16
+ "method_added",
17
+ "method_missing",
18
+ "prepended",
19
+ "respond_to_missing?",
20
+ "to_s",
21
+ )
22
+
23
+ sig { override.params(indexer: Indexer, send: Send).void }
24
+ def on_send(indexer, send)
25
+ case send.name
26
+ when "const_defined?", "const_get", "const_source_location"
27
+ reference_symbol_as_constant(indexer, send, T.must(send.args.first))
28
+ when "send", "__send__", "try"
29
+ reference_send_first_symbol_as_method(indexer, send)
30
+ when "alias_method"
31
+ last_arg = send.args.last
32
+
33
+ name = case last_arg
34
+ when SyntaxTree::SymbolLiteral
35
+ indexer.node_string(last_arg.value)
36
+ when SyntaxTree::StringLiteral
37
+ last_arg.parts.map { |part| indexer.node_string(part) }.join
38
+ end
39
+
40
+ return unless name
41
+
42
+ indexer.reference_method(name, send.node)
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ sig { params(indexer: Indexer, send: Send, node: SyntaxTree::Node).void }
49
+ def reference_symbol_as_constant(indexer, send, node)
50
+ case node
51
+ when SyntaxTree::SymbolLiteral
52
+ name = indexer.node_string(node.value)
53
+ indexer.reference_constant(name, send.node)
54
+ when SyntaxTree::StringLiteral
55
+ string = T.must(indexer.node_string(node)[1..-2])
56
+ string.split("::").each do |name|
57
+ indexer.reference_constant(name, send.node) unless name.empty?
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,5 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "plugins/base"
5
+ require_relative "plugins/ruby"
@@ -12,6 +12,7 @@ require_relative "deadcode/location"
12
12
  require_relative "deadcode/definition"
13
13
  require_relative "deadcode/reference"
14
14
  require_relative "deadcode/send"
15
+ require_relative "deadcode/plugins"
15
16
 
16
17
  module Spoom
17
18
  module Deadcode
@@ -34,10 +35,10 @@ module Spoom
34
35
  class << self
35
36
  extend T::Sig
36
37
 
37
- sig { params(index: Index, ruby: String, file: String).void }
38
- def index_ruby(index, ruby, file:)
38
+ sig { params(index: Index, ruby: String, file: String, plugins: T::Array[Deadcode::Plugins::Base]).void }
39
+ def index_ruby(index, ruby, file:, plugins: [])
39
40
  node = SyntaxTree.parse(ruby)
40
- visitor = Spoom::Deadcode::Indexer.new(file, ruby, index)
41
+ visitor = Spoom::Deadcode::Indexer.new(file, ruby, index, plugins: plugins)
41
42
  visitor.visit(node)
42
43
  rescue SyntaxTree::Parser::ParseError => e
43
44
  raise ParserError.new("Error while parsing #{file} (#{e.message} at #{e.lineno}:#{e.column})", parent: e)
@@ -45,10 +46,10 @@ module Spoom
45
46
  raise IndexerError.new("Error while indexing #{file} (#{e.message})", parent: e)
46
47
  end
47
48
 
48
- sig { params(index: Index, erb: String, file: String).void }
49
- def index_erb(index, erb, file:)
49
+ sig { params(index: Index, erb: String, file: String, plugins: T::Array[Deadcode::Plugins::Base]).void }
50
+ def index_erb(index, erb, file:, plugins: [])
50
51
  ruby = ERB.new(erb).src
51
- index_ruby(index, ruby, file: file)
52
+ index_ruby(index, ruby, file: file, plugins: plugins)
52
53
  end
53
54
  end
54
55
  end
@@ -53,7 +53,7 @@ module Spoom
53
53
  sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) }
54
54
  def read
55
55
  raw_string = read_raw
56
- return nil unless raw_string
56
+ return unless raw_string
57
57
 
58
58
  json = JSON.parse(raw_string)
59
59
 
@@ -101,7 +101,7 @@ module Spoom
101
101
  },
102
102
  ))
103
103
 
104
- return nil unless json && json["result"]
104
+ return unless json && json["result"]
105
105
 
106
106
  Hover.from_json(json["result"])
107
107
  end
@@ -28,7 +28,7 @@ module Spoom
28
28
  T::Array[String],
29
29
  )
30
30
 
31
- SIGIL_REGEXP = T.let(/^#[\ t]*typed[\ t]*:[ \t]*(\w*)[ \t]*/, Regexp)
31
+ SIGIL_REGEXP = T.let(/^#[[:blank:]]*typed:[[:blank:]]*(\S*)/, Regexp)
32
32
 
33
33
  class << self
34
34
  extend T::Sig
@@ -61,7 +61,7 @@ module Spoom
61
61
  # * returns nil if no sigil
62
62
  sig { params(path: T.any(String, Pathname)).returns(T.nilable(String)) }
63
63
  def file_strictness(path)
64
- return nil unless File.file?(path)
64
+ return unless File.file?(path)
65
65
 
66
66
  content = File.read(path, encoding: Encoding::ASCII_8BIT)
67
67
  strictness_in_content(content)
data/lib/spoom/sorbet.rb CHANGED
@@ -35,6 +35,7 @@ module Spoom
35
35
 
36
36
  CONFIG_PATH = "sorbet/config"
37
37
  GEM_PATH = T.let(Gem::Specification.find_by_name("sorbet-static").full_gem_path, String)
38
+ GEM_VERSION = T.let(Gem::Specification.find_by_name("sorbet-static-and-runtime").version.to_s, String)
38
39
  BIN_PATH = T.let((Pathname.new(GEM_PATH) / "libexec" / "sorbet").to_s, String)
39
40
 
40
41
  KILLED_CODE = 137
data/lib/spoom/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Spoom
5
- VERSION = "1.2.2"
5
+ VERSION = "1.2.3"
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spoom
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre Terrasa
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-21 00:00:00.000000000 Z
11
+ date: 2023-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: 1.10.0
83
83
  - !ruby/object:Gem::Dependency
84
- name: sorbet
84
+ name: sorbet-static-and-runtime
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -94,20 +94,6 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: 0.5.10187
97
- - !ruby/object:Gem::Dependency
98
- name: sorbet-runtime
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: 0.5.9204
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: 0.5.9204
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: syntax_tree
113
99
  requirement: !ruby/object:Gem::Requirement
@@ -177,6 +163,9 @@ files:
177
163
  - lib/spoom/deadcode/index.rb
178
164
  - lib/spoom/deadcode/indexer.rb
179
165
  - lib/spoom/deadcode/location.rb
166
+ - lib/spoom/deadcode/plugins.rb
167
+ - lib/spoom/deadcode/plugins/base.rb
168
+ - lib/spoom/deadcode/plugins/ruby.rb
180
169
  - lib/spoom/deadcode/reference.rb
181
170
  - lib/spoom/deadcode/send.rb
182
171
  - lib/spoom/file_collector.rb
@@ -216,7 +205,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
216
205
  - !ruby/object:Gem::Version
217
206
  version: '0'
218
207
  requirements: []
219
- rubygems_version: 3.4.14
208
+ rubygems_version: 3.4.17
220
209
  signing_key:
221
210
  specification_version: 4
222
211
  summary: Useful tools for Sorbet enthusiasts.