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 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
- def self.analyse(*klasses)
9
- report = Report.new
10
- klasses.each do |klass|
11
- ClassChecker.new(report).check_object(klass)
12
- end
13
- report
14
- end
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
- def initialize(smells)
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 = 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
@@ -7,12 +7,12 @@ module Reek
7
7
 
8
8
  class ClassChecker < Checker
9
9
 
10
- def initialize(smells)
11
- super(smells)
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)
@@ -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
- mine = calls[:self]
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} could be moved to #{@receiver}"
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
@@ -1,8 +1,8 @@
1
1
  module Reek #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 0
5
- TINY = 1
4
+ MINOR = 1
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -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 'runs the specs in colour'
24
- Spec::Rake::SpecTask.new(:spec_colour) do |t|
25
- t.spec_opts = ['--options', "spec/spec.opts"]
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 reports coverage in #{REPORT_DIR}"
37
- RCov::VerifyTask.new(:spec => :spec_rcov) do |t|
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.1</a>
36
+ <a href="http://rubyforge.org/projects/reek" class="numbers">0.1.0</a>
37
37
  </div>
38
38
  <h1>&#x2192; &#8216;reek&#8217;</h1>
39
39
 
@@ -62,16 +62,21 @@
62
62
  <p>(More details coming soon&#8230;)</p>
63
63
 
64
64
 
65
- <h2>Demonstration of usage</h2>
65
+ <h2>Code Smells</h2>
66
66
 
67
67
 
68
- <p>(More details coming soon&#8230;)</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
- <p>Coming soon&#8230;</p>
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>, 8th September 2008<br>
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. Demonstration of usage
23
+ h2. Code Smells
24
24
 
25
- (More details coming soon...)
26
-
27
- h2. Forum
25
+ reek currently includes very naive checks for the following code smells:
28
26
 
29
- Coming soon...
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.1
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-08 00:00:00 +01:00
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