reek 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +5 -0
  3. data/README.md +70 -92
  4. data/config/defaults.reek +3 -0
  5. data/features/samples.feature +24 -20
  6. data/features/step_definitions/reek_steps.rb +1 -1
  7. data/features/support/env.rb +7 -7
  8. data/lib/reek/core/code_context.rb +1 -1
  9. data/lib/reek/core/code_parser.rb +19 -18
  10. data/lib/reek/core/method_context.rb +8 -7
  11. data/lib/reek/core/module_context.rb +1 -1
  12. data/lib/reek/core/smell_repository.rb +1 -0
  13. data/lib/reek/core/sniffer.rb +3 -1
  14. data/lib/reek/rake/task.rb +1 -5
  15. data/lib/reek/smell_description.rb +26 -0
  16. data/lib/reek/smell_warning.rb +35 -49
  17. data/lib/reek/smells.rb +1 -0
  18. data/lib/reek/smells/attribute.rb +1 -1
  19. data/lib/reek/smells/control_parameter.rb +14 -7
  20. data/lib/reek/smells/data_clump.rb +1 -1
  21. data/lib/reek/smells/duplicate_method_call.rb +2 -9
  22. data/lib/reek/smells/module_initialize.rb +38 -0
  23. data/lib/reek/smells/nested_iterators.rb +1 -1
  24. data/lib/reek/smells/nil_check.rb +3 -3
  25. data/lib/reek/smells/repeated_conditional.rb +3 -2
  26. data/lib/reek/smells/smell_detector.rb +1 -1
  27. data/lib/reek/smells/too_many_instance_variables.rb +1 -1
  28. data/lib/reek/smells/too_many_methods.rb +1 -1
  29. data/lib/reek/smells/uncommunicative_method_name.rb +0 -4
  30. data/lib/reek/smells/uncommunicative_parameter_name.rb +0 -4
  31. data/lib/reek/smells/uncommunicative_variable_name.rb +11 -9
  32. data/lib/reek/smells/utility_function.rb +2 -2
  33. data/lib/reek/source/ast_node.rb +40 -0
  34. data/lib/reek/source/ast_node_class_map.rb +37 -0
  35. data/lib/reek/source/reference_collector.rb +3 -3
  36. data/lib/reek/source/sexp_extensions.rb +133 -59
  37. data/lib/reek/source/sexp_formatter.rb +10 -4
  38. data/lib/reek/source/sexp_node.rb +25 -17
  39. data/lib/reek/source/source_code.rb +21 -9
  40. data/lib/reek/source/tree_dresser.rb +10 -33
  41. data/lib/reek/version.rb +1 -1
  42. data/reek.gemspec +2 -4
  43. data/spec/matchers/smell_of_matcher.rb +9 -1
  44. data/spec/quality/reek_source_spec.rb +0 -35
  45. data/spec/reek/core/code_context_spec.rb +22 -8
  46. data/spec/reek/core/method_context_spec.rb +10 -10
  47. data/spec/reek/smell_description_spec.rb +43 -0
  48. data/spec/reek/smell_warning_spec.rb +0 -3
  49. data/spec/reek/smells/control_parameter_spec.rb +24 -0
  50. data/spec/reek/smells/feature_envy_spec.rb +50 -17
  51. data/spec/reek/smells/irresponsible_module_spec.rb +25 -17
  52. data/spec/reek/smells/module_initialize_spec.rb +20 -0
  53. data/spec/reek/smells/prima_donna_method_spec.rb +2 -2
  54. data/spec/reek/smells/repeated_conditional_spec.rb +10 -4
  55. data/spec/reek/smells/too_many_instance_variables_spec.rb +47 -21
  56. data/spec/reek/smells/too_many_statements_spec.rb +11 -1
  57. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +1 -1
  58. data/spec/reek/smells/utility_function_spec.rb +26 -25
  59. data/spec/reek/source/sexp_extensions_spec.rb +164 -91
  60. data/spec/reek/source/sexp_formatter_spec.rb +13 -1
  61. data/spec/reek/source/sexp_node_spec.rb +5 -5
  62. data/spec/reek/source/source_code_spec.rb +18 -6
  63. data/spec/reek/source/tree_dresser_spec.rb +5 -5
  64. data/spec/spec_helper.rb +8 -4
  65. metadata +16 -50
@@ -3,96 +3,138 @@ require 'reek/source/sexp_extensions'
3
3
 
4
4
  include Reek::Source
5
5
 
6
- describe SexpExtensions::DefnNode do
6
+ describe SexpExtensions::DefNode do
7
7
  context 'with no parameters' do
8
8
  before :each do
9
- @node = s(:defn, :hello, s(:args))
10
- @node.extend(SexpExtensions::DefnNode)
9
+ @node = s(:def, :hello, s(:args))
11
10
  end
11
+
12
12
  it 'has no arg names' do
13
- expect(@node.arg_names).to eq(s())
13
+ expect(@node.arg_names).to eq []
14
14
  end
15
+
15
16
  it 'has no parameter names' do
16
- expect(@node.parameter_names).to eq(s())
17
+ expect(@node.parameter_names).to eq []
17
18
  end
19
+
18
20
  it 'includes outer scope in its full name' do
19
- expect(@node.full_name('Fred')).to eq('Fred#hello')
21
+ expect(@node.full_name('Fred')).to eq 'Fred#hello'
20
22
  end
23
+
21
24
  it 'includes no marker in its full name with empty outer scope' do
22
- expect(@node.full_name('')).to eq('hello')
25
+ expect(@node.full_name('')).to eq 'hello'
23
26
  end
27
+
24
28
  end
25
29
 
26
30
  context 'with 1 parameter' do
27
31
  before :each do
28
- @node = s(:defn, :hello, s(:args, :param))
29
- @node.extend(SexpExtensions::DefnNode)
32
+ @node = s(:def, :hello,
33
+ s(:args, s(:arg, :param)))
30
34
  end
35
+
31
36
  it 'has 1 arg name' do
32
- expect(@node.arg_names).to eq(s(:param))
37
+ expect(@node.arg_names).to eq [:param]
33
38
  end
39
+
34
40
  it 'has 1 parameter name' do
35
- expect(@node.parameter_names).to eq(s(:param))
41
+ expect(@node.parameter_names).to eq [:param]
36
42
  end
43
+
37
44
  it 'includes outer scope in its full name' do
38
- expect(@node.full_name('Fred')).to eq('Fred#hello')
45
+ expect(@node.full_name('Fred')).to eq 'Fred#hello'
39
46
  end
47
+
40
48
  it 'includes no marker in its full name with empty outer scope' do
41
- expect(@node.full_name('')).to eq('hello')
49
+ expect(@node.full_name('')).to eq 'hello'
42
50
  end
51
+
43
52
  end
44
53
 
45
- context 'with a block' do
54
+ context 'with a block parameter' do
46
55
  before :each do
47
- @node = s(:defn, :hello, s(:args, :param, :"&blk"))
48
- @node.extend(SexpExtensions::DefnNode)
56
+ @node = s(:def, :hello,
57
+ s(:args,
58
+ s(:arg, :param),
59
+ s(:blockarg, :blk)))
49
60
  end
61
+
50
62
  it 'has 1 arg name' do
51
- expect(@node.arg_names).to eq(s(:param))
63
+ expect(@node.arg_names).to eq [:param]
52
64
  end
65
+
53
66
  it 'has 2 parameter names' do
54
- expect(@node.parameter_names).to eq(s(:param, :"&blk"))
67
+ expect(@node.parameter_names).to eq [:param, :blk]
55
68
  end
69
+
56
70
  it 'includes outer scope in its full name' do
57
- expect(@node.full_name('Fred')).to eq('Fred#hello')
71
+ expect(@node.full_name('Fred')).to eq 'Fred#hello'
58
72
  end
73
+
59
74
  it 'includes no marker in its full name with empty outer scope' do
60
- expect(@node.full_name('')).to eq('hello')
75
+ expect(@node.full_name('')).to eq 'hello'
61
76
  end
77
+
62
78
  end
63
79
 
64
80
  context 'with 1 defaulted parameter' do
65
81
  before :each do
66
- @node = s(:defn, :hello, s(:args, s(:lasgn, :param, s(:array))))
67
- @node.extend(SexpExtensions::DefnNode)
82
+ @node = s(:def, :hello,
83
+ s(:args,
84
+ s(:optarg, :param, s(:array))))
68
85
  end
86
+
69
87
  it 'has 1 arg name' do
70
- expect(@node.arg_names).to eq(s(:param))
88
+ expect(@node.arg_names).to eq [:param]
71
89
  end
90
+
72
91
  it 'has 1 parameter name' do
73
- expect(@node.parameter_names).to eq(s(:param))
92
+ expect(@node.parameter_names).to eq [:param]
74
93
  end
94
+
75
95
  it 'includes outer scope in its full name' do
76
- expect(@node.full_name('Fred')).to eq('Fred#hello')
96
+ expect(@node.full_name('Fred')).to eq 'Fred#hello'
77
97
  end
98
+
78
99
  it 'includes no marker in its full name with empty outer scope' do
79
- expect(@node.full_name('')).to eq('hello')
100
+ expect(@node.full_name('')).to eq 'hello'
80
101
  end
102
+
81
103
  end
82
104
 
83
105
  context 'with a body with 2 statements' do
84
106
  before :each do
85
- @node = s(:defn, :hello, s(:args), s(:first), s(:second))
86
- @node.extend(SexpExtensions::DefnNode)
107
+ @node = s(:def, :hello, s(:args),
108
+ s(:begin,
109
+ s(:first),
110
+ s(:second)))
87
111
  end
88
112
 
89
113
  it 'has 2 body statements' do
90
- expect(@node.body).to eq(s(s(:first), s(:second)))
114
+ expect(@node.body).to eq s(:begin, s(:first), s(:second))
91
115
  end
92
116
 
93
117
  it 'has a body extended with SexpNode' do
94
118
  b = @node.body
95
- expect((class << b; self; end).included_modules.first).to eq(SexpNode)
119
+ expect(b.class.included_modules.first).to eq SexpNode
120
+ end
121
+
122
+ it 'finds nodes in the body with #body_nodes' do
123
+ expect(@node.body_nodes([:first])).to eq [s(:first)]
124
+ end
125
+ end
126
+
127
+ context 'with no body' do
128
+ before :each do
129
+ @node = s(:def, :hello, s(:args), nil)
130
+ end
131
+
132
+ it 'has a body that is nil' do
133
+ expect(@node.body).to be_nil
134
+ end
135
+
136
+ it 'finds no nodes in the body' do
137
+ expect(@node.body_nodes([:foo])).to eq []
96
138
  end
97
139
  end
98
140
  end
@@ -100,157 +142,188 @@ end
100
142
  describe SexpExtensions::DefsNode do
101
143
  context 'with no parameters' do
102
144
  before :each do
103
- @node = s(:defs, :obj, :hello, s(:args))
104
- @node.extend(SexpExtensions::DefsNode)
145
+ @node = s(:defs, s(:lvar, :obj), :hello, s(:args))
105
146
  end
147
+
106
148
  it 'has no arg names' do
107
- expect(@node.arg_names).to eq(s())
149
+ expect(@node.arg_names).to eq []
108
150
  end
151
+
109
152
  it 'has no parameter names' do
110
- expect(@node.parameter_names).to eq(s())
153
+ expect(@node.parameter_names).to eq []
111
154
  end
155
+
112
156
  it 'includes outer scope in its full name' do
113
- expect(@node.full_name('Fred')).to eq('Fred#obj.hello')
157
+ expect(@node.full_name('Fred')).to eq 'Fred#obj.hello'
114
158
  end
159
+
115
160
  it 'includes no marker in its full name with empty outer scope' do
116
- expect(@node.full_name('')).to eq('obj.hello')
161
+ expect(@node.full_name('')).to eq 'obj.hello'
117
162
  end
163
+
118
164
  end
119
165
 
120
166
  context 'with 1 parameter' do
121
167
  before :each do
122
- @node = s(:defs, :obj, :hello, s(:args, :param))
123
- @node.extend(SexpExtensions::DefsNode)
168
+ @node = s(:defs, s(:lvar, :obj), :hello,
169
+ s(:args, s(:arg, :param)))
124
170
  end
171
+
125
172
  it 'has 1 arg name' do
126
- expect(@node.arg_names).to eq(s(:param))
173
+ expect(@node.arg_names).to eq [:param]
127
174
  end
175
+
128
176
  it 'has 1 parameter name' do
129
- expect(@node.parameter_names).to eq(s(:param))
177
+ expect(@node.parameter_names).to eq [:param]
130
178
  end
179
+
131
180
  it 'includes outer scope in its full name' do
132
- expect(@node.full_name('Fred')).to eq('Fred#obj.hello')
181
+ expect(@node.full_name('Fred')).to eq 'Fred#obj.hello'
133
182
  end
183
+
134
184
  it 'includes no marker in its full name with empty outer scope' do
135
- expect(@node.full_name('')).to eq('obj.hello')
185
+ expect(@node.full_name('')).to eq 'obj.hello'
136
186
  end
187
+
137
188
  end
138
189
 
139
190
  context 'with a block' do
140
191
  before :each do
141
- @node = s(:defs, :obj, :hello, s(:args, :param, :"&blk"))
142
- @node.extend(SexpExtensions::DefsNode)
192
+ @node = s(:defs, s(:lvar, :obj), :hello,
193
+ s(:args,
194
+ s(:arg, :param),
195
+ s(:blockarg, :blk)))
143
196
  end
197
+
144
198
  it 'has 1 arg name' do
145
- expect(@node.arg_names).to eq(s(:param))
199
+ expect(@node.arg_names).to eq [:param]
146
200
  end
201
+
147
202
  it 'has 2 parameter names' do
148
- expect(@node.parameter_names).to eq(s(:param, :"&blk"))
203
+ expect(@node.parameter_names).to eq [:param, :blk]
149
204
  end
205
+
150
206
  it 'includes outer scope in its full name' do
151
- expect(@node.full_name('Fred')).to eq('Fred#obj.hello')
207
+ expect(@node.full_name('Fred')).to eq 'Fred#obj.hello'
152
208
  end
209
+
153
210
  it 'includes no marker in its full name with empty outer scope' do
154
- expect(@node.full_name('')).to eq('obj.hello')
211
+ expect(@node.full_name('')).to eq 'obj.hello'
155
212
  end
213
+
156
214
  end
157
215
 
158
216
  context 'with 1 defaulted parameter' do
159
217
  before :each do
160
- @node = s(:defs, :obj, :hello, s(:args, s(:lasgn, :param, s(:array))))
161
- @node.extend(SexpExtensions::DefsNode)
218
+ @node = s(:defs, s(:lvar, :obj), :hello,
219
+ s(:args,
220
+ s(:optarg, :param, s(:array))))
162
221
  end
222
+
163
223
  it 'has 1 arg name' do
164
- expect(@node.arg_names).to eq(s(:param))
224
+ expect(@node.arg_names).to eq [:param]
165
225
  end
226
+
166
227
  it 'has 1 parameter name' do
167
- expect(@node.parameter_names).to eq(s(:param))
228
+ expect(@node.parameter_names).to eq [:param]
168
229
  end
230
+
169
231
  it 'includes outer scope in its full name' do
170
- expect(@node.full_name('Fred')).to eq('Fred#obj.hello')
232
+ expect(@node.full_name('Fred')).to eq 'Fred#obj.hello'
171
233
  end
234
+
172
235
  it 'includes no marker in its full name with empty outer scope' do
173
- expect(@node.full_name('')).to eq('obj.hello')
236
+ expect(@node.full_name('')).to eq 'obj.hello'
174
237
  end
238
+
175
239
  end
176
240
 
177
241
  context 'with a body with 2 statements' do
178
242
  before :each do
179
- @node = s(:defs, s(:self), :hello, s(:args), s(:first), s(:second))
180
- @node.extend(SexpExtensions::DefsNode)
243
+ @node = s(:defs, s(:self), :hello, s(:args),
244
+ s(:begin,
245
+ s(:first),
246
+ s(:second)))
181
247
  end
182
248
 
183
249
  it 'has 2 body statements' do
184
- expect(@node.body).to eq(s(s(:first), s(:second)))
250
+ expect(@node.body).to eq s(:begin, s(:first), s(:second))
185
251
  end
186
252
 
187
253
  it 'has a body extended with SexpNode' do
188
254
  b = @node.body
189
- expect((class << b; self; end).included_modules.first).to eq(SexpNode)
255
+ expect(b.class.included_modules.first).to eq SexpNode
190
256
  end
257
+
191
258
  end
259
+
192
260
  end
193
261
 
194
- describe SexpExtensions::CallNode do
262
+ describe SexpExtensions::SendNode do
195
263
  context 'with no parameters' do
196
264
  before :each do
197
- @node = s(:call, nil, :hello)
198
- @node.extend(SexpExtensions::CallNode)
265
+ @node = s(:send, nil, :hello)
199
266
  end
200
- it 'has no parameter names' do
201
- expect(@node.parameter_names).to eq(nil)
267
+
268
+ it 'has no argument names' do
269
+ expect(@node.arg_names).to eq []
202
270
  end
271
+
203
272
  end
204
273
 
205
274
  context 'with 1 literal parameter' do
206
275
  before :each do
207
- @node = s(:call, nil, :hello, s(:lit, :param))
208
- @node.extend(SexpExtensions::CallNode)
276
+ @node = s(:send, nil, :hello, s(:lit, :param))
209
277
  end
278
+
210
279
  it 'has 1 argument name' do
211
- expect(@node.arg_names).to eq([:param])
280
+ expect(@node.arg_names).to eq [:param]
212
281
  end
282
+
213
283
  end
214
284
 
215
285
  context 'with 2 literal parameters' do
216
286
  before :each do
217
- @node = s(:call, nil, :hello, s(:lit, :x), s(:lit, :y))
218
- @node.extend(SexpExtensions::CallNode)
287
+ @node = s(:send, nil, :hello, s(:lit, :x), s(:lit, :y))
219
288
  end
289
+
220
290
  it 'has 2 argument names' do
221
- expect(@node.arg_names).to eq([:x, :y])
291
+ expect(@node.arg_names).to eq [:x, :y]
222
292
  end
293
+
223
294
  end
295
+
224
296
  end
225
297
 
226
- describe SexpExtensions::IterNode do
298
+ describe SexpExtensions::BlockNode do
227
299
  context 'with no parameters' do
228
300
  before :each do
229
- @node = s(:iter, s(), s(:args), s())
230
- @node.extend(SexpExtensions::IterNode)
301
+ @node = s(:block, s(:send, nil, :map), s(:args), nil)
231
302
  end
303
+
232
304
  it 'has no parameter names' do
233
- expect(@node.parameter_names).to eq([])
305
+ expect(@node.parameter_names).to eq []
234
306
  end
307
+
235
308
  end
236
309
 
237
310
  context 'with 1 parameter' do
238
311
  before :each do
239
- @node = s(:iter, s(), s(:args, :param), s())
240
- @node.extend(SexpExtensions::IterNode)
312
+ @node = s(:block, s(:send, nil, :map), s(:args, :param), nil)
241
313
  end
314
+
242
315
  it 'has 1 parameter name' do
243
- expect(@node.parameter_names).to eq(s(:param))
316
+ expect(@node.parameter_names).to eq [:param]
244
317
  end
245
318
  end
246
319
 
247
320
  context 'with 2 parameters' do
248
321
  before :each do
249
- @node = s(:iter, s(), s(:args, :x, :y), s())
250
- @node.extend(SexpExtensions::IterNode)
322
+ @node = s(:block, s(:send, nil, :map), s(:args, :x, :y), nil)
251
323
  end
324
+
252
325
  it 'has 2 parameter names' do
253
- expect(@node.parameter_names).to eq([:x, :y])
326
+ expect(@node.parameter_names).to eq [:x, :y]
254
327
  end
255
328
  end
256
329
  end
@@ -263,49 +336,49 @@ describe SexpExtensions::ModuleNode do
263
336
  end
264
337
 
265
338
  it 'has the correct #name' do
266
- expect(subject.name).to eq(:Fred)
339
+ expect(subject.name).to eq :Fred
267
340
  end
268
341
 
269
342
  it 'has the correct #simple_name' do
270
- expect(subject.simple_name).to eq(:Fred)
343
+ expect(subject.simple_name).to eq :Fred
271
344
  end
272
345
 
273
346
  it 'has the correct #text_name' do
274
- expect(subject.text_name).to eq('Fred')
347
+ expect(subject.text_name).to eq 'Fred'
275
348
  end
276
349
 
277
350
  it 'has a simple full_name' do
278
- expect(subject.full_name('')).to eq('Fred')
351
+ expect(subject.full_name('')).to eq 'Fred'
279
352
  end
353
+
280
354
  it 'has a fq full_name' do
281
- expect(subject.full_name('Blimey::O::Reilly')).to eq('Blimey::O::Reilly::Fred')
355
+ expect(subject.full_name('Blimey::O::Reilly')).to eq 'Blimey::O::Reilly::Fred'
282
356
  end
283
357
  end
284
358
 
285
359
  context 'with a scoped name' do
286
360
  subject do
287
- mod = ast(:module, s(:colon2, s(:const, :Foo), :Bar), nil)
288
- mod
361
+ s(:module, s(:const, s(:const, nil, :Foo), :Bar), nil)
289
362
  end
290
363
 
291
364
  it 'has the correct #name' do
292
- expect(subject.name).to eq(s(:colon2, s(:const, :Foo), :Bar))
365
+ expect(subject.name).to eq s(:const, s(:const, nil, :Foo), :Bar)
293
366
  end
294
367
 
295
368
  it 'has the correct #simple_name' do
296
- expect(subject.simple_name).to eq(:Bar)
369
+ expect(subject.simple_name).to eq :Bar
297
370
  end
298
371
 
299
372
  it 'has the correct #text_name' do
300
- expect(subject.text_name).to eq('Foo::Bar')
373
+ expect(subject.text_name).to eq 'Foo::Bar'
301
374
  end
302
375
 
303
376
  it 'has a simple full_name' do
304
- expect(subject.full_name('')).to eq('Foo::Bar')
377
+ expect(subject.full_name('')).to eq 'Foo::Bar'
305
378
  end
306
379
 
307
380
  it 'has a fq full_name' do
308
- expect(subject.full_name('Blimey::O::Reilly')).to eq('Blimey::O::Reilly::Foo::Bar')
381
+ expect(subject.full_name('Blimey::O::Reilly')).to eq 'Blimey::O::Reilly::Foo::Bar'
309
382
  end
310
383
  end
311
384
  end