zombie_scout 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c1d48e23ce3d846d2a1bb64d2c5a698386a7ccbb
4
- data.tar.gz: dec98dc4fcf229576c71c080c00e4a24e1afa7d1
3
+ metadata.gz: 3017624103d8c386a942a3653769d1e62b93175e
4
+ data.tar.gz: 4051fd1c51e9626ff04846945c7d9d22a58b4788
5
5
  SHA512:
6
- metadata.gz: 989aedb17a61b6aa6dc899a3b9426117dc771fece220a5fb1505d5b21b36e40dde5a06af2e17a424e438fffb212b765e4500aa227f3bec11c9350081ab6e1d91
7
- data.tar.gz: 973b0f339bbfef34d128924df0d66902be6c929ac96c617516f230c28c7b2ebce8761026376a11cb6b5efcf104a22a914574bbf62e24fb5c4c4c03d9ebf810e5
6
+ metadata.gz: 0bee3360ff18f1c4363d605612a0b48f574b8390607ee975f51a84cab76f9544bf6334429d6133f770ef97ea179ee5349760edbb3d55e0a6adb66f2260283354
7
+ data.tar.gz: 49dec6d09b9d3f62538a93072bd6a6cf3619a2c1366b778154a2a0b4a20f68fab4557854a966c6cb895bbfb632e2b6cb177de168fe14caaf52caa4abff8e70c1
data/README.md CHANGED
@@ -81,20 +81,22 @@ Or, add this to your Gemfile:
81
81
  You can run it on a whole folder:
82
82
 
83
83
  dan@aleph:~/projects/zombie_scout$ zombie_scout scout
84
- Scouted 43 methods in 9 files, in 1.096459054 seconds.
85
- Found 11 potential zombies, with a combined flog score of 51.5.
86
-
87
- lib/zombie_scout/parser.rb:29 on_send 8.3
88
- lib/zombie_scout/parser.rb:23 on_defs 5.9
89
- lib/zombie_scout/parser.rb:65 handle_def_delegators 5.8
90
- lib/zombie_scout/parser.rb:56 handle_attr_accessor 5.6
91
- lib/zombie_scout/parser.rb:17 on_def 4.9
92
- lib/zombie_scout/parser.rb:48 handle_attr_writer 4.3
93
- lib/zombie_scout/parser.rb:40 handle_attr_reader 4.3
94
- lib/zombie_scout/parser.rb:73 handle_def_delegator 3.8
95
- lib/zombie_scout/parser.rb:79 handle_scope 3.8
96
- lib/zombie_scout/parser.rb:100 on_sym 2.4
97
- lib/zombie_scout/mission.rb:34 zombie_count 2.4
84
+ Scouted 48 methods in 10 files, in 1.470468836 seconds.
85
+ Found 13 potential zombies, with a combined flog score of 66.9.
86
+
87
+ lib/zombie_scout/parser.rb:45 ZombieScout::Parser#on_send 8.3
88
+ lib/zombie_scout/parser.rb:17 ZombieScout::Parser#on_class 7.9
89
+ lib/zombie_scout/parser.rb:25 ZombieScout::Parser#on_module 7.2
90
+ lib/zombie_scout/parser.rb:39 ZombieScout::Parser#on_defs 5.9
91
+ lib/zombie_scout/parser.rb:81 ZombieScout::Parser#handle_def_delegators 5.8
92
+ lib/zombie_scout/parser.rb:72 ZombieScout::Parser#handle_attr_accessor 5.6
93
+ lib/zombie_scout/parser.rb:33 ZombieScout::Parser#on_def 4.9
94
+ lib/zombie_scout/parser.rb:56 ZombieScout::Parser#handle_attr_reader 4.3
95
+ lib/zombie_scout/parser.rb:64 ZombieScout::Parser#handle_attr_writer 4.3
96
+ lib/zombie_scout/parser.rb:89 ZombieScout::Parser#handle_def_delegator 3.8
97
+ lib/zombie_scout/parser.rb:95 ZombieScout::Parser#handle_scope 3.8
98
+ lib/zombie_scout/parser.rb:122 ZombieScout::ConstExtracter#on_const 2.7
99
+ lib/zombie_scout/parser.rb:116 ZombieScout::SymbolExtracter#on_sym 2.4
98
100
 
99
101
  (See what I meant about callbacks and false-positives?)
100
102
 
@@ -108,17 +110,19 @@ ZombieScout will also report in CSV, if you like:
108
110
 
109
111
  dan@aleph:~/projects/zombie_scout$ zombie_scout scout --format csv
110
112
  location,name,flog_score
111
- lib/zombie_scout/parser.rb:29,on_send,8.3
112
- lib/zombie_scout/parser.rb:23,on_defs,5.9
113
- lib/zombie_scout/parser.rb:65,handle_def_delegators,5.8
114
- lib/zombie_scout/parser.rb:56,handle_attr_accessor,5.6
115
- lib/zombie_scout/parser.rb:17,on_def,4.9
116
- lib/zombie_scout/parser.rb:48,handle_attr_writer,4.3
117
- lib/zombie_scout/parser.rb:40,handle_attr_reader,4.3
118
- lib/zombie_scout/parser.rb:73,handle_def_delegator,3.8
119
- lib/zombie_scout/parser.rb:79,handle_scope,3.8
120
- lib/zombie_scout/parser.rb:100,on_sym,2.4
121
- lib/zombie_scout/mission.rb:34,zombie_count,2.4
113
+ lib/zombie_scout/parser.rb:45,ZombieScout::Parser#on_send,8.3
114
+ lib/zombie_scout/parser.rb:17,ZombieScout::Parser#on_class,7.9
115
+ lib/zombie_scout/parser.rb:25,ZombieScout::Parser#on_module,7.2
116
+ lib/zombie_scout/parser.rb:39,ZombieScout::Parser#on_defs,5.9
117
+ lib/zombie_scout/parser.rb:81,ZombieScout::Parser#handle_def_delegators,5.8
118
+ lib/zombie_scout/parser.rb:72,ZombieScout::Parser#handle_attr_accessor,5.6
119
+ lib/zombie_scout/parser.rb:33,ZombieScout::Parser#on_def,4.9
120
+ lib/zombie_scout/parser.rb:56,ZombieScout::Parser#handle_attr_reader,4.3
121
+ lib/zombie_scout/parser.rb:64,ZombieScout::Parser#handle_attr_writer,4.3
122
+ lib/zombie_scout/parser.rb:89,ZombieScout::Parser#handle_def_delegator,3.8
123
+ lib/zombie_scout/parser.rb:95,ZombieScout::Parser#handle_scope,3.8
124
+ lib/zombie_scout/parser.rb:122,ZombieScout::ConstExtracter#on_const,2.7
125
+ lib/zombie_scout/parser.rb:116,ZombieScout::SymbolExtracter#on_sym,2.4
122
126
 
123
127
  ### In Ruby
124
128
 
@@ -131,14 +135,20 @@ thing:
131
135
  => true
132
136
  irb> > pp ZombieScout::Mission.new('.').scout
133
137
  [{:location=>"./lib/zombie_scout/parser.rb:17",
138
+ :file_path=>"./lib/zombie_scout/parser.rb",
139
+ :name=>:on_class,
140
+ :full_name=>"ZombieScout::Parser#on_class",
141
+ :flog_score=>7.9},
142
+ {:location=>"./lib/zombie_scout/parser.rb:25",
143
+ :file_path=>"./lib/zombie_scout/parser.rb",
144
+ :name=>:on_module,
145
+ :full_name=>"ZombieScout::Parser#on_module",
146
+ :flog_score=>7.2},
147
+ {:location=>"./lib/zombie_scout/parser.rb:33",
148
+ :file_path=>"./lib/zombie_scout/parser.rb",
134
149
  :name=>:on_def,
135
- :flog_score=>4.9},
136
- {:location=>"./lib/zombie_scout/parser.rb:23",
137
- :name=>:on_defs,
138
- :flog_score=>5.9},
139
- {:location=>"./lib/zombie_scout/parser.rb:29",
140
- :name=>:on_send,
141
- :flog_score=>8.3}, ...]
150
+ :full_name=>"ZombieScout::Parser#on_def",
151
+ :flog_score=>4.9}, ...]
142
152
 
143
153
  ## Code Status
144
154
 
@@ -150,6 +160,7 @@ thing:
150
160
  * [ ] parse for rails delegators
151
161
  * [ ] let users configure: files to search for methods, files to search for calls...probably in `.zombie_scout`.
152
162
  * [x] option for CSV output
163
+ * [ ] 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.
153
164
 
154
165
  ToThinkAbouts:
155
166
  * [x] extract a hash-y report structure that can be used by whatever, from the default report
@@ -4,27 +4,27 @@ require 'zombie_scout/mission'
4
4
  module ZombieScout
5
5
  class App < Thor
6
6
  desc "scout", "scout for zombie code in current directory"
7
- option :format, default: 'report'
7
+ option :format, enum: %w(report csv), default: 'report'
8
8
  def scout(*globs)
9
9
  mission = Mission.new(globs)
10
- report = mission.scout.sort_by { |z| -z[:flog_score] }
10
+ report = mission.scout.sort_by { |z| [z[:file_path], -z[:flog_score]] }
11
11
 
12
12
  if options[:format] == 'report'
13
13
  total_flog_score = report.map { |z| z[:flog_score] }.reduce(0, :+)
14
14
 
15
15
  puts "Scouted #{mission.defined_method_count} methods in #{mission.source_count} files, in #{mission.duration} seconds."
16
- puts "Found #{report.size} potential zombies, with a combined flog score of #{total_flog_score.round(1)}."
16
+ puts "Found #{mission.zombie_count} potential zombies, with a combined flog score of #{total_flog_score.round(1)}."
17
17
  puts
18
18
 
19
19
  report.each do |zombie|
20
- puts [zombie[:location], zombie[:name], zombie[:flog_score]] * "\t"
20
+ puts [zombie[:location], zombie[:full_name], zombie[:flog_score]] * "\t"
21
21
  end
22
22
  elsif options[:format] == 'csv'
23
23
  require 'csv'
24
24
  CSV do |csv|
25
25
  csv << %w(location name flog_score)
26
26
  report.each do |zombie|
27
- csv << [zombie[:location], zombie[:name], zombie[:flog_score]]
27
+ csv << [zombie[:location], zombie[:full_name], zombie[:flog_score]]
28
28
  end
29
29
  end
30
30
  end
@@ -0,0 +1,11 @@
1
+ module ZombieScout
2
+ class Method < Struct.new(:name, :class_name, :file_path, :line_number)
3
+ def full_name
4
+ [class_name, '#', name].join('')
5
+ end
6
+
7
+ def location
8
+ [file_path, line_number].join(':')
9
+ end
10
+ end
11
+ end
@@ -15,7 +15,9 @@ module ZombieScout
15
15
  @start_time = Time.now
16
16
  zombies.map { |zombie|
17
17
  { location: zombie.location,
18
+ file_path: zombie.file_path,
18
19
  name: zombie.name,
20
+ full_name: zombie.full_name,
19
21
  flog_score: flog_score(zombie.location)
20
22
  }
21
23
  }.tap {
@@ -1,8 +1,7 @@
1
1
  require 'parser/current'
2
+ require 'zombie_scout/method'
2
3
 
3
4
  module ZombieScout
4
- Method = Class.new(Struct.new(:name, :location))
5
-
6
5
  class Parser < Parser::AST::Processor
7
6
  attr_reader :defined_methods, :called_methods
8
7
 
@@ -10,10 +9,27 @@ module ZombieScout
10
9
  @ruby_source = ruby_source
11
10
  @defined_methods = []
12
11
  @called_methods = []
12
+ @class_module_stack = []
13
13
  node = ::Parser::CurrentRuby.parse(@ruby_source.source)
14
14
  process(node)
15
15
  end
16
16
 
17
+ def on_class(node)
18
+ classname_const, superclass, body = *node
19
+ classname = ConstExtracter.new.process(classname_const)
20
+ @class_module_stack.push(classname)
21
+ process(body)
22
+ @class_module_stack.pop
23
+ end
24
+
25
+ def on_module(node)
26
+ modulename_const, body = *node
27
+ modulename = ConstExtracter.new.process(modulename_const)
28
+ @class_module_stack.push(modulename)
29
+ process(body)
30
+ @class_module_stack.pop
31
+ end
32
+
17
33
  def on_def(node)
18
34
  method_name, args, body = *node
19
35
  stash_method(method_name, node)
@@ -91,8 +107,8 @@ module ZombieScout
91
107
 
92
108
  def stash_method(method_name, node)
93
109
  line_number = node.location.line
94
- location = [@ruby_source.path, line_number].join(":")
95
- @defined_methods << Method.new(method_name, location)
110
+ class_name = @class_module_stack.join('::')
111
+ @defined_methods << Method.new(method_name, class_name, @ruby_source.path, line_number)
96
112
  end
97
113
  end
98
114
 
@@ -101,4 +117,10 @@ module ZombieScout
101
117
  node.to_a[0]
102
118
  end
103
119
  end
120
+
121
+ class ConstExtracter < ::Parser::AST::Processor
122
+ def on_const(node)
123
+ node.to_a[1]
124
+ end
125
+ end
104
126
  end
@@ -1,3 +1,3 @@
1
1
  module ZombieScout
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -2,8 +2,9 @@ require 'spec_helper'
2
2
  require 'zombie_scout/parser'
3
3
 
4
4
  describe ZombieScout::Parser do
5
+ let(:file_name) { 'lib/fizzbuzz.rb' }
5
6
  let(:ruby_source) {
6
- double(:ruby_source, path: 'lib/fizzbuzz.rb', source: ruby_code)
7
+ double(:ruby_source, path: file_name, source: ruby_code)
7
8
  }
8
9
 
9
10
  describe '#called_methods' do
@@ -32,31 +33,86 @@ describe ZombieScout::Parser do
32
33
  context 'when a ruby file has instance or class methods' do
33
34
  let(:ruby_code) {
34
35
  "class FizzBuzz
35
- def fizz
36
- 'plop plop'
37
- end
38
-
39
- def self.buzz
40
- 'bzz bzz bzz'
41
- end
42
- end"
36
+ def fizz
37
+ 'plop plop'
38
+ end
39
+
40
+ def self.buzz
41
+ 'bzz bzz bzz'
42
+ end
43
+ end"
43
44
  }
44
45
 
45
- it 'can find the methods' do
46
+ it 'can find the methods, and the class and file they belong to' do
47
+ expect(defined_methods.size).to eq 2
48
+
46
49
  expect(defined_methods[0].name).to eq :buzz
50
+ expect(defined_methods[0].full_name).to eq 'FizzBuzz#buzz'
47
51
  expect(defined_methods[0].location).to eq 'lib/fizzbuzz.rb:6'
48
52
 
49
53
  expect(defined_methods[1].name).to eq :fizz
54
+ expect(defined_methods[1].full_name).to eq 'FizzBuzz#fizz'
50
55
  expect(defined_methods[1].location).to eq 'lib/fizzbuzz.rb:2'
51
56
  end
52
57
  end
53
58
 
59
+ context 'when a ruby file has methods in a module' do
60
+ let(:file_name) { 'fizz.rb' }
61
+ let(:ruby_code) {
62
+ "module Fizz
63
+ def berries
64
+ 'fizz berries?'
65
+ end
66
+ end"
67
+ }
68
+ it 'can find the methods, and the module they belong to' do
69
+ expect(defined_methods.size).to eq 1
70
+ expect(defined_methods[0].name).to eq :berries
71
+ expect(defined_methods[0].full_name).to eq 'Fizz#berries'
72
+ expect(defined_methods[0].location).to eq 'fizz.rb:2'
73
+ end
74
+ end
75
+
76
+ context 'when a ruby file has a class nested in a module' do
77
+ let(:file_name) { 'zombie.rb' }
78
+ let(:ruby_code) {
79
+ "module Zombie
80
+ class Report
81
+ def info
82
+ 'all clear!'
83
+ end
84
+ end
85
+ end"
86
+ }
87
+ it 'will record the nesting in the classname' do
88
+ expect(defined_methods.size).to eq 1
89
+ expect(defined_methods[0].name).to eq :info
90
+ expect(defined_methods[0].full_name).to eq 'Zombie::Report#info'
91
+ expect(defined_methods[0].location).to eq 'zombie.rb:3'
92
+ end
93
+ end
94
+
95
+ context 'when a ruby file has a class nested in another class' do
96
+ let(:ruby_code) {
97
+ "class Person
98
+ class Address
99
+ def street
100
+ '123 main'
101
+ end
102
+ end
103
+ end"
104
+ }
105
+ it 'will record the nesting in the classname' do
106
+ expect(defined_methods[0].full_name).to eq 'Person::Address#street'
107
+ end
108
+ end
109
+
54
110
  context 'when a ruby file has attr_readers' do
55
111
  context "when they're declared with symbols, the normal way" do
56
112
  let(:ruby_code) {
57
113
  "class Book
58
- attr_reader :title, :author
59
- end"
114
+ attr_reader :title, :author
115
+ end"
60
116
  }
61
117
  it 'can find attr_readers' do
62
118
  expect(defined_methods.map(&:name)).to match_array(%i[author title])
@@ -65,9 +121,9 @@ describe ZombieScout::Parser do
65
121
  context "when they're declare with a splat from an array of symbols" do
66
122
  let(:ruby_code) {
67
123
  "class Book
68
- attributes = %i(title author)
69
- attr_reader *attributes
70
- end"
124
+ attributes = %i(title author)
125
+ attr_reader *attributes
126
+ end"
71
127
  }
72
128
  it 'will ignore them' do
73
129
  expect(defined_methods).to be_empty
@@ -79,8 +135,8 @@ describe ZombieScout::Parser do
79
135
  context "when they're declared with symbols, the normal way" do
80
136
  let(:ruby_code) {
81
137
  "class Book
82
- attr_writer :title, :author
83
- end"
138
+ attr_writer :title, :author
139
+ end"
84
140
  }
85
141
  it 'can find attr_writers' do
86
142
  expect(defined_methods.map(&:name)).to match_array(%i[author= title=])
@@ -89,9 +145,9 @@ describe ZombieScout::Parser do
89
145
  context "when they're declare with a splat from an array of symbols" do
90
146
  let(:ruby_code) {
91
147
  "class Book
92
- attributes = %i(title author)
93
- attr_reader *attributes
94
- end"
148
+ attributes = %i(title author)
149
+ attr_reader *attributes
150
+ end"
95
151
  }
96
152
  it 'will ignore them' do
97
153
  expect(defined_methods).to be_empty
@@ -103,8 +159,8 @@ describe ZombieScout::Parser do
103
159
  context "when they're declared with symbols, the normal way" do
104
160
  let(:ruby_code) {
105
161
  "class Book
106
- attr_accessor :title, :author
107
- end"
162
+ attr_accessor :title, :author
163
+ end"
108
164
  }
109
165
  it 'can find attr_accessors' do
110
166
  expect(defined_methods.map(&:name)).to match_array(%i[author author= title title=])
@@ -113,9 +169,9 @@ describe ZombieScout::Parser do
113
169
  context "when they're declare with a splat from an array of symbols" do
114
170
  let(:ruby_code) {
115
171
  "class Book
116
- attributes = %i(title author)
117
- attr_accessor *attributes
118
- end"
172
+ attributes = %i(title author)
173
+ attr_accessor *attributes
174
+ end"
119
175
  }
120
176
  it 'will ignore them' do
121
177
  expect(defined_methods).to be_empty
@@ -126,9 +182,9 @@ describe ZombieScout::Parser do
126
182
  context 'when a ruby file uses Forwardable::def_delegator' do
127
183
  let(:ruby_code) {
128
184
  "class RecordCollection
129
- extend Forwardable
130
- def_delegator :@records, :[], :record_number
131
- end"
185
+ extend Forwardable
186
+ def_delegator :@records, :[], :record_number
187
+ end"
132
188
  }
133
189
  it 'can find methods created by def_delegator' do
134
190
  expect(defined_methods.map(&:name)).to match_array([:record_number])
@@ -138,9 +194,9 @@ describe ZombieScout::Parser do
138
194
  context 'when a ruby file uses Forwardable::def_delegators' do
139
195
  let(:ruby_code) {
140
196
  "class RecordCollection
141
- extend Forwardable
142
- def_delegators :@records, :size, :<<, :map
143
- end"
197
+ extend Forwardable
198
+ def_delegators :@records, :size, :<<, :map
199
+ end"
144
200
  }
145
201
  it 'can find methods created by def_delegators' do
146
202
  expect(defined_methods.map(&:name)).to match_array(%i[<< map size])
@@ -150,9 +206,9 @@ describe ZombieScout::Parser do
150
206
  context 'when a rails model has scopes' do
151
207
  let(:ruby_code) {
152
208
  "class Post
153
- scope :published, -> { where(published: true) }
154
- scope :draft, -> { where(published: true) }
155
- end"
209
+ scope :published, -> { where(published: true) }
210
+ scope :draft, -> { where(published: true) }
211
+ end"
156
212
  }
157
213
  it 'can find scopes' do
158
214
  expect(defined_methods.map(&:name)).to match_array(%i[draft published])
@@ -162,19 +218,19 @@ describe ZombieScout::Parser do
162
218
  context 'when a ruby file has private methods' do
163
219
  let(:ruby_code) {
164
220
  "class FizzBuzz
165
- def fizz
166
- magick_helper
167
- end
168
-
169
- private
170
- def magick_helper
171
- 'magick sauce'
172
- end
173
-
174
- def other_helper
175
- 'boo'
176
- end
177
- end"
221
+ def fizz
222
+ magick_helper
223
+ end
224
+
225
+ private
226
+ def magick_helper
227
+ 'magick sauce'
228
+ end
229
+
230
+ def other_helper
231
+ 'boo'
232
+ end
233
+ end"
178
234
  }
179
235
  it 'excludes private method calls, since we KNOW they are called' do
180
236
  expect(defined_methods.map(&:name)).to match_array([:fizz, :magick_helper, :other_helper])
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.3
4
+ version: 0.0.4
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-07 00:00:00.000000000 Z
11
+ date: 2014-03-11 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/method.rb
94
95
  - lib/zombie_scout/method_call_finder.rb
95
96
  - lib/zombie_scout/mission.rb
96
97
  - lib/zombie_scout/parser.rb