reek 1.2.2 → 1.2.3

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.
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:"