zombie_scout 0.0.3 → 0.0.4

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
  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