reek 0.0.1 → 0.1.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.
- data/History.txt +9 -0
- data/README.txt +12 -1
- data/lib/reek.rb +12 -9
- data/lib/reek/checker.rb +13 -5
- data/lib/reek/class_checker.rb +4 -4
- data/lib/reek/method_checker.rb +3 -0
- data/lib/reek/report.rb +7 -5
- data/lib/reek/smells.rb +12 -3
- data/lib/reek/version.rb +2 -2
- data/spec/reek/long_method_spec.rb +52 -0
- data/spec/reek/method_checker_spec.rb +0 -38
- data/spec/reek/nested_iterators_spec.rb +20 -0
- data/tasks/rspec.rake +6 -6
- data/website/index.html +13 -8
- data/website/index.txt +9 -5
- metadata +4 -2
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
== 0.1.0 2008-09-09
|
2
|
+
|
3
|
+
* 1 minor enhancement:
|
4
|
+
* Added a check for nested iterators within a method
|
5
|
+
* Some tweaks:
|
6
|
+
* Begun adding some rdoc
|
7
|
+
* Split some of the specs into more meaningful chunks
|
8
|
+
* Updated the rakefile so that rcov is no longer the default
|
9
|
+
|
1
10
|
== 0.0.1 2008-09-08
|
2
11
|
|
3
12
|
* 1 major enhancement:
|
data/README.txt
CHANGED
@@ -9,8 +9,19 @@
|
|
9
9
|
Reek is a tool that examines Ruby classes, modules and methods and
|
10
10
|
reports any code smells it finds.
|
11
11
|
|
12
|
+
=== SUPPORTED SMELLS:
|
13
|
+
|
14
|
+
* Long Method
|
15
|
+
* Large Class
|
16
|
+
* Feature Envy
|
17
|
+
* Uncommunicative Name
|
18
|
+
* Long Parameter List
|
19
|
+
* Utility Function
|
20
|
+
* Nested Iterators
|
21
|
+
|
12
22
|
== FEATURES/PROBLEMS:
|
13
23
|
|
24
|
+
* Most of the current checks are quite naive.
|
14
25
|
* Not many smells checked right now; more coming soon.
|
15
26
|
* The current Feature Envy check is probably over zealous.
|
16
27
|
* There's no convenient programmer's API just yet.
|
@@ -32,7 +43,7 @@ reports any code smells it finds.
|
|
32
43
|
|
33
44
|
(The MIT License)
|
34
45
|
|
35
|
-
Copyright (c) Kevin Rutherford, Rutherford Software
|
46
|
+
Copyright (c) 2008 Kevin Rutherford, Rutherford Software
|
36
47
|
|
37
48
|
Permission is hereby granted, free of charge, to any person obtaining
|
38
49
|
a copy of this software and associated documentation files (the
|
data/lib/reek.rb
CHANGED
@@ -3,14 +3,17 @@ $:.unshift File.dirname(__FILE__)
|
|
3
3
|
require 'reek/class_checker'
|
4
4
|
require 'reek/report'
|
5
5
|
|
6
|
-
module Reek
|
6
|
+
module Reek # :doc:
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
8
|
+
#
|
9
|
+
# Analyse the given instances of class Class, looking for code smells.
|
10
|
+
# Returns a +Report+ listing the smells found.
|
11
|
+
#
|
12
|
+
def self.analyse(*klasses) # :doc:
|
13
|
+
report = Report.new
|
14
|
+
klasses.each do |klass|
|
15
|
+
ClassChecker.new(report).check_object(klass)
|
16
|
+
end
|
17
|
+
report
|
18
|
+
end
|
16
19
|
end
|
data/lib/reek/checker.rb
CHANGED
@@ -9,31 +9,39 @@ module Reek
|
|
9
9
|
class Checker < SexpProcessor
|
10
10
|
attr_accessor :description
|
11
11
|
|
12
|
-
|
12
|
+
# Creates a new Ruby code checker. Any smells discovered by
|
13
|
+
# +check_source+ or +check_object+ will be stored in +report+.
|
14
|
+
def initialize(report)
|
13
15
|
super()
|
14
16
|
@require_empty = false
|
15
|
-
@smells =
|
17
|
+
@smells = report
|
16
18
|
@description = ''
|
17
19
|
@unsupported -= [:cfunc]
|
18
20
|
end
|
19
21
|
|
20
|
-
def report(smell)
|
22
|
+
def report(smell) # :nodoc:
|
21
23
|
@smells << smell
|
22
24
|
end
|
23
25
|
|
26
|
+
# Analyses the given Ruby source +code+ looking for smells.
|
27
|
+
# Any smells found are saved in the +Report+ object that
|
28
|
+
# was passed to this object's constructor.
|
24
29
|
def check_source(code)
|
25
30
|
check_parse_tree ParseTree.new.parse_tree_for_string(code)
|
26
31
|
end
|
27
32
|
|
33
|
+
# Analyses the given Ruby object +obj+ looking for smells.
|
34
|
+
# Any smells found are saved in the +Report+ object that
|
35
|
+
# was passed to this object's constructor.
|
28
36
|
def check_object(obj)
|
29
37
|
check_parse_tree ParseTree.new.parse_tree(obj)
|
30
38
|
end
|
31
39
|
|
32
|
-
def to_s
|
40
|
+
def to_s # :nodoc:
|
33
41
|
description
|
34
42
|
end
|
35
43
|
|
36
|
-
def check_parse_tree(sexp)
|
44
|
+
def check_parse_tree(sexp) # :nodoc:
|
37
45
|
sexp.each { |exp| process(exp) }
|
38
46
|
end
|
39
47
|
end
|
data/lib/reek/class_checker.rb
CHANGED
@@ -7,12 +7,12 @@ module Reek
|
|
7
7
|
|
8
8
|
class ClassChecker < Checker
|
9
9
|
|
10
|
-
def initialize(
|
11
|
-
super(
|
10
|
+
def initialize(report)
|
11
|
+
super(report)
|
12
12
|
@description = ''
|
13
13
|
end
|
14
14
|
|
15
|
-
def process_class(exp)
|
15
|
+
def process_class(exp) # :nodoc:
|
16
16
|
@description = exp[1].to_s
|
17
17
|
superclass = exp[2]
|
18
18
|
LargeClass.check(@description, self)
|
@@ -20,7 +20,7 @@ module Reek
|
|
20
20
|
s(exp)
|
21
21
|
end
|
22
22
|
|
23
|
-
def process_defn(exp)
|
23
|
+
def process_defn(exp) # :nodoc:
|
24
24
|
bc = Reek::MethodChecker.new(@smells, @description)
|
25
25
|
bc.process(exp)
|
26
26
|
s(exp)
|
data/lib/reek/method_checker.rb
CHANGED
@@ -15,6 +15,7 @@ module Reek
|
|
15
15
|
@top_level_block = true
|
16
16
|
@calls = Hash.new(0)
|
17
17
|
@lvars = Set.new
|
18
|
+
@inside_an_iter = false
|
18
19
|
end
|
19
20
|
|
20
21
|
def process_defn(exp)
|
@@ -39,7 +40,9 @@ module Reek
|
|
39
40
|
end
|
40
41
|
|
41
42
|
def process_iter(exp)
|
43
|
+
NestedIterators.check(@inside_an_iter, self)
|
42
44
|
@top_level_block = false
|
45
|
+
@inside_an_iter = true
|
43
46
|
exp[1..-1].each { |s| process(s) }
|
44
47
|
s(exp)
|
45
48
|
end
|
data/lib/reek/report.rb
CHANGED
@@ -3,26 +3,28 @@ $:.unshift File.dirname(__FILE__)
|
|
3
3
|
module Reek
|
4
4
|
|
5
5
|
class Report
|
6
|
-
def initialize
|
6
|
+
def initialize # :nodoc:
|
7
7
|
@smells = []
|
8
8
|
end
|
9
9
|
|
10
|
-
def <<(smell)
|
10
|
+
def <<(smell) # :nodoc:
|
11
11
|
@smells << smell
|
12
12
|
end
|
13
13
|
|
14
|
-
def empty?
|
14
|
+
def empty? # :nodoc:
|
15
15
|
@smells.empty?
|
16
16
|
end
|
17
17
|
|
18
|
-
def length
|
18
|
+
def length # :nodoc:
|
19
19
|
@smells.length
|
20
20
|
end
|
21
21
|
|
22
|
-
def [](i)
|
22
|
+
def [](i) # :nodoc:
|
23
23
|
@smells[i]
|
24
24
|
end
|
25
25
|
|
26
|
+
# Creates a formatted report of all the smells recorded in
|
27
|
+
# this report.
|
26
28
|
def to_s
|
27
29
|
@smells.map {|smell| smell.report}.join("\n")
|
28
30
|
end
|
data/lib/reek/smells.rb
CHANGED
@@ -103,15 +103,14 @@ module Reek
|
|
103
103
|
|
104
104
|
def recognise?(calls)
|
105
105
|
max = calls.empty? ? 0 : calls.values.max
|
106
|
-
|
107
|
-
return false unless max > mine
|
106
|
+
return false unless max > calls[:self]
|
108
107
|
receivers = calls.keys.select { |key| calls[key] == max }
|
109
108
|
@receiver = receivers.map {|r| Printer.print(r)}.sort.join(' or ')
|
110
109
|
return true
|
111
110
|
end
|
112
111
|
|
113
112
|
def detailed_report
|
114
|
-
"#{@context}
|
113
|
+
"#{@context} uses #{@receiver} more than self"
|
115
114
|
end
|
116
115
|
end
|
117
116
|
|
@@ -156,4 +155,14 @@ module Reek
|
|
156
155
|
"#{@context} uses the #{@symbol_type} name '#{@symbol}'"
|
157
156
|
end
|
158
157
|
end
|
158
|
+
|
159
|
+
class NestedIterators < Smell
|
160
|
+
def recognise?(already_in_iter)
|
161
|
+
already_in_iter
|
162
|
+
end
|
163
|
+
|
164
|
+
def detailed_report
|
165
|
+
"#{@context} has nested iterators"
|
166
|
+
end
|
167
|
+
end
|
159
168
|
end
|
data/lib/reek/version.rb
CHANGED
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
require 'reek/method_checker'
|
4
|
+
require 'reek/report'
|
5
|
+
|
6
|
+
include Reek
|
7
|
+
|
8
|
+
describe MethodChecker, "(Long Method)" do
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
@rpt = Report.new
|
12
|
+
@cchk = MethodChecker.new(@rpt, 'Thing')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should not report short methods' do
|
16
|
+
@cchk.check_source('def short(arga) alf = f(1);@bet = 2;@cut = 3;@dit = 4; @emp = 5;end')
|
17
|
+
@rpt.should be_empty
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should report long methods' do
|
21
|
+
@cchk.check_source('def long(arga) alf = f(1);@bet = 2;@cut = 3;@dit = 4; @emp = 5;@fry = 6;end')
|
22
|
+
@rpt.length.should == 1
|
23
|
+
@rpt[0].should == LongMethod.new(@cchk)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe MethodChecker, "(Long Block)" do
|
28
|
+
|
29
|
+
before(:each) do
|
30
|
+
@rpt = Report.new
|
31
|
+
@cchk = MethodChecker.new(@rpt, 'Thing')
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should report long inner block' do
|
35
|
+
src = <<EOS
|
36
|
+
def long(arga)
|
37
|
+
f(3)
|
38
|
+
37.each do |xyzero|
|
39
|
+
xyzero = 1
|
40
|
+
xyzero = 2
|
41
|
+
xyzero = 3
|
42
|
+
xyzero = 4
|
43
|
+
xyzero = 5
|
44
|
+
xyzero = 6
|
45
|
+
end
|
46
|
+
end
|
47
|
+
EOS
|
48
|
+
@cchk.check_source(src)
|
49
|
+
@rpt.length.should == 1
|
50
|
+
@rpt[0].report.should match(/block/)
|
51
|
+
end
|
52
|
+
end
|
@@ -149,44 +149,6 @@ describe LongParameterList, '#report' do
|
|
149
149
|
|
150
150
|
end
|
151
151
|
|
152
|
-
describe MethodChecker, "(Long Method)" do
|
153
|
-
|
154
|
-
before(:each) do
|
155
|
-
@rpt = Report.new
|
156
|
-
@cchk = MethodChecker.new(@rpt, 'Thing')
|
157
|
-
end
|
158
|
-
|
159
|
-
it 'should not report short methods' do
|
160
|
-
@cchk.check_source('def short(arga) alf = f(1);@bet = 2;@cut = 3;@dit = 4; @emp = 5;end')
|
161
|
-
@rpt.should be_empty
|
162
|
-
end
|
163
|
-
|
164
|
-
it 'should report long methods' do
|
165
|
-
@cchk.check_source('def long(arga) alf = f(1);@bet = 2;@cut = 3;@dit = 4; @emp = 5;@fry = 6;end')
|
166
|
-
@rpt.length.should == 1
|
167
|
-
@rpt[0].should == LongMethod.new(@cchk)
|
168
|
-
end
|
169
|
-
|
170
|
-
it 'should report long inner block' do
|
171
|
-
src = <<EOS
|
172
|
-
def long(arga)
|
173
|
-
f(3)
|
174
|
-
37.each do |xyzero|
|
175
|
-
xyzero = 1
|
176
|
-
xyzero = 2
|
177
|
-
xyzero = 3
|
178
|
-
xyzero = 4
|
179
|
-
xyzero = 5
|
180
|
-
xyzero = 6
|
181
|
-
end
|
182
|
-
end
|
183
|
-
EOS
|
184
|
-
@cchk.check_source(src)
|
185
|
-
@rpt.length.should == 1
|
186
|
-
@rpt[0].report.should match(/block/)
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
152
|
describe MethodChecker, 'when given a C extension' do
|
191
153
|
|
192
154
|
before(:each) do
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
require 'reek/method_checker'
|
4
|
+
require 'reek/report'
|
5
|
+
|
6
|
+
include Reek
|
7
|
+
|
8
|
+
describe MethodChecker, " nested iterators" do
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
@rpt = Report.new
|
12
|
+
@chk = MethodChecker.new(@rpt, 'Thing')
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should report nested iterators in a method" do
|
16
|
+
@chk.check_source('def bad(fred) @fred.each {|item| item.each {|ting| ting.ting} } end')
|
17
|
+
@rpt.length.should == 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
data/tasks/rspec.rake
CHANGED
@@ -20,12 +20,12 @@ end
|
|
20
20
|
REPORT_DIR = 'spec/output/coverage'
|
21
21
|
CLEAN.include(REPORT_DIR)
|
22
22
|
|
23
|
-
desc
|
24
|
-
Spec::Rake::SpecTask.new(:
|
25
|
-
t.
|
26
|
-
t.spec_files = FileList['spec/**/*_spec.rb']
|
23
|
+
desc "runs the specs"
|
24
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
25
|
+
t.spec_files = FileList['spec/**/*.rb']
|
27
26
|
end
|
28
27
|
|
28
|
+
desc "runs the specs and reports coverage in #{REPORT_DIR}"
|
29
29
|
Spec::Rake::SpecTask.new(:spec_rcov) do |t|
|
30
30
|
t.spec_files = FileList['spec/**/*.rb']
|
31
31
|
t.rcov = true
|
@@ -33,8 +33,8 @@ Spec::Rake::SpecTask.new(:spec_rcov) do |t|
|
|
33
33
|
t.rcov_opts = ['--exclude', 'spec,\.autotest']
|
34
34
|
end
|
35
35
|
|
36
|
-
"runs the specs and
|
37
|
-
RCov::VerifyTask.new(:
|
36
|
+
desc "runs the specs and checks for 100% coverage"
|
37
|
+
RCov::VerifyTask.new(:rcov => :spec_rcov) do |t|
|
38
38
|
t.index_html = "#{REPORT_DIR}/index.html"
|
39
39
|
t.threshold = 100
|
40
40
|
end
|
data/website/index.html
CHANGED
@@ -33,7 +33,7 @@
|
|
33
33
|
<h1>Code smell detector</h1>
|
34
34
|
<div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/reek"; return false'>
|
35
35
|
<p>Get Version</p>
|
36
|
-
<a href="http://rubyforge.org/projects/reek" class="numbers">0.0
|
36
|
+
<a href="http://rubyforge.org/projects/reek" class="numbers">0.1.0</a>
|
37
37
|
</div>
|
38
38
|
<h1>→ ‘reek’</h1>
|
39
39
|
|
@@ -62,16 +62,21 @@
|
|
62
62
|
<p>(More details coming soon…)</p>
|
63
63
|
|
64
64
|
|
65
|
-
<h2>
|
65
|
+
<h2>Code Smells</h2>
|
66
66
|
|
67
67
|
|
68
|
-
<p>
|
69
|
-
|
70
|
-
|
71
|
-
<h2>Forum</h2>
|
68
|
+
<p>reek currently includes very naive checks for the following code smells:</p>
|
72
69
|
|
73
70
|
|
74
|
-
<
|
71
|
+
<ul>
|
72
|
+
<li>Long Method</li>
|
73
|
+
<li>Large Class</li>
|
74
|
+
<li>Feature Envy</li>
|
75
|
+
<li>Uncommunicative Name</li>
|
76
|
+
<li>Long Parameter List</li>
|
77
|
+
<li>Utility Function</li>
|
78
|
+
<li>Nested Iterators</li>
|
79
|
+
</ul>
|
75
80
|
|
76
81
|
|
77
82
|
<h2>How to access the source code</h2>
|
@@ -91,7 +96,7 @@
|
|
91
96
|
|
92
97
|
<p>Comments are welcome. Send an email to <a href="mailto:kevin@rutherford-software.com">Kevin Rutherford</a></p>
|
93
98
|
<p class="coda">
|
94
|
-
<a href="http://www.kevinrutherford.co.uk">Kevin Rutherford</a>,
|
99
|
+
<a href="http://www.kevinrutherford.co.uk">Kevin Rutherford</a>, 9th September 2008<br>
|
95
100
|
Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
|
96
101
|
</p>
|
97
102
|
</div>
|
data/website/index.txt
CHANGED
@@ -20,13 +20,17 @@ h2. The basics
|
|
20
20
|
|
21
21
|
(More details coming soon...)
|
22
22
|
|
23
|
-
h2.
|
23
|
+
h2. Code Smells
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
h2. Forum
|
25
|
+
reek currently includes very naive checks for the following code smells:
|
28
26
|
|
29
|
-
|
27
|
+
* Long Method
|
28
|
+
* Large Class
|
29
|
+
* Feature Envy
|
30
|
+
* Uncommunicative Name
|
31
|
+
* Long Parameter List
|
32
|
+
* Utility Function
|
33
|
+
* Nested Iterators
|
30
34
|
|
31
35
|
h2. How to access the source code
|
32
36
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reek
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Rutherford
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-09-
|
12
|
+
date: 2008-09-09 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -60,7 +60,9 @@ files:
|
|
60
60
|
- spec/reek/class_checker_spec.rb
|
61
61
|
- spec/reek/feature_envy_spec.rb
|
62
62
|
- spec/reek/large_class_spec.rb
|
63
|
+
- spec/reek/long_method_spec.rb
|
63
64
|
- spec/reek/method_checker_spec.rb
|
65
|
+
- spec/reek/nested_iterators_spec.rb
|
64
66
|
- spec/reek/report_spec.rb
|
65
67
|
- spec/reek/smell_spec.rb
|
66
68
|
- spec/reek/uncommunicative_name_spec.rb
|