reek 0.2.3 → 0.3.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,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