spoom 1.7.0 → 1.7.2

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: 232ecacb9d25232ca17356951f795baf011b5ec9dd4c18b5688be1c474bccf2b
4
- data.tar.gz: 824782c6b5b810cae1a88805e3dd196a4499f4f04fce86e57fc933873958cbd9
3
+ metadata.gz: 59987238a3b2bae115f02d1da2a7e2a4cd6b3532d816bbe80d9153fa7819f989
4
+ data.tar.gz: d7e6bccfa046b7c457cb3e5d3d4383141243949021bd584b22cde0db0cc165ef
5
5
  SHA512:
6
- metadata.gz: de1b4478214f3be4f3369b7930cd6a3b96dac3e6c5ba506a3e25380bf1733b093996851dc59537ef56c2700eb63e3d0c317cc3ab44d0690e0255da38c0e6da77
7
- data.tar.gz: 61e14bcfd81428eb251b514b4b21c0febd5df783bc5221e68d1c5ca44e3c5ae34017c12e13d034d331c31ee8900a38847e3712197797431122c5a24d57fc144b
6
+ metadata.gz: b2f53478b7fdee59bfa7c579c3686b6d6c388db8737584c02f613daa2c4d42c0be2c1baaa39c50e90137697f62d7b8bb04e9fdbb458defdfa7813be3b6cbbd36
7
+ data.tar.gz: 57b26d457d2235bedaff15c832accc34a9c5ffcb89876306394f12b74a87ce03964d0309cd62e213e9954607150968607227436ebeb522a84f27782f7cc8cac8
@@ -0,0 +1,68 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Spoom
5
+ module Cli
6
+ module Srb
7
+ class Metrics < Thor
8
+ include Helper
9
+
10
+ default_task :show
11
+
12
+ desc "show", "Show metrics about Sorbet usage"
13
+ option :dump, type: :boolean, default: false
14
+ def show(*paths)
15
+ files = collect_files(paths)
16
+ metrics = Spoom::Sorbet::Metrics.collect_code_metrics(files)
17
+
18
+ if options[:dump]
19
+ metrics.sort_by { |key, _value| key }.each do |key, value|
20
+ puts "#{key} #{value}"
21
+ end
22
+
23
+ return
24
+ end
25
+
26
+ say("Files: `#{files.size}`")
27
+
28
+ ["classes", "modules", "singleton_classes"].each do |key|
29
+ value = metrics[key]
30
+ next if value == 0
31
+
32
+ say("\n#{key.capitalize}: `#{value}`")
33
+ ["with_srb_type_params", "with_rbs_type_params"].each do |subkey|
34
+ say(" * #{subkey.gsub("_", " ")}: `#{metrics["#{key}_#{subkey}"]}`")
35
+ end
36
+ end
37
+
38
+ ["methods", "accessors"].each do |key|
39
+ value = metrics[key]
40
+ next if value == 0
41
+
42
+ say("\n#{key.capitalize}: `#{value}`")
43
+ ["without_sig", "with_srb_sig", "with_rbs_sig"].each do |subkey|
44
+ say(" * #{subkey.gsub("_", " ")}: `#{metrics["#{key}_#{subkey}"]}`")
45
+ end
46
+ end
47
+
48
+ say("\nT. calls: `#{metrics["T_calls"]}`")
49
+ metrics
50
+ .select { |key, _value| key.start_with?("T.") }
51
+ .sort_by { |_key, value| -value }
52
+ .each do |key, value|
53
+ say(" * #{key}: `#{value}`")
54
+ end
55
+
56
+ say("\nRBS Assertions: `#{metrics["rbs_assertions"]}`")
57
+ metrics
58
+ .reject { |key, _value| key == "rbs_assertions" }
59
+ .select { |key, _value| key.start_with?("rbs_") }
60
+ .sort_by { |_key, value| -value }
61
+ .each do |key, value|
62
+ say(" * #{key}: `#{value}`")
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
data/lib/spoom/cli/srb.rb CHANGED
@@ -5,6 +5,7 @@ require_relative "srb/assertions"
5
5
  require_relative "srb/bump"
6
6
  require_relative "srb/coverage"
7
7
  require_relative "srb/lsp"
8
+ require_relative "srb/metrics"
8
9
  require_relative "srb/sigs"
9
10
  require_relative "srb/tc"
10
11
 
@@ -24,6 +25,9 @@ module Spoom
24
25
  desc "lsp", "Send LSP requests to Sorbet"
25
26
  subcommand "lsp", Spoom::Cli::Srb::LSP
26
27
 
28
+ desc "metrics", "Collect metrics about Sorbet usage"
29
+ subcommand "metrics", Spoom::Cli::Srb::Metrics
30
+
27
31
  desc "sigs", "Translate signatures from/to RBI and RBS"
28
32
  subcommand "sigs", Spoom::Cli::Srb::Sigs
29
33
 
@@ -48,7 +48,7 @@ module Spoom
48
48
  return unless file?(metrics_file)
49
49
 
50
50
  metrics_path = absolute_path_to(metrics_file)
51
- metrics = Spoom::Sorbet::MetricsParser.parse_file(metrics_path)
51
+ metrics = Spoom::Sorbet::Metrics::MetricsFileParser.parse_file(metrics_path)
52
52
  remove!(metrics_file)
53
53
  metrics
54
54
  end
@@ -0,0 +1,22 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Spoom
5
+ #: [K = String, V = Integer, Elem = [String, Integer]]
6
+ class Counters < Hash
7
+ #: -> void
8
+ def initialize
9
+ super(0)
10
+ end
11
+
12
+ #: (String) -> void
13
+ def increment(key)
14
+ self[key] += 1
15
+ end
16
+
17
+ #: (String) -> Integer
18
+ def [](key)
19
+ super(key) #: as Integer
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,236 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Spoom
5
+ module Sorbet
6
+ module Metrics
7
+ class << self
8
+ #: (Array[String]) -> Spoom::Counters
9
+ def collect_code_metrics(files)
10
+ counters = Counters.new
11
+
12
+ files.each do |file|
13
+ counters.increment("files")
14
+
15
+ content = File.read(file)
16
+ node = Spoom.parse_ruby(content, file: file, comments: true)
17
+ visitor = CodeMetricsVisitor.new(counters)
18
+ visitor.visit(node)
19
+ end
20
+
21
+ counters
22
+ end
23
+ end
24
+
25
+ # Collects metrics about how Sorbet is used in the codebase.
26
+ #
27
+ # This approach is different from the metrics file we get directly from Sorbet.
28
+ #
29
+ # This visitor actually visits the codebase and collects metrics about the amount of signatures, `T.` calls,
30
+ # and other metrics. It also knows about RBS comments.
31
+ #
32
+ # On the other hand, the metrics file is a snapshot of the metrics at type checking time and knows about
33
+ # is calls are typed, how many assertions are done, etc.
34
+ class CodeMetricsVisitor < Spoom::Visitor
35
+ include RBS::ExtractRBSComments
36
+
37
+ #: Counters
38
+ attr_reader :counters
39
+
40
+ #: (Spoom::Counters) -> void
41
+ def initialize(counters)
42
+ super()
43
+
44
+ @counters = counters
45
+
46
+ @last_sigs = [] #: Array[Prism::CallNode]
47
+ @type_params = [] #: Array[Prism::CallNode]
48
+ end
49
+
50
+ # @override
51
+ #: (Prism::Node?) -> void
52
+ def visit(node)
53
+ return if node.nil?
54
+
55
+ node.location.trailing_comments.each do |comment|
56
+ text = comment.slice.strip
57
+ next unless text.start_with?("#:")
58
+
59
+ @counters.increment("rbs_assertions")
60
+
61
+ case text
62
+ when /^#: as !nil/
63
+ @counters.increment("rbs_must")
64
+ when /^#: as untyped/
65
+ @counters.increment("rbs_unsafe")
66
+ when /^#: as/
67
+ @counters.increment("rbs_cast")
68
+ when /^#:/
69
+ @counters.increment("rbs_let")
70
+ end
71
+ end
72
+
73
+ super
74
+ end
75
+
76
+ # @override
77
+ #: (Prism::ClassNode) -> void
78
+ def visit_class_node(node)
79
+ visit_scope(node) do
80
+ super
81
+ end
82
+ end
83
+
84
+ # @override
85
+ #: (Prism::ModuleNode) -> void
86
+ def visit_module_node(node)
87
+ visit_scope(node) do
88
+ super
89
+ end
90
+ end
91
+
92
+ # @override
93
+ #: (Prism::SingletonClassNode) -> void
94
+ def visit_singleton_class_node(node)
95
+ visit_scope(node) do
96
+ super
97
+ end
98
+ end
99
+
100
+ # @override
101
+ #: (Prism::DefNode) -> void
102
+ def visit_def_node(node)
103
+ unless node.name.to_s.start_with?("test_")
104
+ @counters.increment("methods")
105
+
106
+ rbs_sigs = node_rbs_comments(node).signatures
107
+ srb_sigs = collect_last_srb_sigs
108
+
109
+ if rbs_sigs.any?
110
+ @counters.increment("methods_with_rbs_sig")
111
+ end
112
+
113
+ if srb_sigs.any?
114
+ @counters.increment("methods_with_srb_sig")
115
+ end
116
+
117
+ if rbs_sigs.empty? && srb_sigs.empty?
118
+ @counters.increment("methods_without_sig")
119
+ end
120
+ end
121
+
122
+ super
123
+ end
124
+
125
+ # @override
126
+ #: (Prism::CallNode) -> void
127
+ def visit_call_node(node)
128
+ @counters.increment("calls")
129
+
130
+ case node.name
131
+ when :attr_accessor, :attr_reader, :attr_writer
132
+ visit_attr_accessor(node)
133
+ return
134
+ when :sig
135
+ visit_sig(node)
136
+ return
137
+ when :type_member, :type_template
138
+ visit_type_member(node)
139
+ return
140
+ end
141
+
142
+ case node.receiver&.slice
143
+ when /^(::)?T$/
144
+ @counters.increment("T_calls")
145
+ @counters.increment("T.#{node.name}")
146
+ end
147
+
148
+ super
149
+ end
150
+
151
+ private
152
+
153
+ #: (Prism::ClassNode | Prism::ModuleNode | Prism::SingletonClassNode) { -> void } -> void
154
+ def visit_scope(node, &block)
155
+ key = node_key(node)
156
+ @counters.increment(key)
157
+ @counters.increment("#{key}_with_rbs_type_params") if node_rbs_comments(node).signatures.any?
158
+
159
+ old_type_params = @type_params
160
+ @type_params = []
161
+
162
+ yield
163
+
164
+ @counters.increment("#{key}_with_srb_type_params") if @type_params.any?
165
+
166
+ @type_params = old_type_params
167
+ end
168
+
169
+ #: (Prism::CallNode) -> void
170
+ def visit_attr_accessor(node)
171
+ @counters.increment("accessors")
172
+
173
+ rbs_sigs = node_rbs_comments(node).signatures
174
+ srb_sigs = collect_last_srb_sigs
175
+
176
+ if rbs_sigs.any?
177
+ @counters.increment("accessors_with_rbs_sig")
178
+ end
179
+
180
+ if srb_sigs.any?
181
+ @counters.increment("accessors_with_srb_sig")
182
+ end
183
+
184
+ if rbs_sigs.empty? && srb_sigs.empty?
185
+ @counters.increment("accessors_without_sig")
186
+ end
187
+ end
188
+
189
+ #: (Prism::CallNode) -> void
190
+ def visit_sig(node)
191
+ @last_sigs << node
192
+ @counters.increment("srb_sigs")
193
+
194
+ if node.slice =~ /abstract/
195
+ @counters.increment("srb_sigs_abstract")
196
+ end
197
+ end
198
+
199
+ #: (Prism::CallNode) -> void
200
+ def visit_type_member(node)
201
+ key = case node.name
202
+ when :type_member
203
+ "type_members"
204
+ when :type_template
205
+ "type_templates"
206
+ else
207
+ return
208
+ end
209
+
210
+ @counters.increment(key)
211
+
212
+ @type_params << node
213
+ end
214
+
215
+ #: -> Array[Prism::CallNode]
216
+ def collect_last_srb_sigs
217
+ sigs = @last_sigs.dup
218
+ @last_sigs.clear
219
+ sigs
220
+ end
221
+
222
+ #: (Prism::ClassNode | Prism::ModuleNode | Prism::SingletonClassNode) -> String
223
+ def node_key(node)
224
+ case node
225
+ when Prism::ClassNode
226
+ "classes"
227
+ when Prism::ModuleNode
228
+ "modules"
229
+ when Prism::SingletonClassNode
230
+ "singleton_classes"
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end
236
+ end
@@ -0,0 +1,34 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "spoom/sorbet/sigils"
5
+
6
+ module Spoom
7
+ module Sorbet
8
+ module Metrics
9
+ module MetricsFileParser
10
+ DEFAULT_PREFIX = "ruby_typer.unknown."
11
+
12
+ class << self
13
+ #: (String path, ?String prefix) -> Hash[String, Integer]
14
+ def parse_file(path, prefix = DEFAULT_PREFIX)
15
+ parse_string(File.read(path), prefix)
16
+ end
17
+
18
+ #: (String string, ?String prefix) -> Hash[String, Integer]
19
+ def parse_string(string, prefix = DEFAULT_PREFIX)
20
+ parse_hash(JSON.parse(string), prefix)
21
+ end
22
+
23
+ #: (Hash[String, untyped] obj, ?String prefix) -> Counters
24
+ def parse_hash(obj, prefix = DEFAULT_PREFIX)
25
+ obj["metrics"].each_with_object(Counters.new) do |metric, metrics|
26
+ name = metric["name"].sub(prefix, "")
27
+ metrics[name] = metric["value"] || 0
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,33 +1,5 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative "sigils"
5
-
6
- module Spoom
7
- module Sorbet
8
- module MetricsParser
9
- DEFAULT_PREFIX = "ruby_typer.unknown."
10
-
11
- class << self
12
- #: (String path, ?String prefix) -> Hash[String, Integer]
13
- def parse_file(path, prefix = DEFAULT_PREFIX)
14
- parse_string(File.read(path), prefix)
15
- end
16
-
17
- #: (String string, ?String prefix) -> Hash[String, Integer]
18
- def parse_string(string, prefix = DEFAULT_PREFIX)
19
- parse_hash(JSON.parse(string), prefix)
20
- end
21
-
22
- #: (Hash[String, untyped] obj, ?String prefix) -> Hash[String, Integer]
23
- def parse_hash(obj, prefix = DEFAULT_PREFIX)
24
- obj["metrics"].each_with_object(Hash.new(0)) do |metric, metrics|
25
- name = metric["name"]
26
- name = name.sub(prefix, "")
27
- metrics[name] = metric["value"] || 0
28
- end
29
- end
30
- end
31
- end
32
- end
33
- end
4
+ require "spoom/sorbet/metrics/code_metrics_visitor"
5
+ require "spoom/sorbet/metrics/metrics_file_parser"
@@ -132,7 +132,6 @@ module Spoom
132
132
  comments.annotations.reverse_each do |annotation|
133
133
  from = adjust_to_line_start(annotation.location.start_offset)
134
134
  to = adjust_to_line_end(annotation.location.end_offset)
135
- @rewriter << Source::Delete.new(from, to)
136
135
 
137
136
  content = case annotation.string
138
137
  when "@abstract"
@@ -147,8 +146,12 @@ module Spoom
147
146
  srb_type = ::RBS::Parser.parse_type(annotation.string.delete_prefix("@requires_ancestor: "))
148
147
  rbs_type = RBI::RBS::TypeTranslator.translate(srb_type)
149
148
  "requires_ancestor { #{rbs_type} }"
149
+ else
150
+ next
150
151
  end
151
152
 
153
+ @rewriter << Source::Delete.new(from, to)
154
+
152
155
  newline = node.body.nil? ? "" : "\n"
153
156
  @rewriter << Source::Insert.new(insert_pos, "\n#{indent}#{content}#{newline}")
154
157
  end
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.7.0"
5
+ VERSION = "1.7.2"
6
6
  end
data/lib/spoom.rb CHANGED
@@ -18,6 +18,7 @@ require "spoom/model"
18
18
  require "spoom/source"
19
19
  require "spoom/deadcode"
20
20
  require "spoom/rbs"
21
+ require "spoom/counters"
21
22
  require "spoom/sorbet"
22
23
  require "spoom/cli"
23
24
  require "spoom/version"
data/rbi/spoom.rbi CHANGED
@@ -165,10 +165,19 @@ class Spoom::Cli::Srb::Main < ::Thor
165
165
  def coverage(*args); end
166
166
  def help(command = T.unsafe(nil), subcommand = T.unsafe(nil)); end
167
167
  def lsp(*args); end
168
+ def metrics(*args); end
168
169
  def sigs(*args); end
169
170
  def tc(*args); end
170
171
  end
171
172
 
173
+ class Spoom::Cli::Srb::Metrics < ::Thor
174
+ include ::Spoom::Colorize
175
+ include ::Spoom::Cli::Helper
176
+
177
+ def help(command = T.unsafe(nil), subcommand = T.unsafe(nil)); end
178
+ def show(*paths); end
179
+ end
180
+
172
181
  class Spoom::Cli::Srb::Sigs < ::Thor
173
182
  include ::Spoom::Colorize
174
183
  include ::Spoom::Cli::Helper
@@ -422,6 +431,17 @@ module Spoom::Context::Sorbet
422
431
  def write_sorbet_config!(contents, append: T.unsafe(nil)); end
423
432
  end
424
433
 
434
+ class Spoom::Counters < ::Hash
435
+ sig { void }
436
+ def initialize; end
437
+
438
+ sig { params(key: ::String).returns(::Integer) }
439
+ def [](key); end
440
+
441
+ sig { params(key: ::String).void }
442
+ def increment(key); end
443
+ end
444
+
425
445
  module Spoom::Coverage
426
446
  class << self
427
447
  sig { params(context: ::Spoom::Context).returns(::Spoom::FileTree) }
@@ -2445,29 +2465,25 @@ end
2445
2465
  class Spoom::ParseError < ::Spoom::Error; end
2446
2466
 
2447
2467
  class Spoom::Poset
2448
- extend T::Generic
2449
-
2450
- E = type_member { { upper: Object } }
2451
-
2452
2468
  sig { void }
2453
2469
  def initialize; end
2454
2470
 
2455
- sig { params(value: E).returns(Spoom::Poset::Element[E]) }
2471
+ sig { params(value: T.untyped).returns(Spoom::Poset::Element[T.untyped]) }
2456
2472
  def [](value); end
2457
2473
 
2458
- sig { params(from: E, to: E).void }
2474
+ sig { params(from: T.untyped, to: T.untyped).void }
2459
2475
  def add_direct_edge(from, to); end
2460
2476
 
2461
- sig { params(value: E).returns(Spoom::Poset::Element[E]) }
2477
+ sig { params(value: T.untyped).returns(Spoom::Poset::Element[T.untyped]) }
2462
2478
  def add_element(value); end
2463
2479
 
2464
- sig { params(from: E, to: E).returns(T::Boolean) }
2480
+ sig { params(from: T.untyped, to: T.untyped).returns(T::Boolean) }
2465
2481
  def direct_edge?(from, to); end
2466
2482
 
2467
- sig { params(from: E, to: E).returns(T::Boolean) }
2483
+ sig { params(from: T.untyped, to: T.untyped).returns(T::Boolean) }
2468
2484
  def edge?(from, to); end
2469
2485
 
2470
- sig { params(value: E).returns(T::Boolean) }
2486
+ sig { params(value: T.untyped).returns(T::Boolean) }
2471
2487
  def element?(value); end
2472
2488
 
2473
2489
  sig { params(direct: T::Boolean, transitive: T::Boolean).void }
@@ -2478,39 +2494,36 @@ class Spoom::Poset
2478
2494
  end
2479
2495
 
2480
2496
  class Spoom::Poset::Element
2481
- extend T::Generic
2482
2497
  include ::Comparable
2483
2498
 
2484
- E = type_member { { upper: Object } }
2485
-
2486
- sig { params(value: E).void }
2499
+ sig { params(value: T.untyped).void }
2487
2500
  def initialize(value); end
2488
2501
 
2489
2502
  sig { params(other: T.untyped).returns(T.nilable(::Integer)) }
2490
2503
  def <=>(other); end
2491
2504
 
2492
- sig { returns(T::Array[E]) }
2505
+ sig { returns(T::Array[T.untyped]) }
2493
2506
  def ancestors; end
2494
2507
 
2495
- sig { returns(T::Array[E]) }
2508
+ sig { returns(T::Array[T.untyped]) }
2496
2509
  def children; end
2497
2510
 
2498
- sig { returns(T::Array[E]) }
2511
+ sig { returns(T::Array[T.untyped]) }
2499
2512
  def descendants; end
2500
2513
 
2501
2514
  def dfroms; end
2502
2515
 
2503
- sig { returns(T::Set[Spoom::Poset::Element[E]]) }
2516
+ sig { returns(T::Set[Spoom::Poset::Element[T.untyped]]) }
2504
2517
  def dtos; end
2505
2518
 
2506
2519
  def froms; end
2507
2520
 
2508
- sig { returns(T::Array[E]) }
2521
+ sig { returns(T::Array[T.untyped]) }
2509
2522
  def parents; end
2510
2523
 
2511
2524
  def tos; end
2512
2525
 
2513
- sig { returns(E) }
2526
+ sig { returns(T.untyped) }
2514
2527
  def value; end
2515
2528
  end
2516
2529
 
@@ -2732,12 +2745,72 @@ Spoom::Sorbet::GEM_PATH = T.let(T.unsafe(nil), String)
2732
2745
  Spoom::Sorbet::GEM_VERSION = T.let(T.unsafe(nil), String)
2733
2746
  Spoom::Sorbet::KILLED_CODE = T.let(T.unsafe(nil), Integer)
2734
2747
 
2735
- module Spoom::Sorbet::MetricsParser
2748
+ module Spoom::Sorbet::Metrics
2749
+ class << self
2750
+ sig { params(files: T::Array[::String]).returns(Spoom::Counters) }
2751
+ def collect_code_metrics(files); end
2752
+ end
2753
+ end
2754
+
2755
+ class Spoom::Sorbet::Metrics::CodeMetricsVisitor < ::Spoom::Visitor
2756
+ include ::Spoom::RBS::ExtractRBSComments
2757
+
2758
+ sig { params(counters: Spoom::Counters).void }
2759
+ def initialize(counters); end
2760
+
2761
+ sig { returns(Spoom::Counters) }
2762
+ def counters; end
2763
+
2764
+ sig { override.params(node: T.nilable(::Prism::Node)).void }
2765
+ def visit(node); end
2766
+
2767
+ sig { override.params(node: ::Prism::CallNode).void }
2768
+ def visit_call_node(node); end
2769
+
2770
+ sig { override.params(node: ::Prism::ClassNode).void }
2771
+ def visit_class_node(node); end
2772
+
2773
+ sig { override.params(node: ::Prism::DefNode).void }
2774
+ def visit_def_node(node); end
2775
+
2776
+ sig { override.params(node: ::Prism::ModuleNode).void }
2777
+ def visit_module_node(node); end
2778
+
2779
+ sig { override.params(node: ::Prism::SingletonClassNode).void }
2780
+ def visit_singleton_class_node(node); end
2781
+
2782
+ private
2783
+
2784
+ sig { returns(T::Array[::Prism::CallNode]) }
2785
+ def collect_last_srb_sigs; end
2786
+
2787
+ sig { params(node: T.any(::Prism::ClassNode, ::Prism::ModuleNode, ::Prism::SingletonClassNode)).returns(::String) }
2788
+ def node_key(node); end
2789
+
2790
+ sig { params(node: ::Prism::CallNode).void }
2791
+ def visit_attr_accessor(node); end
2792
+
2793
+ sig do
2794
+ params(
2795
+ node: T.any(::Prism::ClassNode, ::Prism::ModuleNode, ::Prism::SingletonClassNode),
2796
+ block: T.proc.void
2797
+ ).void
2798
+ end
2799
+ def visit_scope(node, &block); end
2800
+
2801
+ sig { params(node: ::Prism::CallNode).void }
2802
+ def visit_sig(node); end
2803
+
2804
+ sig { params(node: ::Prism::CallNode).void }
2805
+ def visit_type_member(node); end
2806
+ end
2807
+
2808
+ module Spoom::Sorbet::Metrics::MetricsFileParser
2736
2809
  class << self
2737
2810
  sig { params(path: ::String, prefix: ::String).returns(T::Hash[::String, ::Integer]) }
2738
2811
  def parse_file(path, prefix = T.unsafe(nil)); end
2739
2812
 
2740
- sig { params(obj: T::Hash[::String, T.untyped], prefix: ::String).returns(T::Hash[::String, ::Integer]) }
2813
+ sig { params(obj: T::Hash[::String, T.untyped], prefix: ::String).returns(Spoom::Counters) }
2741
2814
  def parse_hash(obj, prefix = T.unsafe(nil)); end
2742
2815
 
2743
2816
  sig { params(string: ::String, prefix: ::String).returns(T::Hash[::String, ::Integer]) }
@@ -2745,7 +2818,7 @@ module Spoom::Sorbet::MetricsParser
2745
2818
  end
2746
2819
  end
2747
2820
 
2748
- Spoom::Sorbet::MetricsParser::DEFAULT_PREFIX = T.let(T.unsafe(nil), String)
2821
+ Spoom::Sorbet::Metrics::MetricsFileParser::DEFAULT_PREFIX = T.let(T.unsafe(nil), String)
2749
2822
  Spoom::Sorbet::SEGFAULT_CODE = T.let(T.unsafe(nil), Integer)
2750
2823
 
2751
2824
  module Spoom::Sorbet::Sigils
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spoom
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre Terrasa
@@ -185,6 +185,7 @@ files:
185
185
  - lib/spoom/cli/srb/bump.rb
186
186
  - lib/spoom/cli/srb/coverage.rb
187
187
  - lib/spoom/cli/srb/lsp.rb
188
+ - lib/spoom/cli/srb/metrics.rb
188
189
  - lib/spoom/cli/srb/sigs.rb
189
190
  - lib/spoom/cli/srb/tc.rb
190
191
  - lib/spoom/colors.rb
@@ -194,6 +195,7 @@ files:
194
195
  - lib/spoom/context/file_system.rb
195
196
  - lib/spoom/context/git.rb
196
197
  - lib/spoom/context/sorbet.rb
198
+ - lib/spoom/counters.rb
197
199
  - lib/spoom/coverage.rb
198
200
  - lib/spoom/coverage/d3.rb
199
201
  - lib/spoom/coverage/d3/base.rb
@@ -249,6 +251,8 @@ files:
249
251
  - lib/spoom/sorbet/lsp/errors.rb
250
252
  - lib/spoom/sorbet/lsp/structures.rb
251
253
  - lib/spoom/sorbet/metrics.rb
254
+ - lib/spoom/sorbet/metrics/code_metrics_visitor.rb
255
+ - lib/spoom/sorbet/metrics/metrics_file_parser.rb
252
256
  - lib/spoom/sorbet/sigils.rb
253
257
  - lib/spoom/sorbet/translate.rb
254
258
  - lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs.rb