reek 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,15 @@
1
+ == 0.2.x 2008-??-??
2
+
3
+ * Minor enhancements:
4
+ * New smell: first naive checks for Control Couple
5
+ * reek now only checks sources passed on the command line
6
+ * Code snippets can be supplied on the commandline
7
+ * Added headings and warnings count when smells in multiple files
8
+ * Added Reek::RakeTask to run reek from rakefiles
9
+ * Tweaks:
10
+ * Fixed: Returns exit status 2 when smells are reported
11
+ * Fixed: no longer claims an empty method is a Utility Function
12
+
1
13
  == 0.2.3 2008-09-22
2
14
 
3
15
  * Minor enhancements:
data/README.txt CHANGED
@@ -1,8 +1,7 @@
1
1
  = reek
2
2
 
3
3
  * http://rubyforge.org/projects/reek/
4
- * http://www.refactoring-workbook.com/reek
5
- * kevin@rutherford-software.com
4
+ * mailto:kevin@rutherford-software.com
6
5
 
7
6
  == DESCRIPTION:
8
7
 
@@ -11,6 +10,8 @@ reports any code smells it finds.
11
10
 
12
11
  === SUPPORTED CODE SMELLS:
13
12
 
13
+ Reek currently includes very naive checks for the following smells:
14
+
14
15
  * Long Method
15
16
  * Large Class
16
17
  * Feature Envy
@@ -18,6 +19,7 @@ reports any code smells it finds.
18
19
  * Long Parameter List
19
20
  * Utility Function
20
21
  * Nested Iterators
22
+ * Control Couple
21
23
 
22
24
  == FEATURES/PROBLEMS:
23
25
 
@@ -28,13 +30,16 @@ reports any code smells it finds.
28
30
 
29
31
  == SYNOPSIS:
30
32
 
31
- $ reek [options] [source_files]
33
+ $ reek [options] sources
32
34
 
33
35
  (See `reek --help` for details.)
34
36
 
35
- == REQUIREMENTS:
37
+ == DEPENDENCIES:
38
+
39
+ Reek makes use of the following other gems:
36
40
 
37
41
  * ParseTree
42
+ * sexp_processor
38
43
 
39
44
  == INSTALL:
40
45
 
@@ -42,7 +47,7 @@ Get the latest version of the gem:
42
47
 
43
48
  $ gem install reek
44
49
 
45
- Or get the latest unpackaged source code:
50
+ Or get the latest source code from:
46
51
 
47
52
  $ git clone git://github.com/kevinrutherford/reek.git
48
53
 
data/bin/reek CHANGED
@@ -2,9 +2,24 @@
2
2
  #
3
3
  # Created on 2008-2-17.
4
4
  # Copyright (c) 2008 Kevin Rutherford, Rutherford Software Ltd. All rights reserved.
5
+ #
6
+
7
+ require File.join(File.dirname(__FILE__), '../lib/', 'reek')
8
+ require File.join(File.dirname(__FILE__), '../lib/', 'reek/options')
5
9
 
6
- require 'reek'
7
- require 'reek/options'
10
+ sources = Reek::Options.parse(ARGV)
11
+ exitstatus = 0
12
+ sources.each do |src|
13
+ smells = Reek.analyse(src)
14
+ next if smells.empty?
15
+ if sources.size == 1
16
+ puts smells.to_s
17
+ else
18
+ puts "\"#{src}\" -- #{smells.length} warnings:"
19
+ puts smells.to_s
20
+ puts
21
+ end
22
+ exitstatus = 2
23
+ end
8
24
 
9
- files = Reek::Options.parse(ARGV)
10
- puts Reek.analyse(*files).to_s
25
+ exit(exitstatus)
data/lib/reek.rb CHANGED
@@ -5,16 +5,22 @@ require 'reek/report'
5
5
 
6
6
  module Reek # :doc:
7
7
 
8
- #
9
- # Analyse the given source files, looking for code smells.
10
- # Returns a +Report+ listing the smells found.
11
- #
12
- def self.analyse(*files) # :doc:
13
- report = Report.new
14
- files.each do |file|
15
- source = IO.readlines(file).join
16
- FileChecker.new(report).check_source(source)
17
- end
18
- report
19
- end
8
+ #
9
+ # Analyse the given source files, looking for code smells.
10
+ # Returns a +Report+ listing the smells found.
11
+ #
12
+ def self.analyse(*files) # :doc:
13
+ report = Report.new
14
+ files.each do |file|
15
+ source = Reek.read(file)
16
+ FileChecker.new(report).check_source(source)
17
+ end
18
+ report
19
+ end
20
+
21
+ private
22
+
23
+ def self.read(file)
24
+ File.exists?(file) ? IO.readlines(file).join : file
25
+ end
20
26
  end
@@ -29,6 +29,7 @@ module Reek
29
29
  def process_args(exp)
30
30
  LongParameterList.check(exp, self)
31
31
  exp.each { |arg| UncommunicativeName.check(arg, self, 'parameter') }
32
+ @args = exp[1..-1]
32
33
  s(exp)
33
34
  end
34
35
 
@@ -95,6 +96,14 @@ module Reek
95
96
  s(exp)
96
97
  end
97
98
 
99
+ def process_if(exp)
100
+ process(exp[1])
101
+ process(exp[2])
102
+ process(exp[3]) if exp[3]
103
+ ControlCouple.check(exp[1], self, @args)
104
+ s(exp)
105
+ end
106
+
98
107
  def process_ivar(exp)
99
108
  UncommunicativeName.check(exp[1], self, 'field')
100
109
  @depends_on_self = true
@@ -127,6 +136,7 @@ module Reek
127
136
  def self.count_statements(exp)
128
137
  result = exp.length - 1
129
138
  result -= 1 if Array === exp[1] and exp[1][0] == :args
139
+ result -= 1 if exp[2] == s(:nil)
130
140
  result
131
141
  end
132
142
 
@@ -155,7 +165,7 @@ module Reek
155
165
  def check_method_properties
156
166
  @lvars.each {|lvar| UncommunicativeName.check(lvar, self, 'local variable') }
157
167
  @depends_on_self = true if is_override?
158
- FeatureEnvy.check(@refs, self) unless UtilityFunction.check(@depends_on_self, self)
168
+ FeatureEnvy.check(@refs, self) unless UtilityFunction.check(@depends_on_self, self, @num_statements)
159
169
  LongMethod.check(@num_statements, self) unless method_name == 'initialize'
160
170
  end
161
171
  end
data/lib/reek/options.rb CHANGED
@@ -10,7 +10,10 @@ module Reek
10
10
 
11
11
  class Options
12
12
  def self.default_options
13
- {:sort_order => Report::SORT_ORDERS[:context]}
13
+ {
14
+ :sort_order => Report::SORT_ORDERS[:context],
15
+ :expressions => []
16
+ }
14
17
  end
15
18
 
16
19
  @@opts = default_options
@@ -22,24 +25,26 @@ module Reek
22
25
  def self.parse_args(args)
23
26
  result = default_options
24
27
  parser = OptionParser.new do |opts|
25
- opts.banner = "Usage: #{File.basename($0)} [options] [files]"
28
+ opts.banner = <<EOB
29
+ Usage: #{File.basename($0)} [options] SOURCES
30
+
31
+ The SOURCES may be any combination of file paths and Ruby source code.
32
+ EOB
26
33
 
27
34
  opts.separator ""
28
- opts.separator "Specific options:"
35
+ opts.separator "Options:"
36
+
37
+ opts.on("-h", "--help", "Show this message") do
38
+ puts opts
39
+ exit(0)
40
+ end
29
41
 
30
42
  opts.on('-s', "--sort ORDER", Report::SORT_ORDERS.keys,
31
43
  "Select sort order for report (#{Report::SORT_ORDERS.keys.join(', ')})") do |arg|
32
44
  result[:sort_order] = Report::SORT_ORDERS[arg] unless arg.nil?
33
45
  end
34
46
 
35
- opts.separator ""
36
- opts.separator "Common options:"
37
- opts.on_tail("-h", "--help", "Show this message") do
38
- puts opts
39
- exit(0)
40
- end
41
-
42
- opts.on_tail("-v", "--version", "Show version") do
47
+ opts.on("-v", "--version", "Show version") do
43
48
  puts "#{File.basename($0)} #{Reek::VERSION::STRING}"
44
49
  exit(0)
45
50
  end
@@ -58,10 +63,7 @@ module Reek
58
63
  def self.parse(args)
59
64
  begin
60
65
  @@opts = parse_args(args)
61
- files = ARGV
62
- files = Dir['**/*.rb'] if files.empty?
63
- fatal_error('no source files specified') if files.empty?
64
- files
66
+ ARGV
65
67
  rescue OptionParser::ParseError => e
66
68
  fatal_error(e)
67
69
  end
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Define a task library for running reek.
4
+
5
+ require 'rake'
6
+ require 'rake/tasklib'
7
+
8
+ module Reek
9
+
10
+ # A Rake task that runs reek on a set of source files.
11
+ #
12
+ # Example:
13
+ #
14
+ # Reek::RakeTask.new do |t|
15
+ # t.fail_on_error = false
16
+ # end
17
+ #
18
+ # This will create a task that can be run with:
19
+ #
20
+ # rake reek
21
+ #
22
+ # If rake is invoked with a "SPEC=filename" command line option,
23
+ # then the list of spec files will be overridden to include only the
24
+ # filename specified on the command line. This provides an easy way
25
+ # to run just one spec.
26
+ #
27
+ # If rake is invoked with a "REEK_SORT=order" command line option,
28
+ # then the given sort order will override the value of the +sort+
29
+ # attribute.
30
+ #
31
+ # Examples:
32
+ #
33
+ # rake reek # run specs normally
34
+ # rake reek SPEC=just_one_file.rb # run just one spec file.
35
+ # rake reek REEK_SORT=smell # sort warnings by smell
36
+ #
37
+ class RakeTask < ::Rake::TaskLib
38
+
39
+ # Name of reek task. (default is :reek)
40
+ attr_accessor :name
41
+
42
+ # Array of directories to be added to $LOAD_PATH before running reek.
43
+ # Defaults to ['<the absolute path to reek's lib directory>']
44
+ attr_accessor :libs
45
+
46
+ # Glob pattern to match source files. (default is 'lib/**/*.rb')
47
+ # Setting the REEK_SRC environment variable overrides this.
48
+ attr_accessor :source_files
49
+
50
+ # Set the sort order for reported smells (see 'reek --help' for possible values).
51
+ # Setting the REEK_SORT environment variable overrides this.
52
+ attr_accessor :sort
53
+
54
+ # Array of commandline options to pass to ruby. Defaults to [].
55
+ attr_accessor :ruby_opts
56
+
57
+ # Whether or not to fail Rake when an error occurs (typically when specs fail).
58
+ # Defaults to true.
59
+ attr_accessor :fail_on_error
60
+
61
+ # Use verbose output. If this is set to true, the task will print
62
+ # the reek command to stdout. Defaults to false.
63
+ attr_accessor :verbose
64
+
65
+ # Defines a new task, using the name +name+.
66
+ def initialize(name = :reek)
67
+ @name = name
68
+ @libs = [File.expand_path(File.dirname(__FILE__) + '/../../../lib')]
69
+ @source_files = nil
70
+ @ruby_opts = []
71
+ @fail_on_error = true
72
+ @sort = nil
73
+
74
+ yield self if block_given?
75
+ @source_files ||= 'lib/**/*.rb'
76
+ define
77
+ end
78
+
79
+ def define # :nodoc:
80
+ desc "Check for code smells" unless ::Rake.application.last_comment
81
+ task(name) { run_task }
82
+ self
83
+ end
84
+
85
+ def run_task
86
+ return if source_file_list.empty?
87
+ cmd = cmd_words.join(' ')
88
+ puts cmd if @verbose
89
+ raise("Smells found!") if !system(cmd) and fail_on_error
90
+ end
91
+
92
+ def self.reek_script
93
+ File.expand_path(File.dirname(__FILE__) + '/../../bin/reek')
94
+ end
95
+
96
+ def self.ruby_exe
97
+ File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
98
+ end
99
+
100
+ def cmd_words
101
+ [self.class.ruby_exe] +
102
+ ruby_options +
103
+ [ %Q|"#{self.class.reek_script}"| ] +
104
+ [sort_option] +
105
+ source_file_list.collect { |fn| %["#{fn}"] }
106
+ end
107
+
108
+ def ruby_options
109
+ lib_path = @libs.join(File::PATH_SEPARATOR)
110
+ @ruby_opts.clone << "-I\"#{lib_path}\""
111
+ end
112
+
113
+ def sort_option
114
+ env_sort = ENV['REEK_SORT']
115
+ return "--sort #{env_sort}" if env_sort
116
+ return "--sort #{@sort}" if @sort
117
+ ''
118
+ end
119
+
120
+ def source_file_list # :nodoc:
121
+ env_src = ENV['REEK_SRC']
122
+ return env_src if env_src
123
+ return FileList[@source_files] if @source_files
124
+ []
125
+ end
126
+
127
+ end
128
+ end
data/lib/reek/smells.rb CHANGED
@@ -109,8 +109,13 @@ module Reek
109
109
  end
110
110
 
111
111
  class UtilityFunction < Smell
112
+ def initialize(context, num_stmts)
113
+ super
114
+ @num_stmts = num_stmts
115
+ end
116
+
112
117
  def recognise?(depends_on_self)
113
- !depends_on_self
118
+ @num_stmts > 0 and !depends_on_self
114
119
  end
115
120
 
116
121
  def detailed_report
@@ -168,4 +173,20 @@ module Reek
168
173
  "#{@context} has nested iterators"
169
174
  end
170
175
  end
176
+
177
+ class ControlCouple < Smell
178
+ def initialize(context, args)
179
+ super
180
+ @args = args
181
+ end
182
+
183
+ def recognise?(cond)
184
+ @couple = cond
185
+ cond[0] == :lvar and @args.include?(@couple[1])
186
+ end
187
+
188
+ def detailed_report
189
+ "#{@context} is controlled by argument #{Printer.print(@couple)}"
190
+ end
191
+ end
171
192
  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 = 2
5
- TINY = 3
4
+ MINOR = 3
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -1,15 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
 
3
- require 'reek/version'
4
-
5
- describe 'Reek version number' do
6
- it 'should report the correct value' do
7
- actual = `ruby -Ilib bin/reek --version`.split
8
- actual[0].should == 'reek'
9
- actual[1].should == Reek::VERSION::STRING
10
- end
11
- end
12
-
13
3
  describe 'Integration test:' do
14
4
  Dir['spec/samples/*.rb'].each do |source|
15
5
  describe source do
@@ -0,0 +1,31 @@
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, "(Control Couple)" do
9
+
10
+ before(:each) do
11
+ @rpt = Report.new
12
+ @cchk = MethodChecker.new(@rpt, 'Thing')
13
+ end
14
+
15
+ it 'should report a ternary check on a parameter' do
16
+ @cchk.check_source('def simple(arga) arga ? @ivar : 3 end')
17
+ @rpt.length.should == 1
18
+ ControlCouple.should === @rpt[0]
19
+ @rpt[0].to_s.should match(/arga/)
20
+ end
21
+
22
+ it 'should not report a ternary check on an ivar' do
23
+ @cchk.check_source('def simple(arga) @ivar ? arga : 3 end')
24
+ @rpt.should be_empty
25
+ end
26
+
27
+ it 'should not report a ternary check on a lvar' do
28
+ @cchk.check_source('def simple(arga) lvar = 27; lvar ? arga : @ivar end')
29
+ @rpt.should be_empty
30
+ end
31
+ end
@@ -186,8 +186,8 @@ describe FeatureEnvy, 'when the receiver is a dvar' do
186
186
  @cchk = MethodChecker.new(@rpt, 'Thing')
187
187
  end
188
188
 
189
- it "should not report method with successive iterators" do
190
- pending('this is a bug!')
189
+ it "should count each scope separately" do
190
+ pending('bug')
191
191
  source =<<EOS
192
192
  def bad(fred)
193
193
  @fred.each {|item| item.each }
@@ -198,3 +198,25 @@ EOS
198
198
  @rpt.should be_empty
199
199
  end
200
200
  end
201
+
202
+ describe FeatureEnvy, 'when the receiver is a message chain keyed on self' do
203
+ before(:each) do
204
+ @rpt = Report.new
205
+ @cchk = MethodChecker.new(@rpt, 'Thing')
206
+ end
207
+
208
+ it "count the references correctly" do
209
+ pending('bug')
210
+ source =<<EOS
211
+ class Parcel
212
+ def addressee
213
+ "#{self.person.first_name} #{self.person.last_name}"
214
+ end
215
+ end
216
+ EOS
217
+ @chk.check_source(source)
218
+ @rpt.length.should == 1
219
+ FeatureEnvy.should === @rpt[0]
220
+ @rpt[0].to_s.should match(/self.person/)
221
+ end
222
+ end
@@ -7,7 +7,7 @@ include Reek
7
7
  describe Options, ' when given no arguments' do
8
8
  it "should retain the default sort order" do
9
9
  default_order = Options[:sort_order]
10
- Options.parse []
10
+ Options.parse ['nosuchfile.rb']
11
11
  Options[:sort_order].should == default_order
12
12
  end
13
13
  end
@@ -23,12 +23,12 @@ describe Options, ' when --sort_order is specified' do
23
23
  end
24
24
 
25
25
  it "should allow sort by smell" do
26
- Options.parse %w{-s smell}
26
+ Options.parse %w{-s smell xx}
27
27
  Options[:sort_order].should == Report::SORT_ORDERS[:smell]
28
28
  end
29
29
 
30
30
  it "should allow sort by context" do
31
- Options.parse %w{-s context}
31
+ Options.parse %w{-s context xx}
32
32
  Options[:sort_order].should == Report::SORT_ORDERS[:context]
33
33
  end
34
34
 
@@ -41,9 +41,9 @@ end
41
41
  describe Report, " as a SortedSet" do
42
42
  it 'should only add a smell once' do
43
43
  rpt = Report.new
44
- rpt << UtilityFunction.new(self)
44
+ rpt << UtilityFunction.new(self, 1)
45
45
  rpt.length.should == 1
46
- rpt << UtilityFunction.new(self)
46
+ rpt << UtilityFunction.new(self, 1)
47
47
  rpt.length.should == 1
48
48
  end
49
49
  end
@@ -17,17 +17,17 @@ end
17
17
 
18
18
  describe Smell, ' in comparisons' do
19
19
  it 'should hash equal when the smell is the same' do
20
- UtilityFunction.new(self).hash.should == UtilityFunction.new(self).hash
20
+ UtilityFunction.new(self, 2).hash.should == UtilityFunction.new(self, 2).hash
21
21
  NestedIterators.new(self).hash.should == NestedIterators.new(self).hash
22
22
  end
23
23
 
24
24
  it 'should compare equal when the smell is the same' do
25
- UtilityFunction.new(self).should == UtilityFunction.new(self)
25
+ UtilityFunction.new(self, 2).should == UtilityFunction.new(self, 2)
26
26
  NestedIterators.new(self).should == NestedIterators.new(self)
27
27
  end
28
28
 
29
29
  it 'should compare equal when using <=>' do
30
- (UtilityFunction.new(self) <=> UtilityFunction.new(self)).should == 0
30
+ (UtilityFunction.new(self, 2) <=> UtilityFunction.new(self, 2)).should == 0
31
31
  (NestedIterators.new(self) <=> NestedIterators.new(self)).should == 0
32
32
  end
33
33
  end
@@ -12,6 +12,11 @@ describe MethodChecker, "(Utility Function)" do
12
12
  @cchk = MethodChecker.new(@rpt, 'Thing')
13
13
  end
14
14
 
15
+ it 'should not report empty method' do
16
+ @cchk.check_source('def simple(arga) end')
17
+ @rpt.should be_empty
18
+ end
19
+
15
20
  it 'should not report instance variable reference' do
16
21
  @cchk.check_source('def simple(arga) @yellow end')
17
22
  @rpt.should be_empty
@@ -29,7 +34,7 @@ describe MethodChecker, "(Utility Function)" do
29
34
  @cchk.check_object(Fred)
30
35
  @rpt.should be_empty
31
36
  end
32
-
37
+
33
38
  it 'should not report references to self' do
34
39
  @cchk.check_source('def into; self; end')
35
40
  @rpt.should be_empty
@@ -54,7 +59,7 @@ describe MethodChecker, "(Utility Function)" do
54
59
  it 'should report simple parameter call' do
55
60
  @cchk.check_source('def simple(arga) arga.to_s end')
56
61
  @rpt.length.should == 1
57
- @rpt[0].should == UtilityFunction.new(@cchk)
62
+ @rpt[0].should == UtilityFunction.new(@cchk, 1)
58
63
  end
59
64
 
60
65
  it 'should report message chain' do
@@ -72,4 +77,19 @@ describe MethodChecker, "(Utility Function)" do
72
77
  ClassChecker.new(@rpt).check_object(Son)
73
78
  @rpt.should be_empty
74
79
  end
80
+
81
+ it 'should not report class method' do
82
+ pending('bug')
83
+ source = <<EOS
84
+ class Cache
85
+ class << self
86
+ def create_unless_known(attributes)
87
+ Cache.create(attributes) unless Cache.known?
88
+ end
89
+ end
90
+ end
91
+ EOS
92
+ @cchk.check_source(source)
93
+ @rpt.should be_empty
94
+ end
75
95
  end
@@ -4,7 +4,8 @@ describe 'Reek source code:' do
4
4
  Dir['lib/**/*.rb'].each do |source|
5
5
  describe source do
6
6
  it 'should report no smells' do
7
- `ruby -Ilib bin/reek #{source}`.should == "\n"
7
+ `ruby -Ilib bin/reek #{source}`.should == ''
8
+ $?.exitstatus.should == 0
8
9
  end
9
10
  end
10
11
  end
@@ -11,7 +11,9 @@
11
11
  [Nested Iterators] C#module_name has nested iterators
12
12
  [Feature Envy] C#module_name uses md5 more than self
13
13
  [Long Method] C#parse_signature has approx 15 statements
14
+ [Control Couple] C#parse_signature is controlled by argument raw
14
15
  [Utility Function] C#strip_comments doesn't depend on instance state
15
16
  [Large Class] Dir has 31 methods
16
17
  [Large Class] Module has 34 methods
17
18
  [Long Method] Module#inline has approx 12 statements
19
+ [Control Couple] Module#inline is controlled by argument options
@@ -1,5 +1,4 @@
1
1
  [Large Class] AmbiguousArgument has 52 methods
2
- [Long Method] AmbiguousArgument#options has approx 6 statements
3
2
  [Long Parameter List] CompletingHash#complete has 4 parameters
4
3
  [Nested Iterators] CompletingHash#complete has nested iterators
5
4
  [Long Method] CompletingHash#getopts has approx 17 statements
@@ -13,11 +12,13 @@
13
12
  [Nested Iterators] CompletingHash#match has nested iterators
14
13
  [Feature Envy] CompletingHash#order uses argv more than self
15
14
  [Feature Envy] CompletingHash#parse uses argv more than self
16
- [Long Method] CompletingHash#parse_in_order has approx 31 statements
15
+ [Long Method] CompletingHash#parse_in_order has approx 30 statements
17
16
  [Nested Iterators] CompletingHash#parse_in_order has nested iterators
17
+ [Control Couple] CompletingHash#parse_in_order is controlled by argument setter
18
18
  [Feature Envy] CompletingHash#permute uses argv more than self
19
19
  [Long Parameter List] CompletingHash#summarize has 4 parameters
20
20
  [Uncommunicative Name] CompletingHash#ver uses the local variable name 'v'
21
+ [Control Couple] List#accept is controlled by argument pat
21
22
  [Feature Envy] List#accept uses pat more than self
22
23
  [Uncommunicative Name] List#accept uses the parameter name 't'
23
24
  [Feature Envy] List#add_banner uses opt more than self
@@ -27,13 +28,19 @@
27
28
  [Feature Envy] List#summarize uses opt more than self
28
29
  [Long Parameter List] List#update has 5 parameters
29
30
  [Long Method] List#update has approx 6 statements
31
+ [Control Couple] List#update is controlled by argument lopts
32
+ [Control Couple] List#update is controlled by argument sopts
30
33
  [Uncommunicative Name] List#update uses the local variable name 'o'
34
+ [Control Couple] NoArgument#parse is controlled by argument arg
31
35
  [Long Method] OptionParser#complete has approx 23 statements
32
36
  [Feature Envy] OptionParser#complete uses candidates more than self
33
37
  [Uncommunicative Name] OptionParser#complete uses the local variable name 'k'
34
38
  [Uncommunicative Name] OptionParser#complete uses the local variable name 'v'
35
39
  [Utility Function] OptionParser#convert doesn't depend on instance state
40
+ [Control Couple] OptionalArgument#parse is controlled by argument arg
41
+ [Control Couple] ParseError#set_option is controlled by argument eq
36
42
  [Long Method] PlacedArgument#parse has approx 6 statements
43
+ [Control Couple] RequiredArgument#parse is controlled by argument arg
37
44
  [Uncommunicative Name] Switch#add_banner uses the local variable name 's'
38
45
  [Long Parameter List] Switch#initialize has 7 parameters
39
46
  [Long Method] Switch#parse_arg has approx 12 statements
@@ -1,5 +1,4 @@
1
1
  [Long Method] RedCloth#block_markdown_bq has approx 6 statements
2
- [Utility Function] RedCloth#block_markdown_lists doesn't depend on instance state
3
2
  [Utility Function] RedCloth#block_markdown_rule doesn't depend on instance state
4
3
  [Long Method] RedCloth#block_textile_lists has approx 21 statements
5
4
  [Nested Iterators] RedCloth#block_textile_lists has nested iterators
@@ -8,6 +7,8 @@
8
7
  [Nested Iterators] RedCloth#block_textile_table has nested iterators
9
8
  [Long Method] RedCloth#blocks has approx 17 statements
10
9
  [Nested Iterators] RedCloth#blocks has nested iterators
10
+ [Control Couple] RedCloth#blocks is controlled by argument deep_code
11
+ [Control Couple] RedCloth#check_refs is controlled by argument text
11
12
  [Utility Function] RedCloth#clean_html doesn't depend on instance state
12
13
  [Long Method] RedCloth#clean_html has approx 14 statements
13
14
  [Nested Iterators] RedCloth#clean_html has nested iterators
@@ -29,13 +30,18 @@
29
30
  [Utility Function] RedCloth#lT doesn't depend on instance state
30
31
  [Utility Function] RedCloth#no_textile doesn't depend on instance state
31
32
  [Long Method] RedCloth#pba has approx 22 statements
33
+ [Control Couple] RedCloth#pba is controlled by argument text_in
32
34
  [Feature Envy] RedCloth#pba uses style and text more than self
33
35
  [Long Method] RedCloth#rip_offtags has approx 22 statements
34
36
  [Feature Envy] RedCloth#rip_offtags uses codepre more than self
35
37
  [Feature Envy] RedCloth#shelve uses @shelf more than self
36
38
  [Feature Envy] RedCloth#smooth_offtags uses @pre_list more than self
37
39
  [Long Parameter List] RedCloth#textile_bq has 4 parameters
40
+ [Control Couple] RedCloth#textile_bq is controlled by argument atts
41
+ [Control Couple] RedCloth#textile_bq is controlled by argument cite
38
42
  [Long Parameter List] RedCloth#textile_fn_ has 5 parameters
43
+ [Control Couple] RedCloth#textile_fn_ is controlled by argument atts
39
44
  [Long Parameter List] RedCloth#textile_p has 4 parameters
45
+ [Control Couple] RedCloth#textile_p is controlled by argument atts
40
46
  [Long Method] RedCloth#to_html has approx 24 statements
41
47
  [Utility Function] RedCloth#v_align doesn't depend on instance state
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ require 'reek/version'
4
+
5
+ describe 'version number' do
6
+ it 'should report the correct value' do
7
+ actual = `ruby -Ilib bin/reek --version`.split
8
+ $?.exitstatus.should == 0
9
+ actual[0].should == 'reek'
10
+ actual[1].should == Reek::VERSION::STRING
11
+ end
12
+ end
13
+
14
+ describe 'exit status', 'when reek is used incorrectly' do
15
+ it 'should return non-zero status on bad option' do
16
+ `ruby -Ilib bin/reek --no-such-option`
17
+ $?.exitstatus.should == 1
18
+ end
19
+
20
+ it 'should not complain about missing file' do
21
+ `ruby -Ilib bin/reek nosuchfile.rb 2>/dev/null`
22
+ $?.exitstatus.should == 0
23
+ end
24
+
25
+ it 'should return non-zero status on missing argument' do
26
+ `ruby -Ilib bin/reek -s 2>/dev/null`
27
+ $?.exitstatus.should == 1
28
+ end
29
+
30
+ it 'should not complain when no source given' do
31
+ `ruby -Ilib bin/reek 2>/dev/null`
32
+ $?.exitstatus.should == 0
33
+ end
34
+ end
35
+
36
+ describe 'exit status', 'when reek is used correctly' do
37
+ it 'should return non-zero status when smells are reported' do
38
+ `ruby -Ilib bin/reek "def x() 3; end"`
39
+ $?.exitstatus.should == 2
40
+ end
41
+
42
+ it 'should return zero status with no smells' do
43
+ `ruby -Ilib bin/reek "def simple() @fred = 3 end"`
44
+ $?.exitstatus.should == 0
45
+ end
46
+ end
47
+
48
+ describe 'report format', 'with no sources' do
49
+ it 'should output nothing' do
50
+ `ruby -Ilib bin/reek`.should be_empty
51
+ end
52
+ end
53
+
54
+ describe 'report format', 'with one source' do
55
+ it 'should output nothing with empty source' do
56
+ `ruby -Ilib bin/reek ""`.should be_empty
57
+ end
58
+
59
+ it 'should output nothing when no smells' do
60
+ `ruby -Ilib bin/reek "def simple() @fred = 3; end"`.should be_empty
61
+ end
62
+
63
+ it 'should not adorn the list of warnings' do
64
+ report = `ruby -Ilib bin/reek "def y() @x = 3; end"`
65
+ report.split(/\n/).length.should == 1
66
+ report.should_not match(/\n\n/)
67
+ end
68
+ end
data/tasks/reek.rake ADDED
@@ -0,0 +1,7 @@
1
+ require 'reek/rake_task'
2
+
3
+ Reek::RakeTask.new do |t|
4
+ t.fail_on_error = true
5
+ t.verbose = false
6
+ # t.sort = 'smell'
7
+ end
data/website/index.html CHANGED
@@ -33,7 +33,7 @@
33
33
  <h1>reek</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.2.2</a>
36
+ <a href="http://rubyforge.org/projects/reek" class="numbers">0.3.0</a>
37
37
  </div>
38
38
  <p>Reek is a tool that examines Ruby classes, modules and methods and reports any code smells it finds.</p>
39
39
  <h2>Installing</h2>
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.2.3
4
+ version: 0.3.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-22 00:00:00 +01:00
12
+ date: 2008-11-02 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -18,9 +18,19 @@ dependencies:
18
18
  version_requirement:
19
19
  version_requirements: !ruby/object:Gem::Requirement
20
20
  requirements:
21
- - - ">="
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: "3.0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: sexp_processor
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
22
32
  - !ruby/object:Gem::Version
23
- version: 2.2.0
33
+ version: "3.0"
24
34
  version:
25
35
  - !ruby/object:Gem::Dependency
26
36
  name: hoe
@@ -30,9 +40,9 @@ dependencies:
30
40
  requirements:
31
41
  - - ">="
32
42
  - !ruby/object:Gem::Version
33
- version: 1.7.0
43
+ version: 1.8.2
34
44
  version:
35
- description: detects smells in your Ruby code
45
+ description: detects smells in Ruby code
36
46
  email:
37
47
  - kevin@rutherford-software.com
38
48
  executables:
@@ -56,12 +66,14 @@ files:
56
66
  - lib/reek/object_refs.rb
57
67
  - lib/reek/options.rb
58
68
  - lib/reek/printer.rb
69
+ - lib/reek/rake_task.rb
59
70
  - lib/reek/report.rb
60
71
  - lib/reek/smells.rb
61
72
  - lib/reek/version.rb
62
73
  - setup.rb
63
74
  - spec/integration_spec.rb
64
75
  - spec/reek/class_checker_spec.rb
76
+ - spec/reek/control_couple_spec.rb
65
77
  - spec/reek/feature_envy_spec.rb
66
78
  - spec/reek/large_class_spec.rb
67
79
  - spec/reek/long_method_spec.rb
@@ -87,8 +99,10 @@ files:
87
99
  - spec/samples/optparse/version.rb
88
100
  - spec/samples/redcloth.rb
89
101
  - spec/samples/redcloth.reek
102
+ - spec/script_spec.rb
90
103
  - spec/spec.opts
91
104
  - spec/spec_helper.rb
105
+ - tasks/reek.rake
92
106
  - tasks/rspec.rake
93
107
  - tasks/samples.rake
94
108
  - website/index.html
@@ -122,6 +136,6 @@ rubyforge_project: reek
122
136
  rubygems_version: 1.2.0
123
137
  signing_key:
124
138
  specification_version: 2
125
- summary: detects smells in your Ruby code
139
+ summary: detects smells in Ruby code
126
140
  test_files: []
127
141