reek 1.4.0 → 1.5.0

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