kevinrutherford-reek 1.0.1 → 1.1.1
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 +42 -22
- data/config/defaults.reek +1 -0
- data/lib/reek.rb +1 -1
- data/lib/reek/block_context.rb +27 -5
- data/lib/reek/class_context.rb +5 -4
- data/lib/reek/code_parser.rb +26 -11
- data/lib/reek/method_context.rb +18 -12
- data/lib/reek/module_context.rb +1 -1
- data/lib/reek/name.rb +8 -1
- data/lib/reek/object_refs.rb +2 -3
- data/lib/reek/report.rb +11 -4
- data/lib/reek/sexp_formatter.rb +4 -46
- data/lib/reek/smells/large_class.rb +26 -7
- data/lib/reek/smells/long_parameter_list.rb +1 -1
- data/lib/reek/smells/smells.rb +4 -8
- data/lib/reek/source.rb +31 -4
- data/lib/reek/spec.rb +6 -0
- data/lib/reek/stop_context.rb +4 -16
- data/lib/reek/yield_call_context.rb +1 -3
- data/reek.gemspec +8 -5
- data/spec/reek/block_context_spec.rb +40 -0
- data/spec/reek/class_context_spec.rb +11 -0
- data/spec/reek/code_context_spec.rb +2 -1
- data/spec/reek/code_parser_spec.rb +0 -10
- data/spec/reek/config_spec.rb +2 -2
- data/spec/reek/method_context_spec.rb +14 -0
- data/spec/reek/name_spec.rb +13 -0
- data/spec/reek/object_refs_spec.rb +11 -9
- data/spec/reek/report_spec.rb +1 -1
- data/spec/reek/sexp_formatter_spec.rb +5 -4
- data/spec/reek/singleton_method_context_spec.rb +1 -1
- data/spec/reek/smells/duplication_spec.rb +2 -2
- data/spec/reek/smells/feature_envy_spec.rb +132 -36
- data/spec/reek/smells/large_class_spec.rb +48 -47
- data/spec/reek/smells/long_method_spec.rb +1 -1
- data/spec/reek/smells/long_parameter_list_spec.rb +4 -11
- data/spec/reek/smells/uncommunicative_name_spec.rb +6 -1
- data/spec/reek/smells/utility_function_spec.rb +6 -9
- data/spec/{samples → slow}/inline_spec.rb +14 -10
- data/spec/{samples → slow}/optparse_spec.rb +20 -12
- data/spec/{samples → slow}/redcloth_spec.rb +16 -8
- data/spec/{integration → slow}/reek_source_spec.rb +0 -0
- data/spec/{samples → slow/samples}/inline.rb +0 -0
- data/spec/{samples → slow/samples}/optparse.rb +0 -0
- data/spec/{samples → slow/samples}/redcloth.rb +0 -0
- data/spec/{integration → slow}/script_spec.rb +0 -0
- data/spec/{reek/source_spec.rb → slow/source_list_spec.rb} +3 -3
- data/spec/spec_helper.rb +2 -0
- data/tasks/rspec.rake +1 -1
- metadata +24 -12
data/spec/reek/report_spec.rb
CHANGED
@@ -7,7 +7,7 @@ include Reek
|
|
7
7
|
|
8
8
|
def should_print(example)
|
9
9
|
it "should format #{example} correctly" do
|
10
|
-
sexp = CodeParser.parse_tree_for(example)
|
10
|
+
sexp = CodeParser.parse_tree_for(example)
|
11
11
|
SexpFormatter.format(sexp).should == example
|
12
12
|
end
|
13
13
|
end
|
@@ -23,9 +23,10 @@ describe SexpFormatter do
|
|
23
23
|
should_print 'obj.method(arg1, arg2)'
|
24
24
|
should_print 'obj.method'
|
25
25
|
should_print '$1'
|
26
|
-
should_print 'o=q.downcase'
|
26
|
+
should_print 'o = q.downcase'
|
27
27
|
should_print 'true'
|
28
28
|
should_print '"-#{q}xxx#{z.size}"'
|
29
|
-
should_print '0..5'
|
30
|
-
should_print '0..temp'
|
29
|
+
should_print '(0..5)'
|
30
|
+
should_print '(0..temp)'
|
31
|
+
should_print 'result[opt] = false'
|
31
32
|
end
|
@@ -11,7 +11,7 @@ describe SingletonMethodContext, 'outer_name' do
|
|
11
11
|
it "should report full context" do
|
12
12
|
element = StopContext.new
|
13
13
|
element = ModuleContext.new(element, [0, :mod])
|
14
|
-
element = SingletonMethodContext.new(element, [:defs, [:
|
14
|
+
element = SingletonMethodContext.new(element, [:defs, [:call, nil, :a, [:arglist]], :b, nil])
|
15
15
|
element.outer_name.should match(/mod::a\.b/)
|
16
16
|
end
|
17
17
|
end
|
@@ -13,7 +13,7 @@ describe Duplication, "repeated method calls" do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'should report repeated call to lvar' do
|
16
|
-
'def double_thing() other[@thing] + other[@thing] end'.should reek_only_of(:Duplication, /other\[@thing\]/)
|
16
|
+
'def double_thing(other) other[@thing] + other[@thing] end'.should reek_only_of(:Duplication, /other\[@thing\]/)
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'should report call parameters' do
|
@@ -50,7 +50,7 @@ describe Duplication, '#examine' do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
it 'should return true when reporting a smell' do
|
53
|
-
@mc.calls = {
|
53
|
+
@mc.calls = {s(:call, nil, :other, s(:arglist)) => 47}
|
54
54
|
@dup.examine(@mc, []).should == true
|
55
55
|
end
|
56
56
|
|
@@ -6,7 +6,7 @@ require 'reek/stop_context'
|
|
6
6
|
include Reek
|
7
7
|
include Reek::Smells
|
8
8
|
|
9
|
-
describe FeatureEnvy
|
9
|
+
describe FeatureEnvy do
|
10
10
|
it 'should not report use of self' do
|
11
11
|
'def simple() self.to_s + self.to_i end'.should_not reek
|
12
12
|
end
|
@@ -18,23 +18,26 @@ describe FeatureEnvy, 'with only messages to self' do
|
|
18
18
|
it 'should not report vcall with argument' do
|
19
19
|
'def simple(arga) func(17); end'.should_not reek
|
20
20
|
end
|
21
|
-
end
|
22
21
|
|
23
|
-
describe FeatureEnvy, 'when the receiver is a parameter' do
|
24
22
|
it 'should not report single use' do
|
25
|
-
'def no_envy(arga)
|
23
|
+
'def no_envy(arga)
|
24
|
+
arga.barg(@item)
|
25
|
+
end'.should_not reek
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'should not report return value' do
|
29
|
-
'def no_envy(arga)
|
29
|
+
'def no_envy(arga)
|
30
|
+
arga.barg(@item)
|
31
|
+
arga
|
32
|
+
end'.should_not reek
|
30
33
|
end
|
31
34
|
|
32
35
|
it 'should report many calls to parameter' do
|
33
|
-
'def envy(arga)
|
36
|
+
'def envy(arga)
|
37
|
+
arga.b(arga) + arga.c(@fred)
|
38
|
+
end'.should reek_only_of(:FeatureEnvy, /arga/)
|
34
39
|
end
|
35
|
-
end
|
36
40
|
|
37
|
-
describe FeatureEnvy, 'when there are many possible receivers' do
|
38
41
|
it 'should report highest affinity' do
|
39
42
|
ruby = 'def total_envy
|
40
43
|
fred = @item
|
@@ -56,9 +59,7 @@ describe FeatureEnvy, 'when there are many possible receivers' do
|
|
56
59
|
ruby.should reek_of(:FeatureEnvy, /total/)
|
57
60
|
ruby.should reek_of(:FeatureEnvy, /fred/)
|
58
61
|
end
|
59
|
-
end
|
60
62
|
|
61
|
-
describe FeatureEnvy, 'when the receiver is external' do
|
62
63
|
it 'should ignore global variables' do
|
63
64
|
'def no_envy() $s2.to_a; $s2[@item] end'.should_not reek
|
64
65
|
end
|
@@ -66,9 +67,7 @@ describe FeatureEnvy, 'when the receiver is external' do
|
|
66
67
|
it 'should not report class methods' do
|
67
68
|
'def simple() self.class.new.flatten_merge(self) end'.should_not reek
|
68
69
|
end
|
69
|
-
end
|
70
70
|
|
71
|
-
describe FeatureEnvy, 'when the receiver is an ivar' do
|
72
71
|
it 'should not report single use of an ivar' do
|
73
72
|
'def no_envy() @item.to_a end'.should_not reek
|
74
73
|
end
|
@@ -78,17 +77,132 @@ describe FeatureEnvy, 'when the receiver is an ivar' do
|
|
78
77
|
end
|
79
78
|
|
80
79
|
it 'should not report ivar usage in a parameter' do
|
81
|
-
'def no_envy
|
80
|
+
'def no_envy
|
81
|
+
@item.price + tax(@item) - savings(@item)
|
82
|
+
end'.should_not reek
|
82
83
|
end
|
83
84
|
|
84
85
|
it 'should not be fooled by duplication' do
|
85
|
-
|
86
|
-
|
86
|
+
'def feed(thing)
|
87
|
+
@cow.feed_to(thing.pig)
|
88
|
+
@duck.feed_to(thing.pig)
|
89
|
+
end'.should reek_only_of(:Duplication, /thing.pig/)
|
87
90
|
end
|
88
91
|
|
89
92
|
it 'should count local calls' do
|
90
|
-
|
91
|
-
|
93
|
+
'def feed(thing)
|
94
|
+
cow.feed_to(thing.pig)
|
95
|
+
duck.feed_to(thing.pig)
|
96
|
+
end'.should reek_only_of(:Duplication, /thing.pig/)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should not report single use of an lvar' do
|
100
|
+
'def no_envy()
|
101
|
+
lv = @item
|
102
|
+
lv.to_a
|
103
|
+
end'.should_not reek
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should not report returning an lvar' do
|
107
|
+
'def no_envy()
|
108
|
+
lv = @item
|
109
|
+
lv.to_a
|
110
|
+
lv
|
111
|
+
end'.should_not reek
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should report many calls to lvar' do
|
115
|
+
'def envy
|
116
|
+
lv = @item
|
117
|
+
lv.price + lv.tax
|
118
|
+
end'.should reek_only_of(:FeatureEnvy, /lv/)
|
119
|
+
#
|
120
|
+
# def moved_version
|
121
|
+
# price + tax
|
122
|
+
# end
|
123
|
+
#
|
124
|
+
# def envy
|
125
|
+
# @item.moved_version
|
126
|
+
# end
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'ignores lvar usage in a parameter' do
|
130
|
+
'def no_envy
|
131
|
+
lv = @item
|
132
|
+
lv.price + tax(lv) - savings(lv)
|
133
|
+
end'.should_not reek
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'reports the most-used ivar' do
|
137
|
+
pending('bug')
|
138
|
+
'def func
|
139
|
+
@other.a
|
140
|
+
@other.b
|
141
|
+
@nother.c
|
142
|
+
end'.should reek_of(:FeatureEnvy, /@other/)
|
143
|
+
#
|
144
|
+
# def other.func(me)
|
145
|
+
# a
|
146
|
+
# b
|
147
|
+
# me.nother_c
|
148
|
+
# end
|
149
|
+
#
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'ignores multiple ivars' do
|
153
|
+
'def func
|
154
|
+
@other.a
|
155
|
+
@other.b
|
156
|
+
@nother.c
|
157
|
+
@nother.d
|
158
|
+
end'.should_not reek
|
159
|
+
#
|
160
|
+
# def other.func(me)
|
161
|
+
# a
|
162
|
+
# b
|
163
|
+
# me.nother_c
|
164
|
+
# me.nother_d
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'ignores frequent use of a call' do
|
170
|
+
'def func
|
171
|
+
other.a
|
172
|
+
other.b
|
173
|
+
nother.c
|
174
|
+
end'.should_not reek_of(:FeatureEnvy)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'counts self references correctly' do
|
178
|
+
'def adopt!(other)
|
179
|
+
other.keys.each do |key|
|
180
|
+
ov = other[key]
|
181
|
+
if Array === ov and has_key?(key)
|
182
|
+
self[key] += ov
|
183
|
+
else
|
184
|
+
self[key] = ov
|
185
|
+
end
|
186
|
+
end
|
187
|
+
self
|
188
|
+
end'.should_not reek
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe FeatureEnvy do
|
193
|
+
it 'counts references to self correctly' do
|
194
|
+
ruby = <<EOS
|
195
|
+
def report
|
196
|
+
unless @report
|
197
|
+
@report = Report.new
|
198
|
+
cf = SmellConfig.new
|
199
|
+
cf = cf.load_local(@dir) if @dir
|
200
|
+
CodeParser.new(@report, cf.smell_listeners).check_source(@source)
|
201
|
+
end
|
202
|
+
@report
|
203
|
+
end
|
204
|
+
EOS
|
205
|
+
ruby.should reek_only_of(:LongMethod)
|
92
206
|
end
|
93
207
|
end
|
94
208
|
|
@@ -104,26 +218,8 @@ describe FeatureEnvy, '#examine' do
|
|
104
218
|
@context.refs.record_ref([:lvar, :thing])
|
105
219
|
@fe.examine(@context, []).should == true
|
106
220
|
end
|
107
|
-
|
221
|
+
|
108
222
|
it 'should return false when not reporting a smell' do
|
109
223
|
@fe.examine(@context, []).should == false
|
110
224
|
end
|
111
225
|
end
|
112
|
-
|
113
|
-
describe FeatureEnvy, 'when the receiver is an lvar' do
|
114
|
-
it 'should not report single use of an lvar' do
|
115
|
-
'def no_envy() lv = @item; lv.to_a end'.should_not reek
|
116
|
-
end
|
117
|
-
|
118
|
-
it 'should not report returning an lvar' do
|
119
|
-
'def no_envy() lv = @item; lv.to_a; lv end'.should_not reek
|
120
|
-
end
|
121
|
-
|
122
|
-
it 'should report many calls to lvar' do
|
123
|
-
'def envy; lv = @item; lv.price + lv.tax end'.should reek_only_of(:FeatureEnvy, /lv/)
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'should not report lvar usage in a parameter' do
|
127
|
-
'def no_envy; lv = @item; lv.price + tax(lv) - savings(lv) end'.should_not reek
|
128
|
-
end
|
129
|
-
end
|
@@ -8,18 +8,19 @@ include Reek::Smells
|
|
8
8
|
|
9
9
|
describe LargeClass do
|
10
10
|
|
11
|
-
class
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
it 'should report large class' do
|
12
|
+
class BigOne
|
13
|
+
26.times do |i|
|
14
|
+
define_method "method#{i}".to_sym do
|
15
|
+
@melting
|
16
|
+
end
|
15
17
|
end
|
16
18
|
end
|
19
|
+
BigOne.should reek_only_of(:LargeClass, /BigOne/)
|
17
20
|
end
|
21
|
+
end
|
18
22
|
|
19
|
-
|
20
|
-
@rpt = Report.new
|
21
|
-
@cchk = CodeParser.new(@rpt, SmellConfig.new.smell_listeners)
|
22
|
-
end
|
23
|
+
describe LargeClass do
|
23
24
|
|
24
25
|
it 'should not report short class' do
|
25
26
|
class ShortClass
|
@@ -30,57 +31,57 @@ describe LargeClass do
|
|
30
31
|
def method5() @var5; end
|
31
32
|
def method6() @var6; end
|
32
33
|
end
|
33
|
-
|
34
|
-
@rpt.should be_empty
|
34
|
+
ShortClass.should_not reek
|
35
35
|
end
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
@cchk.check_object(BigOne)
|
39
|
-
@rpt.length.should == 1
|
40
|
-
end
|
38
|
+
describe LargeClass, 'when exceptions are listed' do
|
41
39
|
|
42
|
-
|
43
|
-
@
|
44
|
-
@
|
40
|
+
before(:each) do
|
41
|
+
@rpt = Report.new
|
42
|
+
@ctx = ClassContext.create(StopContext.new, [0, :Humungous])
|
43
|
+
30.times { |num| @ctx.record_method("method#{num}") }
|
44
|
+
@config = LargeClass.default_config
|
45
45
|
end
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
47
|
+
it 'should ignore first excepted name' do
|
48
|
+
@config[LargeClass::EXCLUDE_KEY] = ['Humungous']
|
49
|
+
lc = LargeClass.new(@config)
|
50
|
+
lc.examine(@ctx, @rpt).should == false
|
51
|
+
@rpt.length.should == 0
|
52
|
+
end
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
54
|
+
it 'should ignore second excepted name' do
|
55
|
+
@config[LargeClass::EXCLUDE_KEY] = ['Oversized', 'Humungous']
|
56
|
+
lc = LargeClass.new(@config)
|
57
|
+
lc.examine(@ctx, @rpt).should == false
|
58
|
+
@rpt.length.should == 0
|
59
|
+
end
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
61
|
+
it 'should report non-excepted name' do
|
62
|
+
@config[LargeClass::EXCLUDE_KEY] = ['SmellMe']
|
63
|
+
lc = LargeClass.new(@config)
|
64
|
+
lc.examine(@ctx, @rpt).should == true
|
65
|
+
@rpt.length.should == 1
|
66
|
+
end
|
67
|
+
end
|
67
68
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
69
|
+
describe LargeClass, 'counting instance variables' do
|
70
|
+
it 'warns about class with 10 ivars' do
|
71
|
+
class ManyIvars
|
72
|
+
def method
|
73
|
+
@vara = @varb = @varc = @vard = @vare
|
74
|
+
@varf = @varg = @varh = @vari = @varj
|
75
|
+
end
|
73
76
|
end
|
77
|
+
ManyIvars.should reek_of(:LargeClass, /10/)
|
74
78
|
end
|
75
|
-
end
|
76
79
|
|
77
|
-
|
78
|
-
|
79
|
-
'class Treetop::Runtime::SyntaxNode; end'.should_not reek
|
80
|
+
it 'ignores class with only a couple of ivars' do
|
81
|
+
LargeClass.should_not reek_of(:LargeClass)
|
80
82
|
end
|
81
83
|
|
82
|
-
it '
|
83
|
-
|
84
|
-
element.num_methods.should == 0
|
84
|
+
it 'ignores fq class with only a couple of ivars' do
|
85
|
+
Reek::Smells::LargeClass.should_not reek_of(:LargeClass)
|
85
86
|
end
|
86
87
|
end
|
@@ -7,7 +7,7 @@ require 'reek/report'
|
|
7
7
|
include Reek
|
8
8
|
include Reek::Smells
|
9
9
|
|
10
|
-
describe
|
10
|
+
describe LongParameterList do
|
11
11
|
|
12
12
|
describe 'for methods with few parameters' do
|
13
13
|
it 'should report nothing for no parameters' do
|
@@ -25,7 +25,7 @@ describe CodeParser, "(Long Parameter List)" do
|
|
25
25
|
it 'should not report inner block with too many parameters' do
|
26
26
|
'def simple(yep,zero); m[3]; rand(34); f.each { |arga, argb, argc, argd| true}; end'.should_not reek
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
describe 'and default values' do
|
30
30
|
it 'should report nothing for 1 parameter' do
|
31
31
|
'def simple(zero=nil) f(3);false end'.should_not reek
|
@@ -57,20 +57,13 @@ describe CodeParser, "(Long Parameter List)" do
|
|
57
57
|
end
|
58
58
|
|
59
59
|
describe 'in a class' do
|
60
|
-
before(:each) do
|
61
|
-
@rpt = Report.new
|
62
|
-
@cchk = CodeParser.new(@rpt, SmellConfig.new.smell_listeners)
|
63
|
-
end
|
64
|
-
|
65
60
|
class InnerTest
|
66
61
|
def xyzero(arga,argb) f(3);true end
|
67
62
|
def abc(argx,yep,zero,argm) f(3);false end
|
68
63
|
end
|
69
64
|
|
70
65
|
it 'should only report long param list' do
|
71
|
-
|
72
|
-
@rpt.length.should == 1
|
73
|
-
@rpt[0].report.should match(/Long Parameter List/)
|
66
|
+
InnerTest.should reek_only_of(:LongParameterList, /abc/)
|
74
67
|
end
|
75
68
|
end
|
76
69
|
end
|
@@ -83,7 +76,7 @@ describe CodeParser, "(Long Parameter List)" do
|
|
83
76
|
'def simple(arga, argb, &blk) f(3);yield a,b; end'.should_not reek
|
84
77
|
end
|
85
78
|
it 'should report yield with many parameters' do
|
86
|
-
'def simple(arga, argb, &blk) f(3);yield
|
79
|
+
'def simple(arga, argb, &blk) f(3);yield arga,argb,arga,argb; end'.should reek_only_of(:LongYieldList, /simple/, /yields/, /4/)
|
87
80
|
end
|
88
81
|
it 'should not report yield of a long expression' do
|
89
82
|
'def simple(arga, argb, &blk) f(3);yield(if @dec then argb else 5+3 end); end'.should_not reek
|