zombie_scout 0.0.4 → 0.0.5
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
- data/.gitignore +2 -0
- data/README.md +2 -0
- data/lib/zombie_scout/app.rb +2 -19
- data/lib/zombie_scout/flog_scorer.rb +10 -6
- data/lib/zombie_scout/formatter.rb +46 -0
- data/lib/zombie_scout/method_call_finder.rb +11 -4
- data/lib/zombie_scout/mission.rb +14 -6
- data/lib/zombie_scout/version.rb +1 -1
- data/lib/zombie_scout/whitelist.rb +15 -0
- data/spec/zombie_scout/flog_scorer_spec.rb +27 -0
- data/spec/zombie_scout/formatter_spec.rb +48 -0
- data/spec/zombie_scout/whitelist_spec.rb +38 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24fef05906d9243f5b7ccc8f5d527162f5a38c5f
|
4
|
+
data.tar.gz: a56de0fbd3d1e9cb5369a2b24bcbd76b5c728931
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5111aa9eff93beb078907b74c24242c053227b71a5b50b8f4a3cc21835519bf58f845111907b8e0d76de39a2419bac3a077a81d76fc2f4bb1f4c6f2d61850ac
|
7
|
+
data.tar.gz: 2c19bbd09b45ae27af15d44f2bfd05795365d063cf42dbfb9732c5fc70c0101c1baf97caa2118584e7bb82229904ff4fcf0f77bb9fe08b111a0d0ce18d97a43e
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -153,6 +153,7 @@ thing:
|
|
153
153
|
## Code Status
|
154
154
|
|
155
155
|
* [](https://travis-ci.org/danbernier/zombie_scout)
|
156
|
+
* [](https://codeclimate.com/github/danbernier/zombie_scout)
|
156
157
|
|
157
158
|
## TODOs
|
158
159
|
|
@@ -161,6 +162,7 @@ thing:
|
|
161
162
|
* [ ] let users configure: files to search for methods, files to search for calls...probably in `.zombie_scout`.
|
162
163
|
* [x] option for CSV output
|
163
164
|
* [ ] if 2 classes have a method w/ the same name, you can't tell (right now, easily) whether it's dead - so don't grep for it.
|
165
|
+
* [ ] look for db/schema.rb & db/structure.sql, parse out columns, & look for those.
|
164
166
|
|
165
167
|
ToThinkAbouts:
|
166
168
|
* [x] extract a hash-y report structure that can be used by whatever, from the default report
|
data/lib/zombie_scout/app.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'zombie_scout/mission'
|
3
|
+
require 'zombie_scout/formatter'
|
3
4
|
|
4
5
|
module ZombieScout
|
5
6
|
class App < Thor
|
@@ -9,25 +10,7 @@ module ZombieScout
|
|
9
10
|
mission = Mission.new(globs)
|
10
11
|
report = mission.scout.sort_by { |z| [z[:file_path], -z[:flog_score]] }
|
11
12
|
|
12
|
-
|
13
|
-
total_flog_score = report.map { |z| z[:flog_score] }.reduce(0, :+)
|
14
|
-
|
15
|
-
puts "Scouted #{mission.defined_method_count} methods in #{mission.source_count} files, in #{mission.duration} seconds."
|
16
|
-
puts "Found #{mission.zombie_count} potential zombies, with a combined flog score of #{total_flog_score.round(1)}."
|
17
|
-
puts
|
18
|
-
|
19
|
-
report.each do |zombie|
|
20
|
-
puts [zombie[:location], zombie[:full_name], zombie[:flog_score]] * "\t"
|
21
|
-
end
|
22
|
-
elsif options[:format] == 'csv'
|
23
|
-
require 'csv'
|
24
|
-
CSV do |csv|
|
25
|
-
csv << %w(location name flog_score)
|
26
|
-
report.each do |zombie|
|
27
|
-
csv << [zombie[:location], zombie[:full_name], zombie[:flog_score]]
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
13
|
+
puts ZombieScout::Formatter.format(options[:format], mission, report)
|
31
14
|
end
|
32
15
|
end
|
33
16
|
end
|
@@ -2,8 +2,9 @@ require 'flog'
|
|
2
2
|
|
3
3
|
module ZombieScout
|
4
4
|
class FlogScorer
|
5
|
-
def initialize(
|
6
|
-
@
|
5
|
+
def initialize(zombie, flog=nil)
|
6
|
+
@zombie = zombie
|
7
|
+
@flog = flog || Flog.new(methode: true, quiet: true, score: false)
|
7
8
|
end
|
8
9
|
|
9
10
|
def score
|
@@ -12,16 +13,19 @@ module ZombieScout
|
|
12
13
|
|
13
14
|
private
|
14
15
|
|
16
|
+
attr_reader :flog
|
17
|
+
|
15
18
|
def raw_score
|
16
|
-
flog = Flog.new(methods: true, quiet: true, score:false)
|
17
19
|
all_scores = flog.flog(zombie_path)
|
18
|
-
|
19
|
-
|
20
|
+
|
21
|
+
# default to {} in case there is no score. (it's a 0)
|
22
|
+
scores = all_scores.fetch(@zombie.full_name, {})
|
23
|
+
|
20
24
|
flog.score_method(scores)
|
21
25
|
end
|
22
26
|
|
23
27
|
def zombie_path
|
24
|
-
@
|
28
|
+
@zombie.location.sub(/\:\d+$/, '')
|
25
29
|
end
|
26
30
|
end
|
27
31
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ZombieScout
|
2
|
+
module Formatter
|
3
|
+
def self.format(format, mission, report)
|
4
|
+
case format
|
5
|
+
when 'report'
|
6
|
+
ReportFormatter.new(mission, report).to_s
|
7
|
+
when 'csv'
|
8
|
+
CsvFormatter.new(mission, report).to_s
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class BaseFormatter
|
13
|
+
attr_reader :mission, :report
|
14
|
+
def initialize(mission, report)
|
15
|
+
@mission, @report = mission, report
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class ReportFormatter < BaseFormatter
|
20
|
+
def to_s
|
21
|
+
one = "Scouted #{mission.defined_method_count} methods in #{mission.source_count} files, in #{mission.duration} seconds."
|
22
|
+
two = "Found #{mission.zombie_count} potential zombies, with a combined flog score of #{total_flog_score.round(1)}."
|
23
|
+
|
24
|
+
([one, two, "\n"] + report.map { |zombie|
|
25
|
+
[zombie[:location], zombie[:full_name], zombie[:flog_score]] * "\t"
|
26
|
+
}) * "\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
def total_flog_score
|
30
|
+
report.map { |z| z[:flog_score] }.reduce(0, :+)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class CsvFormatter < BaseFormatter
|
35
|
+
def to_s
|
36
|
+
require 'csv'
|
37
|
+
CSV.generate do |csv|
|
38
|
+
csv << %w(location name flog_score)
|
39
|
+
report.each do |zombie|
|
40
|
+
csv << [zombie[:location], zombie[:full_name], zombie[:flog_score]]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -7,7 +7,10 @@ module ZombieScout
|
|
7
7
|
|
8
8
|
def count_calls(method_name)
|
9
9
|
method_name = method_name.to_s
|
10
|
-
|
10
|
+
|
11
|
+
# zero-or-more spaces, =, and NOT a > (so we don't match hashrockets)
|
12
|
+
method_name.sub!(/=$/, ' *=[^>]')
|
13
|
+
|
11
14
|
find_occurrances(method_name).size
|
12
15
|
end
|
13
16
|
|
@@ -15,13 +18,17 @@ module ZombieScout
|
|
15
18
|
|
16
19
|
def find_occurrances(method_name)
|
17
20
|
# TODO somehow expose some of this config for end-users
|
18
|
-
command = "grep -rnw
|
19
|
-
# grep -r --include="*.rb" --include="*.erb" -nw PATTERN app lib
|
20
|
-
|
21
|
+
command = "grep -rnw #{includes} --binary-files=without-match \"#{method_name}\" #{files_to_search} Rakefile"
|
21
22
|
grep_lines = `#{command}`
|
22
23
|
grep_lines.split("\n")
|
23
24
|
end
|
24
25
|
|
26
|
+
def includes
|
27
|
+
%w(*.rb *.erb *.rake Rakefile).map { |inc|
|
28
|
+
"--include=\"#{inc}\""
|
29
|
+
}.join(' ')
|
30
|
+
end
|
31
|
+
|
25
32
|
def files_to_search
|
26
33
|
@ruby_project.folders.join(' ')
|
27
34
|
end
|
data/lib/zombie_scout/mission.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'zombie_scout/ruby_project'
|
2
|
+
require 'zombie_scout/whitelist'
|
2
3
|
require 'zombie_scout/parser'
|
3
4
|
require 'zombie_scout/method_call_finder'
|
4
5
|
require 'zombie_scout/flog_scorer'
|
@@ -9,6 +10,7 @@ module ZombieScout
|
|
9
10
|
|
10
11
|
def initialize(globs)
|
11
12
|
@ruby_project = RubyProject.new(*globs)
|
13
|
+
@whitelist = Whitelist.new
|
12
14
|
end
|
13
15
|
|
14
16
|
def scout
|
@@ -18,7 +20,7 @@ module ZombieScout
|
|
18
20
|
file_path: zombie.file_path,
|
19
21
|
name: zombie.name,
|
20
22
|
full_name: zombie.full_name,
|
21
|
-
flog_score: flog_score(zombie
|
23
|
+
flog_score: flog_score(zombie)
|
22
24
|
}
|
23
25
|
}.tap {
|
24
26
|
@end_time = Time.now
|
@@ -43,15 +45,15 @@ module ZombieScout
|
|
43
45
|
@sources ||= @ruby_project.ruby_sources
|
44
46
|
end
|
45
47
|
|
46
|
-
def flog_score(
|
47
|
-
ZombieScout::FlogScorer.new(
|
48
|
+
def flog_score(zombie)
|
49
|
+
ZombieScout::FlogScorer.new(zombie).score
|
48
50
|
end
|
49
51
|
|
50
52
|
def zombies
|
51
53
|
return @zombies unless @zombies.nil?
|
52
54
|
|
53
55
|
scout!
|
54
|
-
@zombies
|
56
|
+
@zombies = @defined_methods.select { |method|
|
55
57
|
might_be_dead?(method)
|
56
58
|
}
|
57
59
|
end
|
@@ -74,8 +76,14 @@ module ZombieScout
|
|
74
76
|
end
|
75
77
|
|
76
78
|
def might_be_dead?(method)
|
77
|
-
|
78
|
-
|
79
|
+
unless whitelisted?(method)
|
80
|
+
@method_call_counter ||= MethodCallFinder.new(@ruby_project)
|
81
|
+
@method_call_counter.count_calls(method.name) < 2
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def whitelisted?(method)
|
86
|
+
@whitelist.include?(method.full_name)
|
79
87
|
end
|
80
88
|
end
|
81
89
|
end
|
data/lib/zombie_scout/version.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
module ZombieScout
|
2
|
+
class Whitelist
|
3
|
+
def initialize
|
4
|
+
@whitelist = if File.exist?('.zombie_scout_whitelist')
|
5
|
+
File.read('.zombie_scout_whitelist')
|
6
|
+
else
|
7
|
+
[]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def include?(zombie_full_name)
|
12
|
+
@whitelist.include?(zombie_full_name)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'zombie_scout/flog_scorer'
|
3
|
+
|
4
|
+
describe ZombieScout::FlogScorer do
|
5
|
+
let(:full_name) { 'ClassName#method_name' }
|
6
|
+
let(:method_score) { :whatever }
|
7
|
+
let(:class_scores) {
|
8
|
+
{full_name => method_score}
|
9
|
+
}
|
10
|
+
|
11
|
+
let(:zombie_path) { 'lib/foo.rb' }
|
12
|
+
|
13
|
+
let(:flog) {
|
14
|
+
flog = double(:flog)
|
15
|
+
flog.stub(:flog).with(zombie_path).and_return(class_scores)
|
16
|
+
flog.stub(:score_method).with(method_score).and_return(38.293)
|
17
|
+
flog
|
18
|
+
}
|
19
|
+
let(:zombie) {
|
20
|
+
double(:zombie, location: "#{zombie_path}:42", full_name: full_name)
|
21
|
+
}
|
22
|
+
|
23
|
+
it 'should call some methods on Flog, and round the result' do
|
24
|
+
scorer = ZombieScout::FlogScorer.new(zombie, flog)
|
25
|
+
expect(scorer.score).to eq(38.3)
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'zombie_scout/formatter'
|
3
|
+
|
4
|
+
describe ZombieScout::Formatter do
|
5
|
+
let(:mission) {
|
6
|
+
double(:mission, defined_method_count: 123,
|
7
|
+
source_count: 97,
|
8
|
+
zombie_count: 42,
|
9
|
+
duration: 55)
|
10
|
+
}
|
11
|
+
|
12
|
+
let(:report) {
|
13
|
+
[
|
14
|
+
{ flog_score: 23.4,
|
15
|
+
location: 'foo.rb:42',
|
16
|
+
full_name: 'Foo#bar' },
|
17
|
+
{ flog_score: 43.2,
|
18
|
+
location: 'bar.rb:99',
|
19
|
+
full_name: 'Bar#none' }
|
20
|
+
]
|
21
|
+
}
|
22
|
+
|
23
|
+
context 'for "report" format' do
|
24
|
+
it 'formats it correctly' do
|
25
|
+
output = ZombieScout::Formatter.format('report', mission, report)
|
26
|
+
|
27
|
+
expect(output).to include "Scouted 123 methods in 97 files"
|
28
|
+
expect(output).to include "in 55 seconds"
|
29
|
+
expect(output).to include "Found 42 potential zombies"
|
30
|
+
expect(output).to include "combined flog score of 66.6"
|
31
|
+
expect(output).to include "foo.rb:42\tFoo#bar\t23.4"
|
32
|
+
expect(output).to include "bar.rb:99\tBar#none\t43.2"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'for "csv" format' do
|
37
|
+
it 'formats it correctly' do
|
38
|
+
output = ZombieScout::Formatter.format('csv', mission, report)
|
39
|
+
|
40
|
+
lines = output.split("\n").map(&:chomp)
|
41
|
+
expect(lines).to eq([
|
42
|
+
'location,name,flog_score',
|
43
|
+
'foo.rb:42,Foo#bar,23.4',
|
44
|
+
'bar.rb:99,Bar#none,43.2'
|
45
|
+
])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'zombie_scout/whitelist'
|
3
|
+
|
4
|
+
describe ZombieScout::Whitelist do
|
5
|
+
include FakeFS::SpecHelpers
|
6
|
+
|
7
|
+
def clear_whitelist!
|
8
|
+
if File.exist?('.zombie_scout_whitelist')
|
9
|
+
File.delete('.zombie_scout_whitelist')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def whitelist!(*names)
|
14
|
+
File.open('.zombie_scout_whitelist', 'w') do |f|
|
15
|
+
f.puts names.join("\n")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:whitelist) { ZombieScout::Whitelist.new }
|
20
|
+
|
21
|
+
describe '#include?' do
|
22
|
+
it 'only includes methods listed in .zombie_scout_whitelist' do
|
23
|
+
whitelist! 'Foo#bar', 'Iron#man'
|
24
|
+
expect(whitelist).to include('Foo#bar')
|
25
|
+
expect(whitelist).to include('Iron#man')
|
26
|
+
expect(whitelist).not_to include('Cran#berry')
|
27
|
+
expect(whitelist).not_to include('Boot#laces')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'includes nothing when .zombie_scout_whitelist does not exist' do
|
31
|
+
clear_whitelist!
|
32
|
+
expect(whitelist).not_to include('Foo#bar')
|
33
|
+
expect(whitelist).not_to include('Iron#man')
|
34
|
+
expect(whitelist).not_to include('Cran#berry')
|
35
|
+
expect(whitelist).not_to include('Boot#laces')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zombie_scout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Bernier
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -91,6 +91,7 @@ files:
|
|
91
91
|
- lib/zombie_scout.rb
|
92
92
|
- lib/zombie_scout/app.rb
|
93
93
|
- lib/zombie_scout/flog_scorer.rb
|
94
|
+
- lib/zombie_scout/formatter.rb
|
94
95
|
- lib/zombie_scout/method.rb
|
95
96
|
- lib/zombie_scout/method_call_finder.rb
|
96
97
|
- lib/zombie_scout/mission.rb
|
@@ -98,10 +99,14 @@ files:
|
|
98
99
|
- lib/zombie_scout/ruby_project.rb
|
99
100
|
- lib/zombie_scout/ruby_source.rb
|
100
101
|
- lib/zombie_scout/version.rb
|
102
|
+
- lib/zombie_scout/whitelist.rb
|
101
103
|
- spec/spec_helper.rb
|
104
|
+
- spec/zombie_scout/flog_scorer_spec.rb
|
105
|
+
- spec/zombie_scout/formatter_spec.rb
|
102
106
|
- spec/zombie_scout/parser_spec.rb
|
103
107
|
- spec/zombie_scout/ruby_project_spec.rb
|
104
108
|
- spec/zombie_scout/ruby_source_spec.rb
|
109
|
+
- spec/zombie_scout/whitelist_spec.rb
|
105
110
|
- zombie_scout.gemspec
|
106
111
|
homepage: https://github.com/danbernier/zombie_scout
|
107
112
|
licenses:
|
@@ -129,6 +134,9 @@ specification_version: 4
|
|
129
134
|
summary: Find dead methods in your Ruby app
|
130
135
|
test_files:
|
131
136
|
- spec/spec_helper.rb
|
137
|
+
- spec/zombie_scout/flog_scorer_spec.rb
|
138
|
+
- spec/zombie_scout/formatter_spec.rb
|
132
139
|
- spec/zombie_scout/parser_spec.rb
|
133
140
|
- spec/zombie_scout/ruby_project_spec.rb
|
134
141
|
- spec/zombie_scout/ruby_source_spec.rb
|
142
|
+
- spec/zombie_scout/whitelist_spec.rb
|