reek 1.3.4 → 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +5 -0
  3. data/README.md +27 -2
  4. data/features/command_line_interface/options.feature +5 -2
  5. data/features/command_line_interface/smells_count.feature +43 -45
  6. data/features/command_line_interface/stdin.feature +9 -15
  7. data/features/configuration_files/masking_smells.feature +9 -17
  8. data/features/rake_task/rake_task.feature +4 -4
  9. data/features/reports/reports.feature +80 -21
  10. data/features/samples.feature +8 -18
  11. data/features/step_definitions/reek_steps.rb +4 -0
  12. data/lib/reek/cli/application.rb +3 -6
  13. data/lib/reek/cli/command_line.rb +16 -6
  14. data/lib/reek/cli/reek_command.rb +4 -12
  15. data/lib/reek/cli/report.rb +61 -19
  16. data/lib/reek/config_file_exception.rb +5 -0
  17. data/lib/reek/smells/control_parameter.rb +45 -14
  18. data/lib/reek/smells/data_clump.rb +15 -39
  19. data/lib/reek/smells/duplicate_method_call.rb +76 -26
  20. data/lib/reek/source/config_file.rb +30 -19
  21. data/lib/reek/source/sexp_extensions.rb +139 -0
  22. data/lib/reek/source/sexp_node.rb +64 -0
  23. data/lib/reek/source/source_code.rb +1 -1
  24. data/lib/reek/source/tree_dresser.rb +30 -175
  25. data/lib/reek/spec/should_reek.rb +2 -5
  26. data/lib/reek/version.rb +1 -1
  27. data/reek.gemspec +1 -1
  28. data/spec/matchers/smell_of_matcher.rb +12 -15
  29. data/spec/reek/cli/report_spec.rb +10 -6
  30. data/spec/reek/core/code_parser_spec.rb +0 -6
  31. data/spec/reek/smells/control_parameter_spec.rb +195 -8
  32. data/spec/reek/smells/data_clump_spec.rb +28 -3
  33. data/spec/reek/smells/uncommunicative_method_name_spec.rb +7 -7
  34. data/spec/reek/source/sexp_extensions_spec.rb +290 -0
  35. data/spec/reek/source/sexp_node_spec.rb +28 -0
  36. data/spec/reek/source/source_code_spec.rb +59 -19
  37. data/spec/reek/source/tree_dresser_spec.rb +7 -314
  38. data/spec/reek/spec/should_reek_spec.rb +51 -64
  39. data/spec/samples/all_but_one_masked/dirty.rb +2 -2
  40. data/spec/samples/corrupt_config_file/dirty.rb +1 -0
  41. data/spec/samples/masked/dirty.rb +1 -1
  42. data/spec/samples/masked_by_dotfile/dirty.rb +2 -2
  43. data/spec/samples/no_config_file/dirty.rb +8 -0
  44. data/spec/samples/not_quite_masked/dirty.rb +0 -3
  45. data/spec/samples/three_smelly_files/dirty_one.rb +3 -0
  46. data/spec/samples/three_smelly_files/dirty_three.rb +5 -0
  47. data/spec/samples/three_smelly_files/dirty_two.rb +4 -0
  48. data/spec/spec_helper.rb +5 -0
  49. metadata +145 -137
  50. data/spec/reek/cli/reek_command_spec.rb +0 -46
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ require 'reek/source/sexp_node'
3
+
4
+ include Reek::Source
5
+
6
+ describe SexpNode do
7
+ context 'format' do
8
+ it 'formats self' do
9
+ @node = s(:self)
10
+ @node.extend(SexpNode)
11
+ @node.format_ruby.should == 'self'
12
+ end
13
+ end
14
+
15
+ context 'hash' do
16
+ it 'hashes equal for equal sexps' do
17
+ node1 = ast(:defn, s(:const2, :Fred, :jim), s(:call, :+, s(:lit, 4), :fred))
18
+ node2 = ast(:defn, s(:const2, :Fred, :jim), s(:call, :+, s(:lit, 4), :fred))
19
+ node1.hash.should == node2.hash
20
+ end
21
+ it 'hashes diferent for diferent sexps' do
22
+ node1 = ast(:defn, s(:const2, :Fred, :jim), s(:call, :+, s(:lit, 4), :fred))
23
+ node2 = ast(:defn, s(:const2, :Fred, :jim), s(:call, :+, s(:lit, 3), :fred))
24
+ node1.hash.should_not == node2.hash
25
+ end
26
+ end
27
+ end
28
+
@@ -6,33 +6,73 @@ include Reek::Source
6
6
 
7
7
  describe SourceCode do
8
8
  context 'when the parser fails' do
9
+ let(:source_name) { 'Test source' }
10
+ let(:error_message) { 'Error message' }
11
+ let(:parser) { double('parser') }
12
+ let(:src) { SourceCode.new('', source_name, parser) }
13
+
9
14
  before :each do
10
15
  @catcher = StringIO.new
11
16
  @old_err_io = (SourceCode.err_io = @catcher)
12
- parser = double('parser')
13
- @error_message = 'Error message'
14
- parser.should_receive(:parse).and_raise(SyntaxError.new(@error_message))
15
- @source_name = 'Test source'
16
- @src = SourceCode.new('', @source_name, parser)
17
- end
18
- it 'raises a SyntaxError' do
19
- @src.syntax_tree
20
17
  end
21
- it 'returns an empty syntax tree' do
22
- @src.syntax_tree.should == s()
18
+
19
+ shared_examples_for "handling and recording the error" do
20
+ it 'does not raise an error' do
21
+ src.syntax_tree
22
+ end
23
+
24
+ it 'returns an empty syntax tree' do
25
+ src.syntax_tree.should == s()
26
+ end
27
+
28
+ it 'records the syntax error' do
29
+ src.syntax_tree
30
+ @catcher.string.should match(error_class.name)
31
+ end
32
+
33
+ it 'records the source name' do
34
+ src.syntax_tree
35
+ @catcher.string.should match(source_name)
36
+ end
37
+
38
+ it 'records the error message' do
39
+ src.syntax_tree
40
+ @catcher.string.should match(error_message)
41
+ end
23
42
  end
24
- it 'records the syntax error' do
25
- @src.syntax_tree
26
- @catcher.string.should match(SyntaxError.name)
43
+
44
+ context "with a RubyParser::SyntaxError" do
45
+ let(:error_class) { RubyParser::SyntaxError }
46
+
47
+ before do
48
+ parser.stub(:parse).and_raise(error_class.new(error_message))
49
+ end
50
+
51
+ it_should_behave_like "handling and recording the error"
27
52
  end
28
- it 'records the source name' do
29
- @src.syntax_tree
30
- @catcher.string.should match(@source_name)
53
+
54
+ context "with a Racc::ParseError" do
55
+ let(:error_class) { Racc::ParseError }
56
+
57
+ before do
58
+ parser.stub(:parse).and_raise(error_class.new(error_message))
59
+ end
60
+
61
+ it_should_behave_like "handling and recording the error"
31
62
  end
32
- it 'records the error message' do
33
- @src.syntax_tree
34
- @catcher.string.should match(@error_message)
63
+
64
+ context "with a generic error" do
65
+ let(:error_class) { RuntimeError }
66
+
67
+ before do
68
+ parser.stub(:parse).and_raise(error_class.new(error_message))
69
+ end
70
+
71
+ it 'raises the error' do
72
+ expect { src.syntax_tree }.to raise_error
73
+ end
35
74
  end
75
+
36
76
  after :each do
37
77
  SourceCode.err_io = @old_err_io
38
78
  end
@@ -4,322 +4,15 @@ require 'reek/source/tree_dresser'
4
4
  include Reek::Source
5
5
 
6
6
  describe TreeDresser do
7
- before(:each) do
8
- @dresser = TreeDresser.new
9
- end
10
- it 'maps :if to IfNode' do
11
- @dresser.extensions_for(:if).should == 'IfNode'
12
- end
13
- it 'maps :call to CallNode' do
14
- @dresser.extensions_for(:call).should == 'CallNode'
15
- end
16
- end
17
-
18
- describe SexpNode do
19
- context 'format' do
20
- it 'formats self' do
21
- @node = s(:self)
22
- @node.extend(SexpNode)
23
- @node.format_ruby.should == 'self'
24
- end
25
- end
26
-
27
- context 'hash' do
28
- it 'hashes equal for equal sexps' do
29
- node1 = ast(:defn, s(:const2, :Fred, :jim), s(:call, :+, s(:lit, 4), :fred))
30
- node2 = ast(:defn, s(:const2, :Fred, :jim), s(:call, :+, s(:lit, 4), :fred))
31
- node1.hash.should == node2.hash
32
- end
33
- it 'hashes diferent for diferent sexps' do
34
- node1 = ast(:defn, s(:const2, :Fred, :jim), s(:call, :+, s(:lit, 4), :fred))
35
- node2 = ast(:defn, s(:const2, :Fred, :jim), s(:call, :+, s(:lit, 3), :fred))
36
- node1.hash.should_not == node2.hash
37
- end
38
- end
39
- end
40
-
41
- describe SexpExtensions::DefnNode do
42
- context 'with no parameters' do
43
- before :each do
44
- @node = s(:defn, :hello, s(:args))
45
- @node.extend(SexpExtensions::DefnNode)
46
- end
47
- it 'has no arg names' do
48
- @node.arg_names.should == s()
49
- end
50
- it 'has no parameter names' do
51
- @node.parameter_names.should == s()
52
- end
53
- it 'includes outer scope in its full name' do
54
- @node.full_name('Fred').should == 'Fred#hello'
55
- end
56
- it 'includes no marker in its full name with empty outer scope' do
57
- @node.full_name('').should == 'hello'
58
- end
59
- end
60
-
61
- context 'with 1 parameter' do
62
- before :each do
63
- @node = s(:defn, :hello, s(:args, :param))
64
- @node.extend(SexpExtensions::DefnNode)
65
- end
66
- it 'has 1 arg name' do
67
- @node.arg_names.should == s(:param)
68
- end
69
- it 'has 1 parameter name' do
70
- @node.parameter_names.should == s(:param)
71
- end
72
- it 'includes outer scope in its full name' do
73
- @node.full_name('Fred').should == 'Fred#hello'
74
- end
75
- it 'includes no marker in its full name with empty outer scope' do
76
- @node.full_name('').should == 'hello'
77
- end
78
- end
79
-
80
- context 'with a block' do
81
- before :each do
82
- @node = s(:defn, :hello, s(:args, :param, :"&blk"))
83
- @node.extend(SexpExtensions::DefnNode)
84
- end
85
- it 'has 1 arg name' do
86
- @node.arg_names.should == s(:param)
87
- end
88
- it 'has 2 parameter names' do
89
- @node.parameter_names.should == s(:param, :"&blk")
90
- end
91
- it 'includes outer scope in its full name' do
92
- @node.full_name('Fred').should == 'Fred#hello'
93
- end
94
- it 'includes no marker in its full name with empty outer scope' do
95
- @node.full_name('').should == 'hello'
96
- end
97
- end
98
-
99
- context 'with 1 defaulted parameter' do
100
- before :each do
101
- @node = s(:defn, :hello, s(:args, s(:lasgn, :param, s(:array))))
102
- @node.extend(SexpExtensions::DefnNode)
103
- end
104
- it 'has 1 arg name' do
105
- @node.arg_names.should == s(:param)
106
- end
107
- it 'has 1 parameter name' do
108
- @node.parameter_names.should == s(:param)
109
- end
110
- it 'includes outer scope in its full name' do
111
- @node.full_name('Fred').should == 'Fred#hello'
112
- end
113
- it 'includes no marker in its full name with empty outer scope' do
114
- @node.full_name('').should == 'hello'
115
- end
116
- end
117
-
118
- context 'with a body with 2 statements' do
119
- before :each do
120
- @node = s(:defn, :hello, s(:args), s(:first), s(:second))
121
- @node.extend(SexpExtensions::DefnNode)
122
- end
123
-
124
- it 'has 2 body statements' do
125
- @node.body.should == s(s(:first), s(:second))
126
- end
127
-
128
- it 'has a body extended with SexpNode' do
129
- b = @node.body
130
- (class << b; self; end).ancestors.first.should == SexpNode
131
- end
132
- end
133
- end
134
-
135
- describe SexpExtensions::DefsNode do
136
- context 'with no parameters' do
137
- before :each do
138
- @node = s(:defs, :obj, :hello, s(:args))
139
- @node.extend(SexpExtensions::DefsNode)
140
- end
141
- it 'has no arg names' do
142
- @node.arg_names.should == s()
143
- end
144
- it 'has no parameter names' do
145
- @node.parameter_names.should == s()
146
- end
147
- it 'includes outer scope in its full name' do
148
- @node.full_name('Fred').should == 'Fred#obj.hello'
149
- end
150
- it 'includes no marker in its full name with empty outer scope' do
151
- @node.full_name('').should == 'obj.hello'
152
- end
153
- end
154
-
155
- context 'with 1 parameter' do
156
- before :each do
157
- @node = s(:defs, :obj, :hello, s(:args, :param))
158
- @node.extend(SexpExtensions::DefsNode)
159
- end
160
- it 'has 1 arg name' do
161
- @node.arg_names.should == s(:param)
162
- end
163
- it 'has 1 parameter name' do
164
- @node.parameter_names.should == s(:param)
165
- end
166
- it 'includes outer scope in its full name' do
167
- @node.full_name('Fred').should == 'Fred#obj.hello'
168
- end
169
- it 'includes no marker in its full name with empty outer scope' do
170
- @node.full_name('').should == 'obj.hello'
171
- end
172
- end
173
-
174
- context 'with a block' do
175
- before :each do
176
- @node = s(:defs, :obj, :hello, s(:args, :param, :"&blk"))
177
- @node.extend(SexpExtensions::DefsNode)
178
- end
179
- it 'has 1 arg name' do
180
- @node.arg_names.should == s(:param)
181
- end
182
- it 'has 2 parameter names' do
183
- @node.parameter_names.should == s(:param, :"&blk")
184
- end
185
- it 'includes outer scope in its full name' do
186
- @node.full_name('Fred').should == 'Fred#obj.hello'
187
- end
188
- it 'includes no marker in its full name with empty outer scope' do
189
- @node.full_name('').should == 'obj.hello'
190
- end
191
- end
192
-
193
- context 'with 1 defaulted parameter' do
194
- before :each do
195
- @node = s(:defs, :obj, :hello, s(:args, s(:lasgn, :param, s(:array))))
196
- @node.extend(SexpExtensions::DefsNode)
197
- end
198
- it 'has 1 arg name' do
199
- @node.arg_names.should == s(:param)
200
- end
201
- it 'has 1 parameter name' do
202
- @node.parameter_names.should == s(:param)
203
- end
204
- it 'includes outer scope in its full name' do
205
- @node.full_name('Fred').should == 'Fred#obj.hello'
206
- end
207
- it 'includes no marker in its full name with empty outer scope' do
208
- @node.full_name('').should == 'obj.hello'
209
- end
210
- end
211
-
212
- context 'with a body with 2 statements' do
213
- before :each do
214
- @node = s(:defs, s(:self), :hello, s(:args), s(:first), s(:second))
215
- @node.extend(SexpExtensions::DefsNode)
216
- end
217
-
218
- it 'has 2 body statements' do
219
- @node.body.should == s(s(:first), s(:second))
220
- end
221
-
222
- it 'has a body extended with SexpNode' do
223
- b = @node.body
224
- (class << b; self; end).ancestors.first.should == SexpNode
225
- end
226
- end
227
- end
228
-
229
- describe SexpExtensions::CallNode do
230
- context 'with no parameters' do
231
- before :each do
232
- @node = s(:call, nil, :hello)
233
- @node.extend(SexpExtensions::CallNode)
234
- end
235
- it 'has no parameter names' do
236
- @node.parameter_names.should == nil
237
- end
238
- end
239
-
240
- context 'with 1 literal parameter' do
241
- before :each do
242
- @node = s(:call, nil, :hello, s(:lit, :param))
243
- @node.extend(SexpExtensions::CallNode)
244
- end
245
- it 'has 1 argument name' do
246
- @node.arg_names.should == [:param]
247
- end
248
- end
249
-
250
- context 'with 2 literal parameters' do
251
- before :each do
252
- @node = s(:call, nil, :hello, s(:lit, :x), s(:lit, :y))
253
- @node.extend(SexpExtensions::CallNode)
254
- end
255
- it 'has 2 argument names' do
256
- @node.arg_names.should == [:x, :y]
257
- end
258
- end
259
- end
260
-
261
- describe SexpExtensions::IterNode do
262
- context 'with no parameters' do
263
- before :each do
264
- @node = s(:iter, s(), s(:args), s())
265
- @node.extend(SexpExtensions::IterNode)
266
- end
267
- it 'has no parameter names' do
268
- @node.parameter_names.should == []
269
- end
270
- end
271
-
272
- context 'with 1 parameter' do
273
- before :each do
274
- @node = s(:iter, s(), s(:args, :param), s())
275
- @node.extend(SexpExtensions::IterNode)
276
- end
277
- it 'has 1 parameter name' do
278
- @node.parameter_names.should == s(:param)
279
- end
280
- end
281
-
282
- context 'with 2 parameters' do
283
- before :each do
284
- @node = s(:iter, s(), s(:args, :x, :y), s())
285
- @node.extend(SexpExtensions::IterNode)
286
- end
287
- it 'has 2 parameter names' do
288
- @node.parameter_names.should == [:x, :y]
289
- end
290
- end
291
- end
7
+ let(:ifnode) { Sexp.new(:if) }
8
+ let(:callnode) { Sexp.new(:call) }
9
+ let(:dresser) { TreeDresser.new }
292
10
 
293
- describe SexpExtensions::ModuleNode do
294
- context 'with a simple name' do
295
- subject do
296
- mod = ast(:module, :Fred, nil)
297
- mod
298
- end
299
- its(:name) { should == :Fred }
300
- its(:simple_name) { should == :Fred }
301
- its(:text_name) { should == 'Fred' }
302
- it 'has a simple full_name' do
303
- subject.full_name('').should == 'Fred'
304
- end
305
- it 'has a fq full_name' do
306
- subject.full_name('Blimey::O::Reilly').should == 'Blimey::O::Reilly::Fred'
307
- end
11
+ it 'dresses :if sexp with IfNode' do
12
+ dresser.dress(ifnode).should be_a Reek::Source::SexpExtensions::IfNode
308
13
  end
309
14
 
310
- context 'with a scoped name' do
311
- subject do
312
- mod = ast(:module, s(:colon2, s(:const, :Foo), :Bar), nil)
313
- mod
314
- end
315
- its(:name) { should == s(:colon2, s(:const, :Foo), :Bar) }
316
- its(:simple_name) { should == :Bar }
317
- its(:text_name) { should == 'Foo::Bar' }
318
- it 'has a simple full_name' do
319
- subject.full_name('').should == 'Foo::Bar'
320
- end
321
- it 'has a fq full_name' do
322
- subject.full_name('Blimey::O::Reilly').should == 'Blimey::O::Reilly::Foo::Bar'
323
- end
15
+ it 'dresses :call sexp with CallNode' do
16
+ dresser.dress(callnode).should be_a Reek::Source::SexpExtensions::CallNode
324
17
  end
325
18
  end