debride 1.10.1 → 1.12.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: 6967abff5ba6b28f0e9883d615830a93e7fcb2dbeb2eaafa665ececa1fed39ce
4
- data.tar.gz: b52412f613a2149775cd552e08f44f616ad1c5c89d0ae3fa1dca6f3ce0ffabeb
3
+ metadata.gz: e23117d21c55f9b3a52eb52b6bbd068167cb1b5852650359e62809ed8de15f1b
4
+ data.tar.gz: 231f1adaefd3cfb507d2352c72a7af1200e3db691d1617186f1cd4bc561e68e8
5
5
  SHA512:
6
- metadata.gz: fc77db06b93e7401cb6a723b1db1532e6c75fba1216301bb4037ae5c6516fcc577931186f1a9ebc9a4fb452403b92f984ab7dca1abcb312cfb0c921d400f32fd
7
- data.tar.gz: 48a62586d3131f682447f5855276ab43e9de334ea791c8d2afa6e9bd49e3ff77007b3be10c00c03f934648f97f62a71871db69169060be3b4a92d432d364495b
6
+ metadata.gz: bea8df45994be8ac31ddf803ec258fcc03054f2f2d3fbed6fd13124bf3c38125398c2f24e5de81e36460305c30b650c4bba2e0f7664854fb0a741085d4d2a138
7
+ data.tar.gz: d9465fbd7fd9404c7b5b381b7d98a40bed4da3de1f87ac39ae11bd13e25a6eb957380537de02f8bd41a6247629f5e6cfe0da975b4dff216850a68bb2d84051d5
checksums.yaml.gz.sig CHANGED
Binary file
data/History.rdoc CHANGED
@@ -1,3 +1,34 @@
1
+ === 1.12.0 / 2023-05-18
2
+
3
+ * 1 major enhancement:
4
+
5
+ * Massive overhaul of bin/debride_rm: faster, cleaner, can run a command between each deletion.
6
+
7
+ * 2 minor enhancements:
8
+
9
+ * Added alias_method and alias as pseudo-calls to source method.
10
+ * Whitelist extended/included/prepended etc by default.
11
+
12
+ * 6 bug fixes:
13
+
14
+ * Added missing rails validation.
15
+ * Bumped sexp_processor and ruby_parser dependencies.
16
+ * Fix --exclude <dir> to properly exclude whole tree.
17
+ * Fixed --exclude option to make it repeatable.
18
+ * Fixed bug on anonymous block forwarding (eg fn(&)). (afuno)
19
+ * Use RubyParser.new instead of RubyParser.for_current_ruby.
20
+
21
+ === 1.11.0 / 2023-03-24
22
+
23
+ * 6 minor enhancements:
24
+
25
+ * Added X.const_get(:Y) support. (TSMMark)
26
+ * Added f(&block_pass) support. (TSMMark)
27
+ * Added obj&.safe_call support. (TSMMark)
28
+ * Added obj.method(:msg) support. (TSMMark)
29
+ * Added op_asgn2 (eg x &&= y) support. (TSMMark)
30
+ * Added try(:msg) support. (TSMMark)
31
+
1
32
  === 1.10.1 / 2022-12-03
2
33
 
3
34
  * 4 minor enhancements:
data/README.rdoc CHANGED
@@ -42,7 +42,7 @@ API), then you can whitelist it:
42
42
  MyClass
43
43
  bad_method lib/some/file.rb:20
44
44
  ...
45
-
45
+
46
46
  Usage example for a typical rails application:
47
47
  # dump rake routes into a file
48
48
  % rake routes > routes.txt
@@ -53,13 +53,48 @@ Usage example for a typical rails application:
53
53
  % echo down >> whitelist.txt
54
54
  % echo change >> whitelist.txt
55
55
  # output debride report co standard output with the following options:
56
- # ignore typical rails methods,
56
+ # ignore typical rails methods,
57
57
  # specify generated whitelist,
58
58
  # run in current directory (".")
59
59
  % debride --rails --whitelist whitelist.txt .
60
60
 
61
61
  You can also use regexps in your whitelist by delimiting them with //'s.
62
62
 
63
+ To generate a whitelist for the last 28 days worth of logs on papertrail:
64
+
65
+ % seq 2 29 | xargs -I {} date -u -v-{}d +%Y-%m-%d | \
66
+ xargs -I {} curl --progress-bar -f --no-include -L -H "X-Papertrail-Token: $PAPERTRAIL_APIKEY" https://papertrailapp.com/api/v1/archives/{}/download | \
67
+ gzip -dc | grep production.log | cut -f 10- | \
68
+ debride_rails_whitelist routes.txt - | sort -u > whitelist.txt
69
+
70
+ == debride_rm
71
+
72
+ debride_rm will automatically remove dead code and optionally run a
73
+ command in between each removal. The command will automatically
74
+ substitute "NAME" and "PATH" with the name and path of the thing being
75
+ removed. Eg:
76
+
77
+ % debride_rm -C="git commit -m 'debride NAME in PATH' ." \
78
+ --rails \
79
+ --whitelist whitelist.txt \
80
+ --exclude test \
81
+ --exclude script \
82
+ --exclude bin \
83
+ --minimum 30
84
+
85
+ This command will:
86
+
87
+ 1. run with rails extensions on
88
+ 2. treat anything named in whitelist.txt as "called"
89
+ 3. exclude directories that shouldn't be scanned or mutated
90
+ 4. exclude anything under 30 lines long
91
+
92
+ One thing to note, debride_rm doesn't do terribly well with things
93
+ like attr_accessor lists, so running debride_rm with --minimum 2 (or
94
+ more) is wise.
95
+
96
+ Strategy: start large (40+) and work your way down.
97
+
63
98
  == PLUGINS:
64
99
 
65
100
  debride-erb :: Extends debride to analyze erb files (via erubis ala rails).
@@ -69,7 +104,7 @@ debride-slim :: Extends debride to analyze Slim files
69
104
 
70
105
  == EDITOR INTEGRATION:
71
106
 
72
- TextMate 2 :: * {Debride-Rails.tmbundle}[https://github.com/jjuliano/Debride-Rails.tmbundle] - Debride with Rails support
107
+ TextMate 2 :: * {Debride-Rails.tmbundle}[https://github.com/jjuliano/Debride-Rails.tmbundle] - Debride with Rails support
73
108
  * {Debride.tmbundle}[https://github.com/jjuliano/Debride-Rails.tmbundle] - Debride for Ruby
74
109
 
75
110
  == REQUIREMENTS:
data/Rakefile CHANGED
@@ -7,6 +7,7 @@ Hoe::add_include_dirs("../../sexp_processor/dev/lib",
7
7
  "../../ruby_parser/dev/lib",
8
8
  "../../ruby2ruby/dev/lib",
9
9
  "../../ZenTest/dev/lib",
10
+ "../../debride-erb/dev/lib",
10
11
  "../../path_expander/dev/lib",
11
12
  "lib")
12
13
 
@@ -19,8 +20,8 @@ Hoe.spec "debride" do
19
20
  developer "Ryan Davis", "ryand-ruby@zenspider.com"
20
21
  license "MIT"
21
22
 
22
- dependency "sexp_processor", "~> 4.5"
23
- dependency "ruby_parser", "~> 3.6"
23
+ dependency "sexp_processor", "~> 4.17"
24
+ dependency "ruby_parser", "~> 3.20"
24
25
  dependency "path_expander", "~> 1.0"
25
26
  end
26
27
 
@@ -28,7 +29,9 @@ def run dir, whitelist
28
29
  abort "Specify dir to scan with D=<path>" unless dir
29
30
 
30
31
  ENV["GEM_HOME"] = "tmp/isolate"
31
- ENV["GEM_PATH"] = "../../debride-erb/dev/tmp/isolate"
32
+ ENV["GEM_PATH"] = "#{Gem.paths.path.join ":"}:../../debride-erb/dev/tmp/isolate"
33
+
34
+ Gem.paths = ENV
32
35
 
33
36
  whitelist = whitelist && ["--whitelist", whitelist]
34
37
  verbose = ENV["V"] && "-v"
data/bin/debride_rm CHANGED
@@ -1,96 +1,59 @@
1
- #!/usr/bin/ruby -w
1
+ #!/usr/bin/env ruby -ws
2
2
 
3
- def autoclave nuke
4
- skips = 0
3
+ $C ||= false # command to run between deletions
5
4
 
6
- nuke.each do |path, ary|
7
- # warn path
5
+ require "set"
6
+ require_relative "../lib/debride"
8
7
 
9
- file = File.readlines path
8
+ def autoclave nuke, cmd
9
+ nuke.each do |path, lines_to_remove, klass, name|
10
+ warn "#{path} #{lines_to_remove} #{klass}##{name}"
10
11
 
11
- ary.each do |(line, name)|
12
- opener = file[line-1]
13
-
14
- case opener
15
- when /^\s*def/
16
- # do nothing
17
- else # attr_accessor, etc
18
- # warn " unsupported: #{opener.strip}"
19
- skips += 1
20
- next
21
- end
22
-
23
- leader = opener[/^\s+/]
24
- end_line = file[line..-1].find_index { |l| l =~ /^#{leader}end/ }
25
-
26
- if end_line then
27
- end_line += line + 1
28
- end_line += 1 while file[end_line] =~ /^\s*$/
29
- end_line += 1 while file[end_line] =~ /^\s*alias.*?\b#{name}$/
30
- end_line += 1 while file[end_line] =~ /^\s*$/
31
-
32
- end_line.downto line do |i|
33
- file.delete_at(i-1)
34
- end
35
- else
36
- warn "NOT FOUND: ending for #{name} #{path}:#{line}"
37
- end
38
- end
12
+ file = File.foreach(path).with_index.map { |l, i| [i+1, l] }
39
13
 
40
14
  File.open path, "w" do |f|
41
- f.write file.join
42
- end
43
- end
44
-
45
- print " skips = %3d" % skips if skips > 0
46
- end
47
-
48
- def read_debride path
49
- nuke = Hash.new { |h,k| h[k] = [] }
50
-
51
- count = 0
52
-
53
- File.foreach path do |line|
54
- case line
55
- when /^ (\S+)\s+(\S+):(\d+)$/ then
56
- name, path, line = $1, $2, $3.to_i
57
- nuke[path] << [line, name]
58
- count += 1
59
- when /^[\w:]+$/, "\n", /:$/ then
60
- # ignore
61
- else
62
- warn "unparsed: #{line.chomp}"
15
+ file.each do |idx, line|
16
+ # skip empty line after a removed line
17
+ next if line.chomp.empty? && lines_to_remove.include?(idx-1)
18
+ f.write line unless lines_to_remove.include? idx
19
+ end
63
20
  end
64
- end
65
21
 
66
- nuke.each do |k, ary|
67
- nuke[k] = ary.sort.reverse
22
+ `#{cmd.gsub(/\bNAME\b/, "#{klass}##{name}").gsub(/\bPATH\b/, path)}` if cmd
68
23
  end
69
-
70
- [nuke, count]
71
24
  end
72
25
 
73
26
  iter = 0
74
27
  old_count = nil
75
28
 
76
- abort "usage: #{$0} [debride args]+" if ARGV.empty? or ARGV.include? "-h"
77
-
78
- cmd = %w[debride] + ARGV + %w[> dummy_for_cmd_below]
29
+ abort "usage: #{$0} [-C=cmd] [debride args]+" if ARGV.empty? or ARGV.include? "-h"
79
30
 
80
31
  loop do
81
32
  iter += 1
82
- dead = "dead%02d.txt" % iter
83
- cmd[-1] = dead
84
33
 
85
- Process.wait Process.spawn cmd.join " "
86
- abort "debride failed: #{$?}" unless $?.success?
34
+ debride = Debride.run ARGV.dup
35
+
36
+ min = debride.option[:minimum] || 0
37
+
38
+ nuke = debride.missing_locations
39
+ .flat_map { |klass, meths|
40
+ meths
41
+ .reject { |(meth, loc)| !loc }
42
+ .map { |(meth, loc)|
43
+ path, start, finish = /^(.+):(\d+)(?:-(\d+))?$/.match(loc).captures
44
+ finish ||= start
45
+ [path, start.to_i..finish.to_i, klass, meth]
46
+ }
47
+ .reject { |p,r,k,m| r.size <= min }
48
+ }
49
+ .sort_by { |p,r,k,m| [p, -r.begin, m] }
87
50
 
88
- nuke, count = read_debride dead
51
+ count = nuke.size
89
52
 
90
- break if old_count == count
53
+ break if count.zero? || old_count == count
91
54
  old_count = count
92
55
 
93
- print "iter = %2d count = %4d" % [iter, count]
94
- autoclave nuke
56
+ puts "iter = %2d count = %4d" % [iter, count]
57
+ autoclave nuke, $C
95
58
  puts
96
59
  end
data/lib/debride.rb CHANGED
@@ -12,7 +12,7 @@ require "path_expander"
12
12
  # A static code analyzer that points out possible dead methods.
13
13
 
14
14
  class Debride < MethodBasedSexpProcessor
15
- VERSION = "1.10.1" # :nodoc:
15
+ VERSION = "1.12.0" # :nodoc:
16
16
  PROJECT = "debride"
17
17
 
18
18
  def self.load_plugins proj = PROJECT
@@ -56,7 +56,7 @@ class Debride < MethodBasedSexpProcessor
56
56
  expander = PathExpander.new(args, glob)
57
57
  files = expander.process
58
58
  excl = debride.option[:exclude]
59
- excl.map! { |fd| File.directory?(fd) ? "#{fd}/" : fd } if excl
59
+ excl.map! { |fd| File.directory?(fd) ? "#{fd}/**/*" : fd } if excl
60
60
 
61
61
  files = expander.filter_files files, StringIO.new(excl.join "\n") if excl
62
62
 
@@ -97,8 +97,7 @@ class Debride < MethodBasedSexpProcessor
97
97
  raise "Unhandled type: #{path_or_io.class}:#{path_or_io.inspect}"
98
98
  end
99
99
 
100
- rp = RubyParser.for_current_ruby rescue RubyParser.new
101
- rp.process(file, path, option[:timeout])
100
+ RubyParser.new.process(file, path, option[:timeout])
102
101
  rescue Racc::ParseError, RegexpError => e
103
102
  warn "Parse Error parsing #{path}. Skipping."
104
103
  warn " #{e.message}"
@@ -111,7 +110,15 @@ class Debride < MethodBasedSexpProcessor
111
110
 
112
111
  def self.parse_options args
113
112
  options = {
114
- :whitelist => [],
113
+ :whitelist => %i[
114
+ extended
115
+ included
116
+ inherited
117
+ method_added
118
+ method_missing
119
+ prepended
120
+ ],
121
+ :exclude => [],
115
122
  :format => :text,
116
123
  }
117
124
 
@@ -129,7 +136,7 @@ class Debride < MethodBasedSexpProcessor
129
136
  end
130
137
 
131
138
  opts.on("-e", "--exclude FILE1,FILE2,ETC", Array, "Exclude files or directories in comma-separated list.") do |list|
132
- options[:exclude] = list
139
+ options[:exclude].concat list
133
140
  end
134
141
 
135
142
  opts.on("-w", "--whitelist FILE", String, "Whitelist these messages.") do |s|
@@ -220,6 +227,14 @@ class Debride < MethodBasedSexpProcessor
220
227
  sexp
221
228
  end
222
229
 
230
+ # handle &&=, ||=, etc
231
+ def process_op_asgn2(sexp)
232
+ _, _, method_name, * = sexp
233
+ called << method_name
234
+ process_until_empty sexp
235
+ sexp
236
+ end
237
+
223
238
  def record_method name, file, line
224
239
  signature = "#{klass_name}##{name}"
225
240
  method_locations[signature] = "#{file}:#{line}"
@@ -273,7 +288,7 @@ class Debride < MethodBasedSexpProcessor
273
288
  end
274
289
  record_method name, file, line
275
290
  end
276
- when :send, :public_send, :__send__ then
291
+ when :send, :public_send, :__send__, :try, :const_get then
277
292
  # s(:call, s(:const, :Seattle), :send, s(:lit, :raining?))
278
293
  _, _, _, msg_arg, * = sexp
279
294
  if Sexp === msg_arg && [:lit, :str].include?(msg_arg.sexp_type) then
@@ -291,6 +306,12 @@ class Debride < MethodBasedSexpProcessor
291
306
  called << val.last.to_sym if val.sexp_type == :str
292
307
  end
293
308
  end
309
+ when :method then
310
+ # s(:call, nil, :method, s(:lit, :foo))
311
+ _, _, _, msg_arg, * = sexp
312
+ if Sexp === msg_arg && [:lit, :str].include?(msg_arg.sexp_type) then
313
+ called << msg_arg.last.to_sym
314
+ end
294
315
  when *RAILS_DSL_METHODS, *RAILS_VALIDATION_METHODS then
295
316
  if option[:rails]
296
317
  # s(:call, nil, :before_save, s(:lit, :save_callback), s(:hash, ...))
@@ -320,6 +341,17 @@ class Debride < MethodBasedSexpProcessor
320
341
  method_name = method_name.to_s.delete_suffix("_path").to_sym if option[:rails]
321
342
  when /^deliver_/ then
322
343
  method_name = method_name.to_s.delete_prefix("deliver_").to_sym if option[:rails]
344
+ when :alias_method then
345
+ _, _, _, lhs, rhs = sexp
346
+
347
+ if Sexp === lhs and Sexp === rhs then
348
+ lhs = lhs.last
349
+ rhs = rhs.last
350
+
351
+ record_method lhs, sexp.file, sexp.line
352
+
353
+ called << rhs
354
+ end
323
355
  end
324
356
 
325
357
  called << method_name
@@ -329,6 +361,33 @@ class Debride < MethodBasedSexpProcessor
329
361
  sexp
330
362
  end
331
363
 
364
+ def process_alias exp
365
+ _, (_, lhs), (_, rhs) = exp
366
+
367
+ record_method lhs, exp.file, exp.line
368
+
369
+ called << rhs
370
+
371
+ exp
372
+ end
373
+
374
+ def process_block_pass exp # :nodoc:
375
+ _, name = exp
376
+
377
+ return exp unless name
378
+
379
+ case name.sexp_type
380
+ when :lit then # eg &:to_sym
381
+ called << name.last
382
+ else # eg &lvar or &method(:x)
383
+ # do nothing, body will get processed below
384
+ end
385
+
386
+ process_until_empty exp
387
+
388
+ exp
389
+ end
390
+
332
391
  def process_cdecl exp # :nodoc:
333
392
  _, name, val = exp
334
393
 
@@ -348,7 +407,7 @@ class Debride < MethodBasedSexpProcessor
348
407
 
349
408
  def name_to_string exp
350
409
  case exp.sexp_type
351
- when :const then
410
+ when :const, :lit, :str then
352
411
  exp.last.to_s
353
412
  when :colon2 then
354
413
  _, lhs, rhs = exp
@@ -402,6 +461,8 @@ class Debride < MethodBasedSexpProcessor
402
461
  end
403
462
  end
404
463
 
464
+ alias process_safe_call process_call
465
+
405
466
  ##
406
467
  # Calculate the difference between known methods and called methods.
407
468
 
@@ -532,6 +593,10 @@ class Debride < MethodBasedSexpProcessor
532
593
  YAML.dump data, io
533
594
  end
534
595
 
596
+ def inspect
597
+ "Debride[current=%s]" % [signature]
598
+ end
599
+
535
600
  ##
536
601
  # Rails' macro-style methods that setup method calls to happen during a rails
537
602
  # app's execution.
@@ -541,7 +606,7 @@ class Debride < MethodBasedSexpProcessor
541
606
  :around_action,
542
607
  :before_action,
543
608
 
544
- # http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
609
+ # https://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html (at bottom)
545
610
  :after_commit,
546
611
  :after_create,
547
612
  :after_destroy,
@@ -562,7 +627,7 @@ class Debride < MethodBasedSexpProcessor
562
627
  :before_update,
563
628
  :before_validation,
564
629
 
565
- # http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validate
630
+ # https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validate
566
631
  :validate,
567
632
  ]
568
633
 
@@ -575,6 +640,7 @@ class Debride < MethodBasedSexpProcessor
575
640
  :validates,
576
641
  :validates_absence_of,
577
642
  :validates_acceptance_of,
643
+ :validates_comparison_of,
578
644
  :validates_confirmation_of,
579
645
  :validates_exclusion_of,
580
646
  :validates_format_of,
data/test/test_debride.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require "minitest/autorun"
2
2
  require "debride"
3
3
 
4
+ $: << "../../debride-erb/dev/tmp/isolate"
5
+
4
6
  class SafeDebride < Debride
5
7
  def self.abort s
6
8
  raise s
@@ -9,15 +11,18 @@ end
9
11
 
10
12
  class TestDebride < Minitest::Test
11
13
  EXP_LIST = [["Debride",
12
- [:process_attrasgn,
13
- :process_call,
14
+ [:process_alias,
15
+ :process_attrasgn,
16
+ :process_block_pass,
14
17
  :process_cdecl,
15
18
  :process_colon2,
16
19
  :process_colon3,
17
20
  :process_const,
18
21
  :process_defn,
19
22
  :process_defs,
23
+ :process_op_asgn2,
20
24
  :process_rb,
25
+ :process_safe_call,
21
26
  :report,
22
27
  :report_json,
23
28
  :report_text,
@@ -29,10 +34,14 @@ class TestDebride < Minitest::Test
29
34
 
30
35
  EXP_FORMATTED = { :missing => formatted_vals }
31
36
 
37
+ make_my_diffs_pretty!
38
+
32
39
  def assert_option arg, exp_arg, exp_opt
33
40
  opt = SafeDebride.parse_options arg
34
41
 
35
- exp_opt = {:whitelist => [], :format => :text}.merge exp_opt
42
+ wl = [:extended, :included, :inherited, :method_added, :method_missing, :prepended]
43
+
44
+ exp_opt = {:whitelist => wl, :exclude => [], :format => :text}.merge exp_opt
36
45
  assert_equal exp_opt, opt
37
46
  assert_equal exp_arg, arg
38
47
  end
@@ -141,7 +150,7 @@ class TestDebride < Minitest::Test
141
150
  debride.report(io)
142
151
 
143
152
  exp = JSON.load JSON.dump EXP_FORMATTED # force stringify
144
- data = JSON.load io.string.gsub(/\d+-\d+/, "###")
153
+ data = JSON.load io.string.gsub(/:\d+(-\d+)?/, ":###")
145
154
 
146
155
  assert_equal exp, data
147
156
  end
@@ -153,7 +162,7 @@ class TestDebride < Minitest::Test
153
162
  debride.report(io)
154
163
 
155
164
  exp = EXP_FORMATTED
156
- data = YAML.load io.string.gsub(/\d+-\d+/, "###")
165
+ data = YAML.load io.string.gsub(/:\d+(-\d+)?/, ":###")
157
166
 
158
167
  assert_equal exp, data
159
168
  end
@@ -287,6 +296,91 @@ class TestDebride < Minitest::Test
287
296
  assert_process [], ruby
288
297
  end
289
298
 
299
+ def test_method_try
300
+ ruby = <<-RUBY.strip
301
+ class Seattle
302
+ def self.raining?
303
+ true
304
+ end
305
+ end
306
+
307
+ Seattle.try :raining?
308
+ RUBY
309
+
310
+ assert_process [], ruby
311
+ end
312
+
313
+ def test_block_pass
314
+ ruby = <<-RUBY.strip
315
+ class Seattle
316
+ def self.raining?
317
+ true
318
+ end
319
+ end
320
+
321
+ [Seattle].each(&:raining?)
322
+ RUBY
323
+
324
+ assert_process [], ruby
325
+ end
326
+
327
+ def test_block_pass_other
328
+ ruby = <<-RUBY.strip
329
+ class Seattle
330
+ def self.raining?
331
+ -> { called }
332
+ end
333
+
334
+ def self.uncalled; end
335
+ def self.called; end
336
+ end
337
+
338
+ f(&Seattle.raining?)
339
+ RUBY
340
+
341
+ assert_process [["Seattle", [:uncalled]]], ruby
342
+ end
343
+
344
+ def test_block_pass_empty
345
+ ruby = <<-RUBY.strip
346
+ f(&) # block forwarding
347
+ RUBY
348
+
349
+ assert_process [], ruby
350
+ end
351
+
352
+ def test_safe_navigation_operator
353
+ ruby = <<-RUBY.strip
354
+ class Seattle
355
+ def self.raining?
356
+ true
357
+ end
358
+ end
359
+
360
+ Seattle&.raining?
361
+ RUBY
362
+
363
+ assert_process [], ruby
364
+ end
365
+
366
+ def test_call_method
367
+ ruby = <<-RUBY.strip
368
+ class Seattle
369
+ def self.raining?
370
+ true
371
+ end
372
+
373
+ def self.raining_still?
374
+ method(:raining?)
375
+ end
376
+ end
377
+
378
+ Seattle.raining_still?
379
+ RUBY
380
+
381
+ assert_process [], ruby
382
+ end
383
+
290
384
  def test_rails_dsl_methods
291
385
  ruby = <<-RUBY.strip
292
386
  class RailsThing
@@ -360,6 +454,8 @@ class TestDebride < Minitest::Test
360
454
  class Constants
361
455
  USED = 42
362
456
  ALSO = 314
457
+ AGAIN = 27
458
+ MORE = 72
363
459
  UNUSED = 24
364
460
 
365
461
  def something
@@ -370,6 +466,8 @@ class TestDebride < Minitest::Test
370
466
  something
371
467
  Constants::ALSO
372
468
  ::Constants::ALSO
469
+ Constants.const_get(:AGAIN)
470
+ ::Constants.const_get("MORE")
373
471
  RUBY
374
472
 
375
473
  assert_process [["Constants", [:UNUSED]]], ruby
@@ -379,11 +477,13 @@ class TestDebride < Minitest::Test
379
477
  ruby = <<-RUBY.strip
380
478
  class AttributeAccessor
381
479
  attr_accessor :a1, :a2, :a3
382
- attr_writer :w1, :w2
480
+ attr_writer :w1, :w2, :w3, :w4
383
481
  attr_reader :r1, :r2
384
482
  def initialize
385
483
  self.a2 = 'Bar'
386
484
  self.w1 = 'W'
485
+ self.w3 ||= 'W3'
486
+ self.w4 &&= 'W4'
387
487
  end
388
488
 
389
489
  def self.class_method
@@ -397,7 +497,10 @@ class TestDebride < Minitest::Test
397
497
  object.a3 = 'Baz'
398
498
  RUBY
399
499
 
400
- d = assert_process [["AttributeAccessor", [:a1=, :a2, :a3, :class_method, :r2, :w2=]]], ruby
500
+ exp = [["AttributeAccessor",
501
+ [:a1=, :a2, :a3, :class_method, :r2, :w2=]]]
502
+
503
+ d = assert_process exp, ruby
401
504
 
402
505
  exp = {
403
506
  "AttributeAccessor#a1" => "(io):2",
@@ -408,10 +511,12 @@ class TestDebride < Minitest::Test
408
511
  "AttributeAccessor#a3=" => "(io):2",
409
512
  "AttributeAccessor#w1=" => "(io):3",
410
513
  "AttributeAccessor#w2=" => "(io):3",
514
+ "AttributeAccessor#w3=" => "(io):3",
515
+ "AttributeAccessor#w4=" => "(io):3",
411
516
  "AttributeAccessor#r1" => "(io):4",
412
517
  "AttributeAccessor#r2" => "(io):4",
413
- "AttributeAccessor#initialize" => "(io):5-7",
414
- "AttributeAccessor::class_method" => "(io):10-11"
518
+ "AttributeAccessor#initialize" => "(io):5-10",
519
+ "AttributeAccessor::class_method" => "(io):12-14"
415
520
  }
416
521
 
417
522
  assert_equal exp, d.method_locations
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.10.1
4
+ version: 1.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Davis
@@ -10,9 +10,9 @@ bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIDPjCCAiagAwIBAgIBBjANBgkqhkiG9w0BAQsFADBFMRMwEQYDVQQDDApyeWFu
13
+ MIIDPjCCAiagAwIBAgIBBzANBgkqhkiG9w0BAQsFADBFMRMwEQYDVQQDDApyeWFu
14
14
  ZC1ydWJ5MRkwFwYKCZImiZPyLGQBGRYJemVuc3BpZGVyMRMwEQYKCZImiZPyLGQB
15
- GRYDY29tMB4XDTIxMTIyMzIzMTkwNFoXDTIyMTIyMzIzMTkwNFowRTETMBEGA1UE
15
+ GRYDY29tMB4XDTIzMDEwMTA3NTExN1oXDTI0MDEwMTA3NTExN1owRTETMBEGA1UE
16
16
  AwwKcnlhbmQtcnVieTEZMBcGCgmSJomT8ixkARkWCXplbnNwaWRlcjETMBEGCgmS
17
17
  JomT8ixkARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALda
18
18
  b9DCgK+627gPJkB6XfjZ1itoOQvpqH1EXScSaba9/S2VF22VYQbXU1xQXL/WzCkx
@@ -22,14 +22,14 @@ cert_chain:
22
22
  qhtV7HJxNKuPj/JFH0D2cswvzznE/a5FOYO68g+YCuFi5L8wZuuM8zzdwjrWHqSV
23
23
  gBEfoTEGr7Zii72cx+sCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAw
24
24
  HQYDVR0OBBYEFEfFe9md/r/tj/Wmwpy+MI8d9k/hMA0GCSqGSIb3DQEBCwUAA4IB
25
- AQCKB5jfsuSnKb+t/Wrh3UpdkmX7TrEsjVmERC0pPqzQ5GQJgmEXDD7oMgaKXaAq
26
- x2m+KSZDrqk7c8uho5OX6YMqg4KdxehfSLqqTZGoeV78qwf/jpPQZKTf+W9gUSJh
27
- zsWpo4K50MP+QtdSbKXZwjAafpQ8hK0MnnZ/aeCsW9ov5vdXpYbf3dpg6ADXRGE7
28
- lQY2y1tJ5/chqu6h7dQmnm2ABUqx9O+JcN9hbCYoA5i/EeubUEtFIh2w3SpO6YfB
29
- JFmxn4h9YO/pVdB962BdBNNDia0kgIjI3ENnkLq0dKpYU3+F3KhEuTksLO0L6X/V
30
- YsuyUzsMz6GQA4khyaMgKNSD
25
+ AQAkg3y+PBnBAPWdxxITm5sPHqdWQgSyCpRA20o4LTuWr8BWhSXBkfQNa7cY6fOn
26
+ xyM34VPzBFbExv6XOGDfOMFBVaYTHuN9peC/5/umL7kLl+nflXzL2QA7K6LYj5Bg
27
+ sM574Onr0dZDM6Vn69bzQ7rBIFDfK/OhlPzqKZad4nsdcsVH8ODCiT+ATMIZyz5K
28
+ WCnNtqlyiWXI8tdTpahDgcUwfcN/oN7v4K8iU5IbLJX6HQ5DKgmKjfb6XyMth16k
29
+ ROfWo9Uyp8ba/j9eVG14KkYRaLydAY1MNQk2yd3R5CGfeOpD1kttxjoypoUJ2dOG
30
+ nsNBRuQJ1UfiCG97a6DNm+Fr
31
31
  -----END CERTIFICATE-----
32
- date: 2022-12-03 00:00:00.000000000 Z
32
+ date: 2023-05-18 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: sexp_processor
@@ -37,28 +37,28 @@ dependencies:
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '4.5'
40
+ version: '4.17'
41
41
  type: :runtime
42
42
  prerelease: false
43
43
  version_requirements: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '4.5'
47
+ version: '4.17'
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: ruby_parser
50
50
  requirement: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.6'
54
+ version: '3.20'
55
55
  type: :runtime
56
56
  prerelease: false
57
57
  version_requirements: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.6'
61
+ version: '3.20'
62
62
  - !ruby/object:Gem::Dependency
63
63
  name: path_expander
64
64
  requirement: !ruby/object:Gem::Requirement
@@ -113,14 +113,14 @@ dependencies:
113
113
  requirements:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
- version: '3.25'
116
+ version: '4.0'
117
117
  type: :development
118
118
  prerelease: false
119
119
  version_requirements: !ruby/object:Gem::Requirement
120
120
  requirements:
121
121
  - - "~>"
122
122
  - !ruby/object:Gem::Version
123
- version: '3.25'
123
+ version: '4.0'
124
124
  description: Analyze code for potentially uncalled / dead methods, now with auto-removal.
125
125
  email:
126
126
  - ryand-ruby@zenspider.com
@@ -166,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
166
  - !ruby/object:Gem::Version
167
167
  version: '0'
168
168
  requirements: []
169
- rubygems_version: 3.3.12
169
+ rubygems_version: 3.4.10
170
170
  signing_key:
171
171
  specification_version: 4
172
172
  summary: Analyze code for potentially uncalled / dead methods, now with auto-removal.
metadata.gz.sig CHANGED
Binary file