reek 1.3.4 → 1.3.5

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 (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