debride 1.14.0 → 1.15.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: 3a714288d6ecf460fcc966b8affc300f4bfe72da8e7d955e1345d757fbe389e9
4
- data.tar.gz: '0608d18319513d0193482b503def7a86b7fc1544dfffb1048849d74b0b0d1728'
3
+ metadata.gz: 77baff9dbc4bab278d0e6b6fe16772ecdce26b00c4c7b24469e0680f0d608c41
4
+ data.tar.gz: 885b6274f63f3d76c6a106543d28be50f177fcc6fa6adad7cf642c0b3ef7f0d8
5
5
  SHA512:
6
- metadata.gz: c7faa53a9d8aaa8e1f6bb5673ac7619a357a34d75636eaaab43fc017814cac33805dcb0904385d19a4e1d32b95ccc6a01877083a379ee74e6c91847b4713e278
7
- data.tar.gz: ec449e3d4d5bdae20271e58d54da4dce6050866e56493d68f7ce236bb7829e51f342185576c5a772ee6e140e1855557598bd9062c5b9cc6f4d2112ea3fc16ed7
6
+ metadata.gz: 421c0cb4b4aa45ed2e7897254549def50af4f4491a029676bcc7671aa026e8cda45b9774073eef8d3bffa15665f7df0466e1b6a68f236fc0b0c2ee12806461a5
7
+ data.tar.gz: 2cc4e04095596764513090fffe356835d3af36c192395dbe7753470801e623f826bf72c54371de30bf1d9006d4cf109809cffc1419e887607914623cc8a1bb82
checksums.yaml.gz.sig CHANGED
Binary file
data/History.rdoc CHANGED
@@ -1,3 +1,18 @@
1
+ === 1.15.0 / 2026-01-02
2
+
3
+ * 1 minor enhancement:
4
+
5
+ * Added process_hash to handle hash shortcut syntax in case it is a call. (TSMMark)
6
+
7
+ * 6 bug fixes:
8
+
9
+ * Bump prism dependency to 1.7+.
10
+ * Load debride with require_relative in bin/debride.
11
+ * Minor fixes for prism 1.7 and ruby 4.0.
12
+ * Oops! Fixed --legacy option definition.
13
+ * Properly handle scope/alias_method with interoplation. (alagos)
14
+ * Removed prism patches now that they've been upstreamed.
15
+
1
16
  === 1.14.0 / 2025-12-11
2
17
 
3
18
  * 2 minor enhancements:
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ Hoe::add_include_dirs("../../sexp_processor/dev/lib",
11
11
  "../../path_expander/dev/lib",
12
12
  "lib")
13
13
 
14
- Hoe.plugin :isolate
14
+ Hoe.plugin :isolate_binaries
15
15
  Hoe.plugin :seattlerb
16
16
  Hoe.plugin :rdoc
17
17
  Hoe.plugin :cov
@@ -21,7 +21,7 @@ Hoe.spec "debride" do
21
21
  license "MIT"
22
22
 
23
23
  dependency "sexp_processor", "~> 4.17"
24
- dependency "prism", "~> 1.5"
24
+ dependency "prism", "~> 1.7"
25
25
  dependency "path_expander", "~> 2.0"
26
26
  end
27
27
 
data/bin/debride CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env -S ruby -w
2
2
 
3
- require "debride"
3
+ require_relative "../lib/debride"
4
4
 
5
5
  Debride.run(ARGV).report
data/lib/debride.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require "optparse"
4
4
  require "set"
5
5
  require "stringio"
6
+ require "timeout"
6
7
 
7
8
  require "sexp_processor"
8
9
  require "path_expander"
@@ -10,13 +11,6 @@ require "path_expander"
10
11
  require "prism"
11
12
  require "prism/translation/ruby_parser"
12
13
 
13
- unless Prism::Translation::RubyParser.method_defined? :process then
14
- class Prism::Translation::RubyParser # compatibility layer
15
- def process(ruby, file, timeout=nil) =
16
- Timeout.timeout(timeout) { parse ruby, file }
17
- end
18
- end
19
-
20
14
  class NotRubyParser < Prism::Translation::RubyParser # compatibility layer
21
15
  end
22
16
 
@@ -24,7 +18,7 @@ end
24
18
  # A static code analyzer that points out possible dead methods.
25
19
 
26
20
  class Debride < MethodBasedSexpProcessor
27
- VERSION = "1.14.0" # :nodoc:
21
+ VERSION = "1.15.0" # :nodoc:
28
22
  PROJECT = "debride"
29
23
 
30
24
  def self.load_plugins proj = PROJECT
@@ -108,8 +102,8 @@ class Debride < MethodBasedSexpProcessor
108
102
  end
109
103
 
110
104
  parser = option[:parser].new
111
- parser.process(file, path, option[:timeout])
112
- rescue Racc::ParseError, RegexpError => e
105
+ parser.process file, path, option[:timeout]
106
+ rescue RubyParser::SyntaxError, RegexpError => e
113
107
  warn "Parse Error parsing #{path}. Skipping."
114
108
  warn " #{e.message}"
115
109
  rescue Timeout::Error
@@ -172,7 +166,7 @@ class Debride < MethodBasedSexpProcessor
172
166
  options[:minimum] = n
173
167
  end
174
168
 
175
- opts.on "--legacy" "Use RubyParser for parsing." do
169
+ opts.on "--legacy", "Use RubyParser for parsing." do
176
170
  require "ruby_parser"
177
171
  option[:parser] = RubyParser
178
172
  end
@@ -349,27 +343,30 @@ class Debride < MethodBasedSexpProcessor
349
343
  end
350
344
  when *RAILS_MACRO_METHODS
351
345
  # s(:call, nil, :has_one, s(:lit, :has_one_relation), ...)
352
- _, _, _, (_, name), * = sexp
346
+ _, _, _, name, * = sexp
353
347
 
354
348
  # try to detect route scope vs model scope
355
349
  if context.include? :module or context.include? :class then
356
- file, line = sexp.file, sexp.line
357
- record_method name, file, line
350
+ if string_like? name then
351
+ file, line = sexp.file, sexp.line
352
+ record_method name.last, file, line
353
+ end
358
354
  end
359
355
  when /_path$/ then
360
356
  method_name = method_name.to_s.delete_suffix("_path").to_sym if option[:rails]
361
357
  when /^deliver_/ then
362
358
  method_name = method_name.to_s.delete_prefix("deliver_").to_sym if option[:rails]
363
359
  when :alias_method then
360
+ # s(:call, nil, :alias_method, lhs, rhs)
364
361
  _, _, _, lhs, rhs = sexp
365
362
 
366
- if Sexp === lhs and Sexp === rhs then
367
- lhs = lhs.last
368
- rhs = rhs.last
363
+ if string_like? lhs and string_like? rhs then
364
+ lhs = lhs.last.to_sym
365
+ rhs = rhs.last.to_sym
369
366
 
370
367
  record_method lhs, sexp.file, sexp.line
371
368
 
372
- called << rhs
369
+ called << rhs # TODO: why?
373
370
  end
374
371
  end
375
372
 
@@ -380,6 +377,10 @@ class Debride < MethodBasedSexpProcessor
380
377
  sexp
381
378
  end
382
379
 
380
+ def string_like? s
381
+ Sexp === s and %i[lit str].include?(s.sexp_type)
382
+ end
383
+
383
384
  def process_alias exp
384
385
  _, (_, lhs), (_, rhs) = exp
385
386
 
@@ -482,6 +483,21 @@ class Debride < MethodBasedSexpProcessor
482
483
 
483
484
  alias process_safe_call process_call
484
485
 
486
+ def process_hash sexp
487
+ _, *pairs = sexp
488
+
489
+ pairs.each_slice 2 do |k, v|
490
+ if v.nil? && k.sexp_type == :lit then
491
+ called << k.last
492
+ else
493
+ process k
494
+ process v
495
+ end
496
+ end
497
+
498
+ sexp
499
+ end
500
+
485
501
  ##
486
502
  # Calculate the difference between known methods and called methods.
487
503
 
data/test/test_debride.rb CHANGED
@@ -20,6 +20,7 @@ class TestDebride < Minitest::Test
20
20
  :process_const,
21
21
  :process_defn,
22
22
  :process_defs,
23
+ :process_hash,
23
24
  :process_op_asgn2,
24
25
  :process_rb,
25
26
  :process_safe_call,
@@ -46,13 +47,15 @@ class TestDebride < Minitest::Test
46
47
  assert_equal exp_arg, arg
47
48
  end
48
49
 
49
- def assert_process exp, ruby, opts = {}
50
+ def assert_process exp, ruby, called:nil, **opts
50
51
  io = StringIO.new ruby
51
52
 
52
53
  debride = Debride.new opts
53
54
  debride.process debride.process_rb io
54
55
 
55
56
  assert_equal exp, debride.missing
57
+ assert_equal Set[*called], debride.called if called
58
+
56
59
  debride
57
60
  end
58
61
 
@@ -240,6 +243,40 @@ class TestDebride < Minitest::Test
240
243
  assert_process [], s
241
244
  end
242
245
 
246
+ def test_call__alias_method__symbol
247
+ ruby = <<~'RUBY'
248
+ class QuarterPounder
249
+ alias_method :get_x, :x
250
+ end
251
+ RUBY
252
+
253
+ exp = [["QuarterPounder", [:get_x]]]
254
+
255
+ assert_process exp, ruby, called:%i[x alias_method]
256
+ end
257
+
258
+ def test_call__alias_method__string
259
+ ruby = <<~'RUBY'
260
+ class QuarterPounder
261
+ alias_method "get_x", "x"
262
+ end
263
+ RUBY
264
+
265
+ exp = [["QuarterPounder", [:get_x]]]
266
+
267
+ assert_process exp, ruby, called:%i[x alias_method]
268
+ end
269
+
270
+ def test_call__alias_method__interpolated
271
+ ruby = <<~'RUBY'
272
+ class QuarterPounder
273
+ alias_method "get_#{integr}", integr
274
+ end
275
+ RUBY
276
+
277
+ assert_process [], ruby, called:%i[integr alias_method]
278
+ end
279
+
243
280
  def test_alias_method_chain
244
281
  ruby = <<-RUBY.strip
245
282
  class QuarterPounder
@@ -352,6 +389,42 @@ class TestDebride < Minitest::Test
352
389
  assert_process [], ruby
353
390
  end
354
391
 
392
+ def test_hash__shorthand
393
+ ruby = <<-RUBY.strip
394
+ class Seattle
395
+ def self.status
396
+ { raining: }
397
+ end
398
+
399
+ def self.raining
400
+ true
401
+ end
402
+ end
403
+
404
+ Seattle.status
405
+ RUBY
406
+
407
+ assert_process [], ruby
408
+ end
409
+
410
+ def test_hash__not_shorthand
411
+ ruby = <<-RUBY.strip
412
+ class Seattle
413
+ def self.status
414
+ { missing: }
415
+ end
416
+
417
+ def self.raining
418
+ true
419
+ end
420
+ end
421
+
422
+ Seattle.status
423
+ RUBY
424
+
425
+ assert_process [["Seattle", [:raining]]], ruby
426
+ end
427
+
355
428
  def test_safe_navigation_operator
356
429
  ruby = <<-RUBY.strip
357
430
  class Seattle
@@ -412,7 +485,7 @@ class TestDebride < Minitest::Test
412
485
  end
413
486
 
414
487
  def test_rails_dsl_macro_definitions
415
- ruby = <<-RUBY.strip
488
+ ruby = <<~'RUBY'
416
489
  class RailsModel
417
490
  has_one :has_one_relation
418
491
  has_one :uncalled_has_one_relation
@@ -424,6 +497,9 @@ class TestDebride < Minitest::Test
424
497
  has_and_belongs_to_many :uncalled_has_and_belongs_to_many_relation
425
498
  scope :scope_method
426
499
  scope :uncalled_scope_method
500
+ scope :"interpolated_#{method}"
501
+ scope "another_#{method}"
502
+ scope "yet_another_#{method}".to_sym
427
503
 
428
504
  def instance_method_caller
429
505
  has_one_relation
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: debride
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.14.0
4
+ version: 1.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Davis
@@ -50,14 +50,14 @@ dependencies:
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '1.5'
53
+ version: '1.7'
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '1.5'
60
+ version: '1.7'
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: path_expander
63
63
  requirement: !ruby/object:Gem::Requirement
@@ -78,20 +78,20 @@ dependencies:
78
78
  requirements:
79
79
  - - ">="
80
80
  - !ruby/object:Gem::Version
81
- version: '4.0'
81
+ version: '6.0'
82
82
  - - "<"
83
83
  - !ruby/object:Gem::Version
84
- version: '7'
84
+ version: '8'
85
85
  type: :development
86
86
  prerelease: false
87
87
  version_requirements: !ruby/object:Gem::Requirement
88
88
  requirements:
89
89
  - - ">="
90
90
  - !ruby/object:Gem::Version
91
- version: '4.0'
91
+ version: '6.0'
92
92
  - - "<"
93
93
  - !ruby/object:Gem::Version
94
- version: '7'
94
+ version: '8'
95
95
  - !ruby/object:Gem::Dependency
96
96
  name: simplecov
97
97
  requirement: !ruby/object:Gem::Requirement
@@ -112,14 +112,14 @@ dependencies:
112
112
  requirements:
113
113
  - - "~>"
114
114
  - !ruby/object:Gem::Version
115
- version: '4.3'
115
+ version: '4.5'
116
116
  type: :development
117
117
  prerelease: false
118
118
  version_requirements: !ruby/object:Gem::Requirement
119
119
  requirements:
120
120
  - - "~>"
121
121
  - !ruby/object:Gem::Version
122
- version: '4.3'
122
+ version: '4.5'
123
123
  description: Analyze code for potentially uncalled / dead methods, now with auto-removal.
124
124
  email:
125
125
  - ryand-ruby@zenspider.com
metadata.gz.sig CHANGED
Binary file