reek 1.2.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/History.txt +4 -0
  2. data/Rakefile +0 -1
  3. data/config/defaults.reek +4 -6
  4. data/features/masking_smells.feature +9 -9
  5. data/features/options.feature +2 -2
  6. data/features/profile.feature +34 -0
  7. data/features/rake_task.feature +74 -0
  8. data/features/reports.feature +1 -1
  9. data/features/samples.feature +4 -4
  10. data/features/stdin.feature +1 -1
  11. data/features/step_definitions/reek_steps.rb +11 -7
  12. data/features/support/env.rb +26 -18
  13. data/lib/reek.rb +1 -1
  14. data/lib/reek/adapters/application.rb +9 -2
  15. data/lib/reek/adapters/command_line.rb +2 -2
  16. data/lib/reek/adapters/source.rb +4 -1
  17. data/lib/reek/adapters/spec.rb +1 -3
  18. data/lib/reek/block_context.rb +14 -8
  19. data/lib/reek/class_context.rb +6 -66
  20. data/lib/reek/code_context.rb +10 -0
  21. data/lib/reek/code_parser.rb +25 -53
  22. data/lib/reek/configuration.rb +12 -6
  23. data/lib/reek/if_context.rb +2 -3
  24. data/lib/reek/method_context.rb +3 -12
  25. data/lib/reek/module_context.rb +30 -22
  26. data/lib/reek/name.rb +2 -0
  27. data/lib/reek/object_refs.rb +0 -3
  28. data/lib/reek/sexp_formatter.rb +0 -2
  29. data/lib/reek/smells/class_variable.rb +17 -4
  30. data/lib/reek/smells/control_couple.rb +3 -10
  31. data/lib/reek/smells/data_clump.rb +10 -10
  32. data/lib/reek/smells/feature_envy.rb +1 -8
  33. data/lib/reek/smells/large_class.rb +3 -3
  34. data/lib/reek/smells/simulated_polymorphism.rb +17 -3
  35. data/lib/reek/smells/smell_detector.rb +11 -2
  36. data/lib/reek/smells/utility_function.rb +1 -1
  37. data/lib/reek/sniffer.rb +0 -8
  38. data/lib/reek/stop_context.rb +1 -1
  39. data/lib/reek/tree_dresser.rb +74 -0
  40. data/reek.gemspec +3 -3
  41. data/spec/reek/block_context_spec.rb +6 -6
  42. data/spec/reek/class_context_spec.rb +2 -23
  43. data/spec/reek/code_context_spec.rb +149 -67
  44. data/spec/reek/code_parser_spec.rb +0 -102
  45. data/spec/reek/method_context_spec.rb +4 -4
  46. data/spec/reek/singleton_method_context_spec.rb +1 -1
  47. data/spec/reek/smells/attribute_spec.rb +1 -1
  48. data/spec/reek/smells/class_variable_spec.rb +96 -7
  49. data/spec/reek/smells/control_couple_spec.rb +1 -1
  50. data/spec/reek/smells/data_clump_spec.rb +31 -13
  51. data/spec/reek/smells/feature_envy_spec.rb +1 -1
  52. data/spec/reek/smells/large_class_spec.rb +32 -18
  53. data/spec/reek/smells/simulated_polymorphism_spec.rb +66 -18
  54. data/spec/reek/sniffer_spec.rb +1 -0
  55. data/spec/samples/not_quite_masked/dirty.rb +2 -0
  56. data/spec/spec_helper.rb +1 -1
  57. data/tasks/reek.rake +1 -1
  58. metadata +5 -3
  59. data/lib/reek/exceptions.reek +0 -20
data/History.txt CHANGED
@@ -2,7 +2,11 @@
2
2
 
3
3
  === Minor Changes
4
4
  * New smell: Attribute (disabled by default)
5
+ * Expanded DataClump to check modules (#9)
6
+ * Fixed LargeClass to ignore inner classes and modules
7
+ * Fixed LargeClass to ignore singleton methods
5
8
  * Removed support for MyClass.should_not reek due to ParseTree EOL
9
+ * Removed internal requiring of 'rubygems'
6
10
 
7
11
  == 1.2.1 (2009-10-02)
8
12
 
data/Rakefile CHANGED
@@ -1,4 +1,3 @@
1
- require 'rake'
2
1
  require 'rake/clean'
3
2
 
4
3
  $:.unshift File.dirname(__FILE__) + '/lib'
data/config/defaults.reek CHANGED
@@ -14,12 +14,11 @@ LongParameterList:
14
14
  initialize:
15
15
  max_params: 5
16
16
  FeatureEnvy:
17
- exclude:
18
- - initialize
19
- enabled: true
20
- ClassVariable:
21
17
  exclude: &id001 []
22
18
 
19
+ enabled: true
20
+ ClassVariable:
21
+ exclude: *id001
23
22
  enabled: true
24
23
  UncommunicativeName:
25
24
  accept:
@@ -64,8 +63,7 @@ DataClump:
64
63
  max_copies: 2
65
64
  min_clump_size: 2
66
65
  ControlCouple:
67
- exclude:
68
- - initialize
66
+ exclude: *id001
69
67
  enabled: true
70
68
  LongYieldList:
71
69
  max_params: 3
@@ -6,7 +6,7 @@ Feature: Masking smells using config files
6
6
 
7
7
  Scenario: empty config file is ignored
8
8
  When I run reek spec/samples/empty_config_file/dirty.rb
9
- Then it fails with exit status 2
9
+ Then the exit status indicates smells
10
10
  And it reports:
11
11
  """
12
12
  spec/samples/empty_config_file/dirty.rb -- 6 warnings:
@@ -21,17 +21,17 @@ Feature: Masking smells using config files
21
21
 
22
22
  Scenario: corrupt config file prevents normal output
23
23
  When I run reek spec/samples/corrupt_config_file/dirty.rb
24
- Then it fails with exit status 1
24
+ Then the exit status indicates an error
25
25
  And it reports the error 'Error: Invalid configuration file "corrupt.reek" -- not a Hash'
26
26
 
27
27
  Scenario: missing source file is an error
28
28
  When I run reek no_such_file.rb
29
- Then it fails with exit status 1
29
+ Then the exit status indicates an error
30
30
  And it reports the error "Error: No such file or directory - no_such_file.rb"
31
31
 
32
32
  Scenario: switch off one smell
33
33
  When I run reek spec/samples/masked/dirty.rb
34
- Then it fails with exit status 2
34
+ Then the exit status indicates smells
35
35
  And it reports:
36
36
  """
37
37
  spec/samples/masked/dirty.rb -- 3 warnings (+3 masked):
@@ -43,7 +43,7 @@ Feature: Masking smells using config files
43
43
 
44
44
  Scenario: switch off one smell but show all in the report
45
45
  When I run reek --show-all spec/samples/masked/dirty.rb
46
- Then it fails with exit status 2
46
+ Then the exit status indicates smells
47
47
  And it reports:
48
48
  """
49
49
  spec/samples/masked/dirty.rb -- 3 warnings (+3 masked):
@@ -58,7 +58,7 @@ Feature: Masking smells using config files
58
58
 
59
59
  Scenario: switch off one smell and hide them in the report
60
60
  When I run reek --no-show-all spec/samples/masked/dirty.rb
61
- Then it fails with exit status 2
61
+ Then the exit status indicates smells
62
62
  And it reports:
63
63
  """
64
64
  spec/samples/masked/dirty.rb -- 3 warnings (+3 masked):
@@ -70,7 +70,7 @@ Feature: Masking smells using config files
70
70
 
71
71
  Scenario: non-masked smells are only counted once
72
72
  When I run reek spec/samples/not_quite_masked/dirty.rb
73
- Then it fails with exit status 2
73
+ Then the exit status indicates smells
74
74
  And it reports:
75
75
  """
76
76
  spec/samples/not_quite_masked/dirty.rb -- 5 warnings (+1 masked):
@@ -85,7 +85,7 @@ Feature: Masking smells using config files
85
85
  @overrides
86
86
  Scenario: lower overrides upper
87
87
  When I run reek spec/samples/overrides
88
- Then it fails with exit status 2
88
+ Then the exit status indicates smells
89
89
  And it reports:
90
90
  """
91
91
  spec/samples/overrides/masked/dirty.rb -- 2 warnings (+4 masked):
@@ -97,7 +97,7 @@ Feature: Masking smells using config files
97
97
  @overrides
98
98
  Scenario: all show up masked even when overridden
99
99
  When I run reek --show-all spec/samples/overrides
100
- Then it fails with exit status 2
100
+ Then the exit status indicates smells
101
101
  And it reports:
102
102
  """
103
103
  spec/samples/overrides/masked/dirty.rb -- 2 warnings (+4 masked):
@@ -6,12 +6,12 @@ Feature: Reek can be controlled using command-line options
6
6
 
7
7
  Scenario: return non-zero status on bad option
8
8
  When I run reek --no-such-option
9
- Then it fails with exit status 1
9
+ Then the exit status indicates an error
10
10
  And it reports the error "Error: invalid option: --no-such-option"
11
11
 
12
12
  Scenario: return non-zero status on missing argument
13
13
  When I run reek -f
14
- Then it fails with exit status 1
14
+ Then the exit status indicates an error
15
15
  And it reports the error "Error: missing argument: -f"
16
16
 
17
17
  Scenario: display the current version number
@@ -0,0 +1,34 @@
1
+ @profile
2
+ Feature: Reek's configuration can be based on any number of canned profiles
3
+ The starting point for configuring the smell detectors can be
4
+ selected from a list of supplied config files.
5
+
6
+ # Scenario: XP profile reveals Attribute smells
7
+ # When I run reek --profile xp spec/samples/not_quite_masked/dirty.rb
8
+ # Then the exit status indicates smells
9
+ # And it reports:
10
+ # """
11
+ # spec/samples/not_quite_masked/dirty.rb -- 5 warnings (+2 masked):
12
+ # Dirty declares the attribute property (Attribute)
13
+ # Dirty has the variable name '@s' (Uncommunicative Name)
14
+ # Dirty#a calls @s.title twice (Duplication)
15
+ # Dirty#a calls puts(@s.title) twice (Duplication)
16
+ # Dirty#a has the name 'a' (Uncommunicative Name)
17
+ #
18
+ # """
19
+ #
20
+ # Scenario: XP profile works with unmasked smells
21
+ # When I run reek --show-all --profile xp spec/samples/not_quite_masked/dirty.rb
22
+ # Then the exit status indicates smells
23
+ # And it reports:
24
+ # """
25
+ # spec/samples/not_quite_masked/dirty.rb -- 5 warnings (+2 masked):
26
+ # Dirty declares the attribute property (Attribute)
27
+ # Dirty has the variable name '@s' (Uncommunicative Name)
28
+ # Dirty#a calls @s.title twice (Duplication)
29
+ # Dirty#a calls puts(@s.title) twice (Duplication)
30
+ # Dirty#a has the name 'a' (Uncommunicative Name)
31
+ # (masked) Dirty#a/block has the variable name 'x' (Uncommunicative Name)
32
+ # (masked) Dirty#a/block/block is nested (Nested Iterators)
33
+ #
34
+ # """
@@ -0,0 +1,74 @@
1
+ @rake
2
+ Feature: Reek can be driven through its RakeTask
3
+ Reek provides an easy way to integrate its use into Rakefiles,
4
+ via the RakeTask class. These scenarios test its various options.
5
+
6
+ Scenario: source_files points at the desired files
7
+ When I run rake reek with:
8
+ """
9
+ Reek::RakeTask.new do |t|
10
+ t.source_files = 'spec/samples/masked/dirty.rb'
11
+ end
12
+ """
13
+ Then the exit status indicates an error
14
+ And it reports:
15
+ """
16
+ spec/samples/masked/dirty.rb -- 3 warnings (+3 masked):
17
+ Dirty#a calls @s.title twice (Duplication)
18
+ Dirty#a calls puts(@s.title) twice (Duplication)
19
+ Dirty#a/block/block is nested (Nested Iterators)
20
+ """
21
+
22
+ Scenario: name changes the task name
23
+ When I run rake silky with:
24
+ """
25
+ Reek::RakeTask.new('silky') do |t|
26
+ t.source_files = 'spec/samples/masked/dirty.rb'
27
+ end
28
+ """
29
+ Then the exit status indicates an error
30
+ And it reports:
31
+ """
32
+ spec/samples/masked/dirty.rb -- 3 warnings (+3 masked):
33
+ Dirty#a calls @s.title twice (Duplication)
34
+ Dirty#a calls puts(@s.title) twice (Duplication)
35
+ Dirty#a/block/block is nested (Nested Iterators)
36
+ """
37
+
38
+ Scenario: verbose prints the reek command
39
+ When I run rake reek with:
40
+ """
41
+ Reek::RakeTask.new do |t|
42
+ t.source_files = 'spec/samples/masked/dirty.rb'
43
+ t.verbose = true
44
+ end
45
+ """
46
+ Then the exit status indicates an error
47
+ And it reports:
48
+ """
49
+ /usr/bin/ruby1.8 -I"/home/kevin/Working/git/reek/lib" "/home/kevin/Working/git/reek/bin/reek" "spec/samples/masked/dirty.rb"
50
+ spec/samples/masked/dirty.rb -- 3 warnings (+3 masked):
51
+ Dirty#a calls @s.title twice (Duplication)
52
+ Dirty#a calls puts(@s.title) twice (Duplication)
53
+ Dirty#a/block/block is nested (Nested Iterators)
54
+ """
55
+
56
+ Scenario: fail_on_error can hide the error status
57
+ When I run rake reek with:
58
+ """
59
+ Reek::RakeTask.new do |t|
60
+ t.fail_on_error = false
61
+ t.source_files = 'spec/samples/empty_config_file/dirty.rb'
62
+ end
63
+ """
64
+ Then it succeeds
65
+ And it reports:
66
+ """
67
+ spec/samples/empty_config_file/dirty.rb -- 6 warnings:
68
+ Dirty has the variable name '@s' (Uncommunicative Name)
69
+ Dirty#a calls @s.title twice (Duplication)
70
+ Dirty#a calls puts(@s.title) twice (Duplication)
71
+ Dirty#a has the name 'a' (Uncommunicative Name)
72
+ Dirty#a/block has the variable name 'x' (Uncommunicative Name)
73
+ Dirty#a/block/block is nested (Nested Iterators)
74
+ """
@@ -6,7 +6,7 @@ Feature: Correctly formatted reports
6
6
 
7
7
  Scenario Outline: two reports run together with indented smells
8
8
  When I run reek <args>
9
- Then it fails with exit status 2
9
+ Then the exit status indicates smells
10
10
  And it reports:
11
11
  """
12
12
  spec/samples/two_smelly_files/dirty_one.rb -- 6 warnings:
@@ -6,7 +6,7 @@ Feature: Basic smell detection
6
6
 
7
7
  Scenario: Correct smells from inline.rb
8
8
  When I run reek spec/samples/inline.rb
9
- Then it fails with exit status 2
9
+ Then the exit status indicates smells
10
10
  And it reports:
11
11
  """
12
12
  spec/samples/inline.rb -- 39 warnings (+1 masked):
@@ -54,11 +54,11 @@ Feature: Basic smell detection
54
54
 
55
55
  Scenario: Correct smells from optparse.rb
56
56
  When I run reek spec/samples/optparse.rb
57
- Then it fails with exit status 2
57
+ Then the exit status indicates smells
58
58
  And it reports:
59
59
  """
60
60
  spec/samples/optparse.rb -- 121 warnings:
61
- OptionParser has at least 59 methods (Large Class)
61
+ OptionParser has at least 42 methods (Large Class)
62
62
  OptionParser tests ((argv.size == 1) and Array.===(argv[0])) at least 3 times (Simulated Polymorphism)
63
63
  OptionParser tests a at least 7 times (Simulated Polymorphism)
64
64
  OptionParser tests default_pattern at least 7 times (Simulated Polymorphism)
@@ -184,7 +184,7 @@ Feature: Basic smell detection
184
184
 
185
185
  Scenario: Correct smells from redcloth.rb
186
186
  When I run reek spec/samples/redcloth.rb
187
- Then it fails with exit status 2
187
+ Then the exit status indicates smells
188
188
  And it reports:
189
189
  """
190
190
  spec/samples/redcloth.rb -- 95 warnings:
@@ -33,7 +33,7 @@ Feature: Reek reads from $stdin when no files are given
33
33
 
34
34
  Scenario: return non-zero status when there are smells
35
35
  When I pass "class Turn; def y() @x = 3; end end" to reek
36
- Then it fails with exit status 2
36
+ Then the exit status indicates smells
37
37
  And it reports:
38
38
  """
39
39
  $stdin -- 2 warnings:
@@ -1,13 +1,13 @@
1
1
  When /^I run reek (.*)$/ do |args|
2
- run args
2
+ reek(args)
3
3
  end
4
4
 
5
5
  When /^I pass "([^\"]*)" to reek *(.*)$/ do |stdin, args|
6
- run_with_pipe(stdin, args)
6
+ reek_with_pipe(stdin, args)
7
7
  end
8
8
 
9
- When /^I run rake reek$/ do
10
- rake
9
+ When /^I run rake (\w*) with:$/ do |name, task_def|
10
+ rake(name, task_def)
11
11
  end
12
12
 
13
13
  Then /^stdout equals "([^\"]*)"$/ do |report|
@@ -15,11 +15,15 @@ Then /^stdout equals "([^\"]*)"$/ do |report|
15
15
  end
16
16
 
17
17
  Then /^it succeeds$/ do
18
- @last_exit_status.should == 0
18
+ @last_exit_status.should == Reek::EXIT_STATUS[:success]
19
19
  end
20
20
 
21
- Then /^it fails with exit status (\d+)$/ do |status|
22
- @last_exit_status.should == status.to_i
21
+ Then /^the exit status indicates an error$/ do
22
+ @last_exit_status.should == Reek::EXIT_STATUS[:error]
23
+ end
24
+
25
+ Then /^the exit status indicates smells$/ do
26
+ @last_exit_status.should == Reek::EXIT_STATUS[:smells]
23
27
  end
24
28
 
25
29
  Then /^it reports:$/ do |report|
@@ -5,34 +5,42 @@ require 'tempfile'
5
5
  require 'spec/expectations'
6
6
  require 'fileutils'
7
7
  require 'reek'
8
+ require 'reek/adapters/application'
8
9
 
9
- class CucumberWorld
10
-
11
- def run(args)
12
- stderr_file = Tempfile.new('cucumber')
10
+ class ReekWorld
11
+ def run(cmd)
12
+ stderr_file = Tempfile.new('reek-world')
13
13
  stderr_file.close
14
- @last_stdout = `ruby -Ilib bin/reek #{args} 2> #{stderr_file.path}`
14
+ @last_stdout = `#{cmd} 2> #{stderr_file.path}`
15
15
  @last_exit_status = $?.exitstatus
16
16
  @last_stderr = IO.read(stderr_file.path)
17
17
  end
18
18
 
19
- def run_with_pipe(stdin, args)
20
- stderr_file = Tempfile.new('cucumber')
21
- stderr_file.close
22
- @last_stdout = `echo \"#{stdin}\" | ruby -Ilib bin/reek #{args} 2> #{stderr_file.path}`
23
- @last_exit_status = $?.exitstatus
24
- @last_stderr = IO.read(stderr_file.path)
19
+ def reek(args)
20
+ run("ruby -Ilib -rubygems bin/reek #{args}")
25
21
  end
26
22
 
27
- def rake
28
- stderr_file = Tempfile.new('cucumber')
29
- stderr_file.close
30
- @last_stdout = `rake reek 2> #{stderr_file.path}`
31
- @last_exit_status = $?.exitstatus
32
- @last_stderr = IO.read(stderr_file.path)
23
+ def reek_with_pipe(stdin, args)
24
+ run("echo \"#{stdin}\" | ruby -Ilib -rubygems bin/reek #{args}")
25
+ end
26
+
27
+ def rake(name, task_def)
28
+ header = <<EOS
29
+ $:.unshift('lib')
30
+ require 'reek/adapters/rake_task'
31
+
32
+ EOS
33
+ rakefile = Tempfile.new('rake_task', '.')
34
+ rakefile.puts(header + task_def)
35
+ rakefile.close
36
+ run("RUBYOPT=rubygems rake -f #{rakefile.path} #{name}")
37
+ lines = @last_stdout.split("\n")
38
+ if lines.length > 0 and lines[0] =~ /^\(/
39
+ @last_stdout = lines[1..-1].join("\n")
40
+ end
33
41
  end
34
42
  end
35
43
 
36
44
  World do
37
- CucumberWorld.new
45
+ ReekWorld.new
38
46
  end
data/lib/reek.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
2
 
3
3
  module Reek # :doc:
4
- VERSION = '1.2.2'
4
+ VERSION = '1.2.3'
5
5
  end
@@ -3,6 +3,13 @@ require 'reek/adapters/source'
3
3
  require 'reek/adapters/core_extras'
4
4
 
5
5
  module Reek
6
+
7
+ EXIT_STATUS = {
8
+ :success => 0,
9
+ :error => 1,
10
+ :smells => 2
11
+ }
12
+
6
13
  #
7
14
  # Represents an instance of a Reek application.
8
15
  # This is the entry point for all invocations of Reek from the
@@ -27,7 +34,7 @@ module Reek
27
34
  def reek
28
35
  examine_sources
29
36
  puts @options.create_report(@sniffer.sniffers).report
30
- return @sniffer.smelly? ? 2 : 0
37
+ return EXIT_STATUS[@sniffer.smelly? ? :smells : :success]
31
38
  end
32
39
 
33
40
  def execute
@@ -37,7 +44,7 @@ module Reek
37
44
  return ex.status
38
45
  rescue Exception => error
39
46
  $stderr.puts "Error: #{error}"
40
- return 1
47
+ return EXIT_STATUS[:error]
41
48
  end
42
49
  end
43
50
  end
@@ -45,11 +45,11 @@ EOB
45
45
 
46
46
  @parser.on("-h", "--help", "Show this message") do
47
47
  puts @parser
48
- exit(0)
48
+ exit(EXIT_STATUS[:success])
49
49
  end
50
50
  @parser.on("-v", "--version", "Show version") do
51
51
  puts "#{@parser.program_name} #{Reek::VERSION}"
52
- exit(0)
52
+ exit(EXIT_STATUS[:success])
53
53
  end
54
54
 
55
55
  @parser.separator "\nReport formatting:"