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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/History.rdoc +31 -0
- data/README.rdoc +38 -3
- data/Rakefile +6 -3
- data/bin/debride_rm +35 -72
- data/lib/debride.rb +76 -10
- data/test/test_debride.rb +114 -9
- data.tar.gz.sig +0 -0
- metadata +17 -17
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e23117d21c55f9b3a52eb52b6bbd068167cb1b5852650359e62809ed8de15f1b
|
|
4
|
+
data.tar.gz: 231f1adaefd3cfb507d2352c72a7af1200e3db691d1617186f1cd4bc561e68e8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
23
|
-
dependency "ruby_parser", "~> 3.
|
|
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"] = "
|
|
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 -
|
|
1
|
+
#!/usr/bin/env ruby -ws
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
skips = 0
|
|
3
|
+
$C ||= false # command to run between deletions
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
require "set"
|
|
6
|
+
require_relative "../lib/debride"
|
|
8
7
|
|
|
9
|
-
|
|
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
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
|
|
86
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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}
|
|
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
|
-
|
|
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]
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
[:
|
|
13
|
-
:
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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-
|
|
414
|
-
"AttributeAccessor::class_method" => "(io):
|
|
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.
|
|
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
|
-
|
|
13
|
+
MIIDPjCCAiagAwIBAgIBBzANBgkqhkiG9w0BAQsFADBFMRMwEQYDVQQDDApyeWFu
|
|
14
14
|
ZC1ydWJ5MRkwFwYKCZImiZPyLGQBGRYJemVuc3BpZGVyMRMwEQYKCZImiZPyLGQB
|
|
15
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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:
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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: '
|
|
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: '
|
|
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.
|
|
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
|