reek 1.2.1 → 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 (68) hide show
  1. data/History.txt +10 -0
  2. data/Rakefile +0 -1
  3. data/config/defaults.reek +8 -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/adapters/application.rb +9 -2
  14. data/lib/reek/adapters/command_line.rb +2 -2
  15. data/lib/reek/adapters/core_extras.rb +0 -8
  16. data/lib/reek/adapters/source.rb +4 -1
  17. data/lib/reek/adapters/spec.rb +1 -4
  18. data/lib/reek/block_context.rb +14 -8
  19. data/lib/reek/class_context.rb +6 -55
  20. data/lib/reek/code_context.rb +10 -0
  21. data/lib/reek/code_parser.rb +26 -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 +8 -12
  25. data/lib/reek/module_context.rb +35 -16
  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/attribute.rb +48 -0
  30. data/lib/reek/smells/class_variable.rb +17 -4
  31. data/lib/reek/smells/control_couple.rb +3 -10
  32. data/lib/reek/smells/data_clump.rb +10 -10
  33. data/lib/reek/smells/feature_envy.rb +1 -8
  34. data/lib/reek/smells/large_class.rb +3 -3
  35. data/lib/reek/smells/simulated_polymorphism.rb +17 -3
  36. data/lib/reek/smells/smell_detector.rb +11 -2
  37. data/lib/reek/smells/utility_function.rb +1 -1
  38. data/lib/reek/sniffer.rb +2 -8
  39. data/lib/reek/stop_context.rb +1 -1
  40. data/lib/reek/tree_dresser.rb +74 -0
  41. data/lib/reek.rb +1 -1
  42. data/reek.gemspec +3 -3
  43. data/spec/reek/adapters/should_reek_of_spec.rb +7 -1
  44. data/spec/reek/block_context_spec.rb +6 -6
  45. data/spec/reek/class_context_spec.rb +2 -23
  46. data/spec/reek/code_context_spec.rb +149 -67
  47. data/spec/reek/code_parser_spec.rb +35 -51
  48. data/spec/reek/method_context_spec.rb +4 -4
  49. data/spec/reek/singleton_method_context_spec.rb +1 -1
  50. data/spec/reek/smells/attribute_spec.rb +26 -0
  51. data/spec/reek/smells/behaves_like_variable_detector.rb +39 -0
  52. data/spec/reek/smells/class_variable_spec.rb +77 -43
  53. data/spec/reek/smells/control_couple_spec.rb +1 -1
  54. data/spec/reek/smells/data_clump_spec.rb +31 -13
  55. data/spec/reek/smells/feature_envy_spec.rb +1 -1
  56. data/spec/reek/smells/large_class_spec.rb +32 -69
  57. data/spec/reek/smells/long_parameter_list_spec.rb +0 -12
  58. data/spec/reek/smells/simulated_polymorphism_spec.rb +66 -18
  59. data/spec/reek/smells/utility_function_spec.rb +0 -21
  60. data/spec/reek/sniffer_spec.rb +1 -0
  61. data/spec/samples/not_quite_masked/dirty.rb +2 -0
  62. data/spec/spec_helper.rb +1 -1
  63. data/tasks/reek.rake +1 -1
  64. data/tasks/test.rake +3 -4
  65. metadata +8 -5
  66. data/lib/reek/adapters/object_source.rb +0 -52
  67. data/lib/reek/exceptions.reek +0 -20
  68. data/spec/quality/reek_source_spec.rb +0 -15
@@ -10,7 +10,7 @@ describe SingletonMethodContext, 'outer_name' do
10
10
 
11
11
  it "should report full context" do
12
12
  element = StopContext.new
13
- element = ModuleContext.new(element, Name.new(:mod))
13
+ element = ModuleContext.new(element, Name.new(:mod), s(:module, :mod, nil))
14
14
  element = SingletonMethodContext.new(element, s(:defs, s(:call, nil, :a, s(:arglist)), :b, s(:args)))
15
15
  element.outer_name.should match(/mod::a\.b/)
16
16
  end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
+
3
+ require 'reek/smells/attribute'
4
+ require 'reek/class_context'
5
+
6
+ require 'spec/reek/smells/behaves_like_variable_detector'
7
+
8
+ include Reek
9
+ include Reek::Smells
10
+
11
+ describe Attribute do
12
+ before :each do
13
+ @detector = Attribute.new
14
+ @record_variable = :record_attribute
15
+ end
16
+
17
+ [ClassContext, ModuleContext].each do |klass|
18
+ context "in a #{klass}" do
19
+ before :each do
20
+ @ctx = klass.create(StopContext.new, s(:null, :Fred))
21
+ end
22
+
23
+ it_should_behave_like 'a variable detector'
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,39 @@
1
+ shared_examples_for 'a variable detector' do
2
+ context 'with no variables' do
3
+ it "doesn't record a smell" do
4
+ @detector.examine_context(@ctx)
5
+ @detector.num_smells.should == 0
6
+ end
7
+ end
8
+
9
+ context 'with one variable encountered twice' do
10
+ before :each do
11
+ @ctx.send(@record_variable, :something)
12
+ @ctx.send(@record_variable, :something)
13
+ @detector.examine_context(@ctx)
14
+ end
15
+
16
+ it 'records only one smell' do
17
+ @detector.num_smells.should == 1
18
+ end
19
+ it 'mentions the variable name in the report' do
20
+ @detector.should have_smell([/something/])
21
+ end
22
+ end
23
+
24
+ context 'with two variables' do
25
+ before :each do
26
+ @ctx.send(@record_variable, :something)
27
+ @ctx.send(@record_variable, :something_else)
28
+ @detector.examine_context(@ctx)
29
+ end
30
+
31
+ it 'records both smells' do
32
+ @detector.num_smells.should == 2
33
+ end
34
+ it 'mentions both variable names in the report' do
35
+ @detector.should have_smell([/something/])
36
+ @detector.should have_smell([/something_else/])
37
+ end
38
+ end
39
+ end
@@ -7,75 +7,109 @@ include Reek
7
7
  include Reek::Smells
8
8
 
9
9
  describe ClassVariable do
10
- shared_examples_for 'a class variable container' do
11
- context 'no class variables' do
12
- it "doesn't record a smell" do
13
- @detector.examine_context(@ctx)
14
- @detector.num_smells.should == 0
10
+ before :each do
11
+ @detector = ClassVariable.new
12
+ end
13
+
14
+ context 'with no class variables' do
15
+ it 'records nothing in the class' do
16
+ ctx = ClassContext.from_s('class Fred; end')
17
+ @detector.class_variables_in(ctx).should be_empty
18
+ end
19
+ it 'records nothing in the module' do
20
+ ctx = ModuleContext.from_s('module Fred; end')
21
+ @detector.class_variables_in(ctx).should be_empty
22
+ end
23
+ end
24
+
25
+ context 'with one class variable' do
26
+ shared_examples_for 'one variable found' do
27
+ it 'records the class variable' do
28
+ @detector.class_variables_in(@ctx).should include(:@@tools)
29
+ end
30
+ it 'records only that class variable' do
31
+ @detector.class_variables_in(@ctx).length.should == 1
15
32
  end
16
33
  end
17
34
 
18
- context 'one class variable' do
35
+ context 'declared in a class' do
19
36
  before :each do
20
- @ctx.record_class_variable(:@@cvar)
21
- @detector.examine_context(@ctx)
37
+ @ctx = ClassContext.from_s('class Fred; @@tools = {}; end')
22
38
  end
23
39
 
24
- it 'records a smell' do
25
- @detector.num_smells.should == 1
26
- end
27
- it 'mentions the variable name in the report' do
28
- @detector.should have_smell([/@@cvar/])
29
- end
40
+ it_should_behave_like 'one variable found'
30
41
  end
31
42
 
32
- context 'one class variable encountered twice' do
43
+ context 'used in a class' do
33
44
  before :each do
34
- @ctx.record_class_variable(:@@cvar)
35
- @ctx.record_class_variable(:@@cvar)
36
- @detector.examine_context(@ctx)
45
+ @ctx = ClassContext.from_s('class Fred; def jim() @@tools = {}; end; end')
37
46
  end
38
47
 
39
- it 'records only one smell' do
40
- @detector.num_smells.should == 1
48
+ it_should_behave_like 'one variable found'
49
+ end
50
+
51
+ context 'indexed in a class' do
52
+ before :each do
53
+ @ctx = ClassContext.from_s('class Fred; def jim() @@tools[mash] = {}; end; end')
41
54
  end
42
- it 'mentions the variable name in the report' do
43
- @detector.should have_smell([/@@cvar/])
55
+
56
+ it_should_behave_like 'one variable found'
57
+ end
58
+
59
+ context 'declared and used in a class' do
60
+ before :each do
61
+ @ctx = ClassContext.from_s('class Fred; @@tools = {}; def jim() @@tools = {}; end; end')
44
62
  end
63
+
64
+ it_should_behave_like 'one variable found'
45
65
  end
46
66
 
47
- context 'two class variables' do
67
+ context 'used twice in a class' do
48
68
  before :each do
49
- @ctx.record_class_variable(:@@cvar)
50
- @ctx.record_class_variable(:@@another)
51
- @detector.examine_context(@ctx)
69
+ @ctx = ClassContext.from_s('class Fred; def jeff() @@tools = {}; end; def jim() @@tools = {}; end; end')
52
70
  end
53
71
 
54
- it 'records a smell' do
55
- @detector.num_smells.should == 2
72
+ it_should_behave_like 'one variable found'
73
+ end
74
+
75
+ context 'declared in a module' do
76
+ before :each do
77
+ @ctx = ClassContext.from_s('module Fred; @@tools = {}; end')
56
78
  end
57
- it 'mentions both variable names in the report' do
58
- @detector.should have_smell([/@@cvar/])
59
- @detector.should have_smell([/@@another/])
79
+
80
+ it_should_behave_like 'one variable found'
81
+ end
82
+
83
+ context 'used in a module' do
84
+ before :each do
85
+ @ctx = ClassContext.from_s('module Fred; def jim() @@tools = {}; end; end')
60
86
  end
87
+
88
+ it_should_behave_like 'one variable found'
61
89
  end
62
- end
63
90
 
64
- context 'in a class' do
65
- before :each do
66
- @ctx = ClassContext.create(StopContext.new, "Fred")
67
- @detector = ClassVariable.new
91
+ context 'indexed in a module' do
92
+ before :each do
93
+ @ctx = ClassContext.from_s('module Fred; def jim() @@tools[mash] = {}; end; end')
94
+ end
95
+
96
+ it_should_behave_like 'one variable found'
68
97
  end
69
98
 
70
- it_should_behave_like 'a class variable container'
71
- end
99
+ context 'declared and used in a module' do
100
+ before :each do
101
+ @ctx = ClassContext.from_s('module Fred; @@tools = {}; def jim() @@tools = {}; end; end')
102
+ end
72
103
 
73
- context 'in a module' do
74
- before :each do
75
- @ctx = ModuleContext.create(StopContext.new, "Fred")
76
- @detector = ClassVariable.new
104
+ it_should_behave_like 'one variable found'
77
105
  end
78
106
 
79
- it_should_behave_like 'a class variable container'
107
+ context 'used twice in a module' do
108
+ before :each do
109
+ @ctx = ClassContext.from_s('module Fred; def jeff() @@tools = {}; end; def jim() @@tools = {}; end; end')
110
+ end
111
+
112
+ it_should_behave_like 'one variable found'
113
+ end
80
114
  end
81
115
  end
@@ -6,7 +6,7 @@ include Reek::Smells
6
6
 
7
7
  describe ControlCouple do
8
8
  it 'should report a ternary check on a parameter' do
9
- 'def simple(arga) arga ? @ivar : 3 end'.should reek_of(:ControlCouple, /arga/)
9
+ 'def simple(arga) arga ? @ivar : 3 end'.should reek_only_of(:ControlCouple, /arga/)
10
10
  end
11
11
 
12
12
  it 'should not report a ternary check on an ivar' do
@@ -4,10 +4,10 @@ require 'reek/smells/data_clump'
4
4
 
5
5
  include Reek::Smells
6
6
 
7
- describe DataClump do
8
- it 'should not report small parameter sets' do
7
+ shared_examples_for 'a data clump detector' do
8
+ it 'does not report small parameter sets' do
9
9
  src = <<EOS
10
- class Scrunch
10
+ #{@context} Scrunch
11
11
  def first(pa) @field == :sym ? 0 : 3; end
12
12
  def second(pa) @field == :sym; end
13
13
  def third(pa) pa - pb + @fred; end
@@ -17,9 +17,9 @@ EOS
17
17
  src.should_not reek
18
18
  end
19
19
 
20
- it 'should report 3 identical pairs in a class' do
20
+ it 'reports 3 identical pairs in a class' do
21
21
  src = <<EOS
22
- class Scrunch
22
+ #{@context} Scrunch
23
23
  def first(pa, pb) @field == :sym ? 0 : 3; end
24
24
  def second(pa, pb) @field == :sym; end
25
25
  def third(pa, pb) pa - pb + @fred; end
@@ -29,9 +29,9 @@ EOS
29
29
  src.should reek_of(:DataClump, /\[pa, pb\]/, /3 methods/)
30
30
  end
31
31
 
32
- it 'should report 3 swapped pairs in a class' do
32
+ it 'reports 3 swapped pairs in a class' do
33
33
  src = <<EOS
34
- class Scrunch
34
+ #{@context} Scrunch
35
35
  def one(pa, pb) @field == :sym ? 0 : 3; end
36
36
  def two(pb, pa) @field == :sym; end
37
37
  def tri(pa, pb) pa - pb + @fred; end
@@ -41,9 +41,9 @@ EOS
41
41
  src.should reek_of(:DataClump, /\[pa, pb\]/, /3 methods/)
42
42
  end
43
43
 
44
- it 'should report 3 identical parameter sets in a class' do
44
+ it 'reports 3 identical parameter sets in a class' do
45
45
  src = <<EOS
46
- class Scrunch
46
+ #{@context} Scrunch
47
47
  def first(pa, pb, pc) @field == :sym ? 0 : 3; end
48
48
  def second(pa, pb, pc) @field == :sym; end
49
49
  def third(pa, pb, pc) pa - pb + @fred; end
@@ -56,9 +56,9 @@ EOS
56
56
  src.should_not reek_of(:DataClump, /\[pb, pc\]/, /3 methods/)
57
57
  end
58
58
 
59
- it 'should recognise re-ordered identical parameter sets' do
59
+ it 'recognises re-ordered identical parameter sets' do
60
60
  src = <<EOS
61
- class Scrunch
61
+ #{@context} Scrunch
62
62
  def first(pb, pa, pc) @field == :sym ? 0 : 3; end
63
63
  def second(pc, pb, pa) @field == :sym; end
64
64
  def third(pa, pb, pc) pa - pb + @fred; end
@@ -71,9 +71,9 @@ EOS
71
71
  src.should_not reek_of(:DataClump, /\[pb, pc\]/, /3 methods/)
72
72
  end
73
73
 
74
- it 'should count only identical parameter sets' do
74
+ it 'counts only identical parameter sets' do
75
75
  src = <<EOS
76
- class RedCloth
76
+ #{@context} RedCloth
77
77
  def fa(p1, p2, p3, conten) end
78
78
  def fb(p1, p2, p3, conten) end
79
79
  def fc(name, windowW, windowH) end
@@ -82,6 +82,24 @@ EOS
82
82
 
83
83
  src.should_not reek_of(:DataClump)
84
84
  end
85
+ end
86
+
87
+ describe DataClump do
88
+ context 'in a class' do
89
+ before :each do
90
+ @context = 'class'
91
+ end
92
+
93
+ it_should_behave_like 'a data clump detector'
94
+ end
95
+
96
+ context 'in a module' do
97
+ before :each do
98
+ @context = 'module'
99
+ end
100
+
101
+ it_should_behave_like 'a data clump detector'
102
+ end
85
103
 
86
104
  # TODO: include singleton methods in the calcs
87
105
  end
@@ -204,7 +204,7 @@ end
204
204
  describe FeatureEnvy, '#examine' do
205
205
 
206
206
  before :each do
207
- @context = MethodContext.new(StopContext.new, [:defn, :cool])
207
+ @context = MethodContext.new(StopContext.new, s(:defn, :cool))
208
208
  @fe = FeatureEnvy.new
209
209
  end
210
210
 
@@ -8,73 +8,31 @@ require 'reek/smells/large_class'
8
8
  include Reek
9
9
  include Reek::Smells
10
10
 
11
- describe LargeClass, 'checking Class objects' do
12
-
13
- it 'should not report class with 26 methods' do
14
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
15
- class BigOne
16
- 26.times do |i|
17
- define_method "method#{i}x".to_sym do
18
- @melting
19
- end
20
- end
21
- end
22
- BigOne.should_not reek
23
- end
24
-
25
- it 'should not report short class' do
26
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
27
- class ShortClass
28
- def method_a() @var_a; end
29
- def method_b() @var_b; end
30
- def method_c() @var_c; end
31
- def method_d() @var_d; end
32
- def method_e() @var_e; end
33
- def method_f() @var_f; end
34
- end
35
- ShortClass.should_not reek
36
- end
37
-
38
- describe LargeClass, 'counting instance variables' do
39
- it 'should not report class with 10 ivars' do
40
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
41
- class ManyIvars
42
- def meth
43
- @vara = @varb = @varc = @vard = @vare
44
- @varf = @varg = @varh = @vari = @varj
45
- end
46
- end
47
- ManyIvars.should_not reek
48
- end
49
-
50
- it 'ignores class with only a couple of ivars' do
51
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
52
- LargeClass.should_not reek_of(:LargeClass)
53
- end
54
-
55
- it 'ignores fq class with only a couple of ivars' do
56
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
57
- Reek::Smells::LargeClass.should_not reek_of(:LargeClass)
58
- end
59
- end
60
- end
61
-
62
11
  describe LargeClass, 'when exceptions are listed' do
63
-
64
12
  before(:each) do
65
- @ctx = ClassContext.create(StopContext.new, [0, :Humungous])
66
- 30.times { |num| @ctx.record_method("method#{num}") }
13
+ @class_name = 'Humungous'
14
+ src = <<EOS
15
+ class #{@class_name}
16
+ def me01x()3 end;def me02x()3 end;def me03x()3 end;def me04x()3 end;def me05x()3 end
17
+ def me11x()3 end;def me12x()3 end;def me13x()3 end;def me14x()3 end;def me15x()3 end
18
+ def me21x()3 end;def me22x()3 end;def me23x()3 end;def me24x()3 end;def me25x()3 end
19
+ def me31x()3 end;def me32x()3 end;def me33x()3 end;def me34x()3 end;def me35x()3 end
20
+ def me41x()3 end;def me42x()3 end;def me43x()3 end;def me44x()3 end;def me45x()3 end
21
+ def me51x()3 end
22
+ end
23
+ EOS
24
+ @ctx = ClassContext.from_s(src)
67
25
  @config = LargeClass.default_config
68
26
  end
69
27
 
70
28
  it 'should ignore first excepted name' do
71
- @config[LargeClass::EXCLUDE_KEY] = ['Humungous']
29
+ @config[LargeClass::EXCLUDE_KEY] = [@class_name]
72
30
  lc = LargeClass.new(@config)
73
31
  lc.examine(@ctx).should == false
74
32
  end
75
33
 
76
34
  it 'should ignore second excepted name' do
77
- @config[LargeClass::EXCLUDE_KEY] = ['Oversized', 'Humungous']
35
+ @config[LargeClass::EXCLUDE_KEY] = ['Oversized', @class_name]
78
36
  lc = LargeClass.new(@config)
79
37
  lc.examine(@ctx).should == false
80
38
  end
@@ -88,7 +46,7 @@ end
88
46
 
89
47
  describe LargeClass, 'checking source code' do
90
48
 
91
- describe 'counting instance variables' do
49
+ context 'counting instance variables' do
92
50
  it 'should not report empty class' do
93
51
  ClassContext.from_s('class Empty;end').should have(0).variable_names
94
52
  end
@@ -119,18 +77,7 @@ EOS
119
77
  end
120
78
  end
121
79
 
122
- describe 'counting methods' do
123
- it 'should not report empty class' do
124
- ClassContext.from_s('class Empty;end').num_methods.should == 0
125
- end
126
-
127
- it 'should count 1 method' do
128
- ClassContext.from_s('class Empty;def ivars() @aa=@ab; end;end').num_methods.should == 1
129
- end
130
-
131
- it 'should count 2 methods' do
132
- ClassContext.from_s('class Empty;def meth1() @aa=@ab;end;def meth2() @aa=@ab;end;end').num_methods.should == 2
133
- end
80
+ context 'counting methods' do
134
81
 
135
82
  it 'should not report 25 methods' do
136
83
  src = <<EOS
@@ -159,4 +106,20 @@ EOS
159
106
  src.should reek_of(:LargeClass)
160
107
  end
161
108
  end
109
+
110
+ context 'with a nested module' do
111
+ it 'stops at a nested module' do
112
+ src = <<EOS
113
+ class Full
114
+ def me01x()3 end;def me02x()3 end;def me03x()3 end;def me04x()3 end;def me05x()3 end
115
+ def me11x()3 end;def me12x()3 end;def me13x()3 end;def me14x()3 end;def me15x()3 end
116
+ def me21x()3 end;def me22x()3 end;def me23x()3 end;def me24x()3 end;def me25x()3 end
117
+ def me31x()3 end;def me32x()3 end;def me33x()3 end;def me34x()3 end;def me35x()3 end
118
+ module Hidden; def me41x()3 end;def me42x()3 end;def me43x()3 end;def me44x()3 end;def me45x()3 end; end
119
+ def me51x()3 end
120
+ end
121
+ EOS
122
+ src.should_not reek_of(:LargeClass)
123
+ end
124
+ end
162
125
  end
@@ -53,18 +53,6 @@ describe LongParameterList do
53
53
  'def simple(aarg, polly=2, yep=true, zero=nil) f(3);false end'.should reek_only_of(:LongParameterList, /4 parameters/)
54
54
  end
55
55
  end
56
-
57
- describe 'in a class' do
58
- class InnerTest
59
- def xyzero(arga,argb) f(3);true end
60
- def abc(argx,yep,zero,argm) f(3);false end
61
- end
62
-
63
- it 'should only report long param list' do
64
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
65
- InnerTest.should reek_only_of(:LongParameterList, /abc/)
66
- end
67
- end
68
56
  end
69
57
 
70
58
  describe 'yield' do
@@ -1,49 +1,97 @@
1
1
  require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
2
 
3
3
  require 'reek/smells/simulated_polymorphism'
4
+ require 'reek/code_context'
4
5
 
6
+ include Reek
5
7
  include Reek::Smells
6
8
 
7
9
  describe SimulatedPolymorphism do
8
- it 'should report 3 similar conditions in a class' do
9
- src = <<EOS
10
+ before :each do
11
+ @detector = SimulatedPolymorphism.new
12
+ end
13
+ context 'with no conditionals' do
14
+ it 'gathers an empty hash' do
15
+ ast = 'module Stable; end'.to_reek_source.syntax_tree
16
+ ctx = CodeContext.new(nil, ast)
17
+ @detector.conditional_counts(ctx).length.should == 0
18
+ end
19
+ end
20
+
21
+ context 'with a test of block_given?' do
22
+ it 'does not record the condition' do
23
+ ast = 'def fred() yield(3) if block_given?; end'.to_reek_source.syntax_tree
24
+ ctx = CodeContext.new(nil, ast)
25
+ @detector.conditional_counts(ctx).length.should == 0
26
+ end
27
+ end
28
+
29
+ context 'with three identical conditionals' do
30
+ before :each do
31
+ cond = '@field == :sym'
32
+ @cond_expr = cond.to_reek_source.syntax_tree
33
+ src = <<EOS
10
34
  class Scrunch
11
35
  def first
12
- return @field == :sym ? 0 : 3;
36
+ return #{cond} ? 0 : 3;
13
37
  end
14
38
  def second
15
- if @field == :sym
39
+ if #{cond}
16
40
  @other += " quarts"
17
41
  end
18
42
  end
19
43
  def third
20
- raise 'flu!' unless @field == :sym
44
+ raise 'flu!' unless #{cond}
21
45
  end
22
46
  end
23
47
  EOS
24
48
 
25
- src.should reek_only_of(:SimulatedPolymorphism, /@field == :sym/)
49
+ ast = src.to_reek_source.syntax_tree
50
+ ctx = CodeContext.new(nil, ast)
51
+ @conds = @detector.conditional_counts(ctx)
52
+ end
53
+ it 'finds one matching conditional' do
54
+ @conds.length.should == 1
55
+ end
56
+ it 'returns the condition expr' do
57
+ @conds.keys[0].should == @cond_expr
58
+ end
59
+ it 'knows there are three copies' do
60
+ @conds[@cond_expr].should == 3
61
+ end
26
62
  end
27
63
 
28
- it 'should include case statements in the count' do
29
- src = <<EOS
64
+ context 'with a matching if and case' do
65
+ before :each do
66
+ cond = '@field == :sym'
67
+ @cond_expr = cond.to_reek_source.syntax_tree
68
+ src = <<EOS
30
69
  class Scrunch
31
- def first
32
- return @field ? 0 : 3;
70
+ def alpha
71
+ return #{cond} ? 0 : 2;
33
72
  end
34
- def second
35
- case @field
36
- when :sym
37
- @other += " quarts"
73
+ def beta
74
+ case #{cond}
75
+ when :symbol
76
+ @tother += " pints"
38
77
  end
39
78
  end
40
- def third
41
- raise 'flu!' unless @field
42
- end
43
79
  end
44
80
  EOS
45
81
 
46
- src.should reek_only_of(:SimulatedPolymorphism, /@field/)
82
+ ast = src.to_reek_source.syntax_tree
83
+ ctx = CodeContext.new(nil, ast)
84
+ @conds = @detector.conditional_counts(ctx)
85
+ end
86
+ it 'finds exactly one conditional' do
87
+ @conds.length.should == 1
88
+ end
89
+ it 'returns the condition expr' do
90
+ @conds.keys[0].should == @cond_expr
91
+ end
92
+ it 'knows there are three copies' do
93
+ @conds[@cond_expr].should == 2
94
+ end
47
95
  end
48
96
 
49
97
  # And count code in superclasses, if we have it
@@ -79,24 +79,3 @@ EOS
79
79
  end
80
80
  end
81
81
  end
82
-
83
- describe UtilityFunction do
84
- it 'should not report attrset' do
85
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
86
- class Fred
87
- attr_writer :xyz
88
- end
89
- Fred.should_not reek
90
- end
91
-
92
- it 'should not report overriding methods' do
93
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
94
- class Father
95
- def thing(ff); @kids = 0; end
96
- end
97
- class Son < Father
98
- def thing(ff); ff; end
99
- end
100
- Son.should_not reek
101
- end
102
- end
@@ -7,4 +7,5 @@ describe Sniffer do
7
7
  dirty_file = Dir['spec/samples/two_smelly_files/*.rb'][0]
8
8
  File.new(dirty_file).sniff.should be_smelly
9
9
  end
10
+
10
11
  end
@@ -1,4 +1,6 @@
1
1
  class Dirty
2
+ attr_reader :property
3
+
2
4
  def a
3
5
  puts @s.title
4
6
  @s.map {|x| x.each {|key| key += 3}}
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  $:.unshift File.dirname(__FILE__) + '/../lib'
2
2
 
3
+ require 'rubygems'
3
4
  begin
4
5
  require 'spec/expectations'
5
6
  rescue LoadError
6
- require 'rubygems'
7
7
  gem 'rspec'
8
8
  require 'spec/expectations'
9
9
  end
data/tasks/reek.rake CHANGED
@@ -4,7 +4,7 @@ begin
4
4
  Reek::RakeTask.new do |t|
5
5
  t.fail_on_error = true
6
6
  t.verbose = false
7
- t.reek_opts = '--quiet --show-all'
7
+ t.reek_opts = '--quiet'
8
8
  end
9
9
  rescue Gem::LoadError
10
10
  end