reek 4.4.0 → 4.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/CONTRIBUTING.md +41 -4
  4. data/README.md +15 -3
  5. data/defaults.reek +1 -1
  6. data/docs/Basic-Smell-Options.md +2 -2
  7. data/docs/Code-Smells.md +4 -0
  8. data/docs/How-To-Write-New-Detectors.md +116 -0
  9. data/docs/How-reek-works-internally.md +3 -4
  10. data/docs/Instance-Variable-Assumption.md +134 -0
  11. data/docs/Simulated-Polymorphism.md +1 -1
  12. data/docs/Smell-Suppression.md +6 -6
  13. data/docs/{style-guide.md → Style-Guide.md} +0 -0
  14. data/docs/Unused-Private-Method.md +1 -1
  15. data/docs/YAML-Reports.md +0 -18
  16. data/features/configuration_files/directory_specific_directives.feature +4 -4
  17. data/features/configuration_files/unused_private_method.feature +2 -2
  18. data/features/samples.feature +122 -117
  19. data/features/smells/subclassed_from_core_class.feature +1 -1
  20. data/lib/reek/code_comment.rb +13 -4
  21. data/lib/reek/context/code_context.rb +1 -0
  22. data/lib/reek/examiner.rb +24 -27
  23. data/lib/reek/smells/class_variable.rb +1 -1
  24. data/lib/reek/smells/control_parameter.rb +1 -1
  25. data/lib/reek/smells/data_clump.rb +1 -1
  26. data/lib/reek/smells/duplicate_method_call.rb +1 -1
  27. data/lib/reek/smells/feature_envy.rb +1 -1
  28. data/lib/reek/smells/instance_variable_assumption.rb +1 -1
  29. data/lib/reek/smells/prima_donna_method.rb +1 -1
  30. data/lib/reek/smells/repeated_conditional.rb +1 -1
  31. data/lib/reek/smells/smell_detector.rb +5 -14
  32. data/lib/reek/smells/smell_repository.rb +1 -5
  33. data/lib/reek/smells/smell_warning.rb +6 -8
  34. data/lib/reek/smells/subclassed_from_core_class.rb +1 -1
  35. data/lib/reek/smells/uncommunicative_variable_name.rb +22 -12
  36. data/lib/reek/smells/unused_private_method.rb +1 -1
  37. data/lib/reek/spec.rb +2 -2
  38. data/lib/reek/spec/should_reek_of.rb +12 -8
  39. data/lib/reek/version.rb +1 -1
  40. data/spec/reek/code_comment_spec.rb +13 -5
  41. data/spec/reek/examiner_spec.rb +2 -2
  42. data/spec/reek/smells/attribute_spec.rb +91 -78
  43. data/spec/reek/smells/boolean_parameter_spec.rb +72 -64
  44. data/spec/reek/smells/class_variable_spec.rb +81 -68
  45. data/spec/reek/smells/control_parameter_spec.rb +101 -141
  46. data/spec/reek/smells/data_clump_spec.rb +94 -149
  47. data/spec/reek/smells/duplicate_method_call_spec.rb +98 -85
  48. data/spec/reek/smells/feature_envy_spec.rb +164 -183
  49. data/spec/reek/smells/instance_variable_assumption_spec.rb +51 -147
  50. data/spec/reek/smells/irresponsible_module_spec.rb +153 -170
  51. data/spec/reek/smells/long_parameter_list_spec.rb +44 -88
  52. data/spec/reek/smells/long_yield_list_spec.rb +41 -41
  53. data/spec/reek/smells/manual_dispatch_spec.rb +36 -18
  54. data/spec/reek/smells/module_initialize_spec.rb +31 -33
  55. data/spec/reek/smells/nested_iterators_spec.rb +189 -183
  56. data/spec/reek/smells/nil_check_spec.rb +48 -37
  57. data/spec/reek/smells/prima_donna_method_spec.rb +41 -26
  58. data/spec/reek/smells/repeated_conditional_spec.rb +75 -87
  59. data/spec/reek/smells/smell_warning_spec.rb +7 -0
  60. data/spec/reek/smells/subclassed_from_core_class_spec.rb +37 -112
  61. data/spec/reek/smells/too_many_constants_spec.rb +109 -199
  62. data/spec/reek/smells/too_many_instance_variables_spec.rb +105 -128
  63. data/spec/reek/smells/too_many_methods_spec.rb +38 -62
  64. data/spec/reek/smells/too_many_statements_spec.rb +69 -45
  65. data/spec/reek/smells/uncommunicative_method_name_spec.rb +16 -29
  66. data/spec/reek/smells/uncommunicative_module_name_spec.rb +24 -37
  67. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +55 -60
  68. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +108 -95
  69. data/spec/reek/smells/unused_parameters_spec.rb +73 -49
  70. data/spec/reek/smells/unused_private_method_spec.rb +97 -50
  71. data/spec/reek/smells/utility_function_spec.rb +130 -188
  72. data/spec/reek/spec/should_reek_of_spec.rb +2 -2
  73. metadata +6 -7
  74. data/lib/reek/cli/warning_collector.rb +0 -27
  75. data/spec/reek/cli/warning_collector_spec.rb +0 -25
  76. data/spec/reek/smells/smell_detector_shared.rb +0 -29
@@ -1,208 +1,191 @@
1
1
  require_relative '../../spec_helper'
2
- require_lib 'reek/context/code_context'
3
2
  require_lib 'reek/smells/irresponsible_module'
4
- require_relative 'smell_detector_shared'
5
3
 
6
4
  RSpec.describe Reek::Smells::IrresponsibleModule do
7
- it 'reports a class without a comment' do
8
- src = 'class BadClass; end'
9
- expect(src).to reek_of :IrresponsibleModule,
10
- lines: [1],
11
- message: 'has no descriptive comment'
12
- end
13
-
14
- it 'reports a module without a comment' do
15
- src = 'module BadClass; end'
16
- expect(src).to reek_of(:IrresponsibleModule, context: 'BadClass')
17
- end
18
-
19
- it 'does not report re-opened modules' do
5
+ it 'reports the right values' do
20
6
  src = <<-EOS
21
- # Abstract base class
22
- class C; end
23
-
24
- class C; def foo; end; end
7
+ class Alfa
8
+ end
25
9
  EOS
26
- expect(src).not_to reek_of(:IrresponsibleModule)
27
- end
28
10
 
29
- it 'does not report a class having a comment' do
30
- src = <<-EOS
31
- # test class
32
- class Responsible; end
33
- EOS
34
- expect(src).not_to reek_of(:IrresponsibleModule)
11
+ expect(src).to reek_of(:IrresponsibleModule,
12
+ lines: [1],
13
+ context: 'Alfa',
14
+ message: 'has no descriptive comment',
15
+ source: 'string')
35
16
  end
36
17
 
37
- it 'reports a class with an empty comment' do
18
+ it 'does count all occurences' do
38
19
  src = <<-EOS
39
- #
40
- #
41
- #
42
- class BadClass; end
20
+ class Alfa
21
+ # Method is necessary because we don't count empty classes.
22
+ def bravo; end
23
+ class Charlie
24
+ end
25
+ end
43
26
  EOS
44
- expect(src).to reek_of(:IrresponsibleModule, context: 'BadClass')
27
+
28
+ expect(src).to reek_of(:IrresponsibleModule,
29
+ lines: [1],
30
+ context: 'Alfa')
31
+ expect(src).to reek_of(:IrresponsibleModule,
32
+ lines: [4],
33
+ context: 'Alfa::Charlie')
45
34
  end
46
35
 
47
- it 'reports a class with a preceding comment with intermittent material' do
48
- src = <<-EOS
49
- # This is a valid comment
36
+ %w(class module).each do |scope|
37
+ it "reports a #{scope} without a comment" do
38
+ src = <<-EOS
39
+ #{scope} Alfa
40
+ end
41
+ EOS
50
42
 
51
- require 'foo'
43
+ expect(src).to reek_of(:IrresponsibleModule)
44
+ end
52
45
 
53
- class Bar; end
54
- EOS
55
- expect(src).to reek_of(:IrresponsibleModule, context: 'Bar')
56
- end
46
+ it "does not report re-opened #{scope}" do
47
+ src = <<-EOS
48
+ # Abstract base
49
+ #{scope} Alfa; end
57
50
 
58
- it 'reports a class with a trailing comment' do
59
- src = <<-EOS
60
- class BadClass
61
- end # end BadClass
62
- EOS
63
- expect(src).to reek_of(:IrresponsibleModule, context: 'BadClass')
64
- end
51
+ #{scope} Alfa; def bravo; end; end
52
+ EOS
65
53
 
66
- it 'reports a fully qualified class name correctly' do
67
- src = 'class Foo::Bar; end'
68
- expect(src).to reek_of(:IrresponsibleModule, context: 'Foo::Bar')
69
- end
54
+ expect(src).not_to reek_of(:IrresponsibleModule)
55
+ end
70
56
 
71
- it 'does not report modules used only as namespaces' do
72
- src = <<-EOS
73
- module Foo
74
- # Describes Bar
75
- class Bar
76
- def baz
57
+ it "does not report a #{scope} having a comment" do
58
+ src = <<-EOS
59
+ # Do not report me
60
+ #{scope} Alfa; end
61
+ EOS
62
+
63
+ expect(src).not_to reek_of(:IrresponsibleModule)
64
+ end
65
+
66
+ it "reports a #{scope} with an empty comment" do
67
+ src = <<-EOS
68
+ #
69
+ #
70
+ #
71
+ #{scope} Alfa; end
72
+ EOS
73
+
74
+ expect(src).to reek_of(:IrresponsibleModule)
75
+ end
76
+
77
+ it "reports a #{scope} with a preceding comment with intermittent material" do
78
+ src = <<-EOS
79
+ # This is a valid comment
80
+
81
+ require 'alfa'
82
+
83
+ #{scope} Bravo
84
+ end
85
+ EOS
86
+
87
+ expect(src).to reek_of(:IrresponsibleModule)
88
+ end
89
+
90
+ it "reports a #{scope} with only a trailing comment" do
91
+ src = <<-EOS
92
+ #{scope} Alfa
93
+ end # end scope
94
+ EOS
95
+
96
+ expect(src).to reek_of(:IrresponsibleModule)
97
+ end
98
+
99
+ it "does not report #{scope} used only as namespaces" do
100
+ src = <<-EOS
101
+ #{scope} Alfa
102
+ # Describes Bravo
103
+ #{scope} Bravo
104
+ def charlie
105
+ end
77
106
  end
78
107
  end
79
- end
80
- EOS
81
- expect(src).not_to reek_of(:IrresponsibleModule)
82
- end
108
+ EOS
83
109
 
84
- it 'does not report classes used only as namespaces' do
85
- src = <<-EOS
86
- class Foo
87
- # Describes Bar
88
- module Bar
89
- def qux
110
+ expect(src).not_to reek_of(:IrresponsibleModule)
111
+ end
112
+
113
+ it "reports #{scope} that have both a nested #{scope} and methods" do
114
+ src = <<-EOS
115
+ #{scope} Alfa
116
+ def bravo
90
117
  end
91
- end
92
- end
93
- EOS
94
- expect(src).not_to reek_of(:IrresponsibleModule)
95
- end
96
118
 
97
- it 'reports modules that have both nested modules and methods' do
98
- src = <<-EOS
99
- module Foo
100
- def foofoo
101
- end
102
- # Describes Bar
103
- module Bar
119
+ # Describes Charlie
120
+ #{scope} Charlie
121
+ end
104
122
  end
105
- end
106
- EOS
107
- expect(src).to reek_of(:IrresponsibleModule, context: 'Foo')
108
- end
123
+ EOS
109
124
 
110
- it 'reports modules that have both nested modules and singleton methods' do
111
- src = <<-EOS
112
- module Foo
113
- def self.foofoo
114
- end
115
- # Describes Bar
116
- module Bar
117
- end
118
- end
119
- EOS
120
- expect(src).to reek_of(:IrresponsibleModule, context: 'Foo')
121
- end
125
+ expect(src).to reek_of(:IrresponsibleModule, context: 'Alfa')
126
+ end
122
127
 
123
- it 'reports modules that have both nested modules and methods on the singleton class' do
124
- src = <<-EOS
125
- module Foo
126
- class << self
127
- def foofoo
128
+ it "reports #{scope} that has both a nested #{scope} and singleton methods" do
129
+ src = <<-EOS
130
+ #{scope} Alfa
131
+ def self.bravo
128
132
  end
129
- end
130
- # Describes Bar
131
- module Bar
132
- end
133
- end
134
- EOS
135
- expect(src).to reek_of(:IrresponsibleModule, context: 'Foo')
136
- end
137
133
 
138
- it 'does not report namespace modules that have a nested class through assignment' do
139
- src = <<-EOS
140
- module Qux
141
- # Foo is responsible
142
- Foo = Class.new Bar do
143
- def quux; end
134
+ # Describes Charlie
135
+ #{scope} Charlie
136
+ end
144
137
  end
145
- end
146
- EOS
147
- expect(src).not_to reek_of(:IrresponsibleModule)
148
- end
138
+ EOS
149
139
 
150
- it 'reports classes that have a defined superclass' do
151
- src = <<-EOS
152
- class Foo < Bar; end
153
- EOS
154
- expect(src).to reek_of(:IrresponsibleModule, context: 'Foo')
155
- end
140
+ expect(src).to reek_of(:IrresponsibleModule, context: 'Alfa')
141
+ end
156
142
 
157
- it 'reports classes defined through assignment' do
158
- src = <<-EOS
159
- # Qux is responsible, but Foo is not
160
- module Qux
161
- Foo = Class.new Bar
162
- end
163
- EOS
164
- expect(src).to reek_of(:IrresponsibleModule, context: 'Qux::Foo')
165
- end
166
-
167
- it 'reports top level classes defined through assignment' do
168
- src = <<-EOS
169
- Foo = Class.new Bar
170
- EOS
171
- expect(src).to reek_of(:IrresponsibleModule, context: 'Foo')
172
- end
143
+ it "does not report a namespace #{scope} that has a nested class through assignment" do
144
+ src = <<-EOS
145
+ #{scope} Alfa
146
+ # Bravo is responsible
147
+ Bravo = Class.new Charlie do
148
+ def delta; end
149
+ end
150
+ end
151
+ EOS
173
152
 
174
- it 'reports structs defined through assignment' do
175
- src = <<-EOS
176
- # Qux is responsible, but Foo is not
177
- module Qux
178
- Foo = Struct.new(:x, :y)
179
- end
180
- EOS
181
- expect(src).to reek_of(:IrresponsibleModule, context: 'Qux::Foo')
182
- end
153
+ expect(src).not_to reek_of(:IrresponsibleModule)
154
+ end
183
155
 
184
- it 'reports top level structs defined through assignment' do
185
- src = <<-EOS
186
- Foo = Struct.new(:x, :y)
187
- EOS
188
- expect(src).to reek_of(:IrresponsibleModule, context: 'Foo')
189
- end
156
+ it "reports a #{scope} defined through assignment" do
157
+ src = <<-EOS
158
+ # Alfa is responsible, but Bravo is not
159
+ #{scope} Alfa
160
+ Bravo = Class.new Charlie # Only "class" is supposed to reek here.
161
+ end
162
+ EOS
190
163
 
191
- it 'does not report constants that are not classes' do
192
- src = <<-EOS
193
- module Qux
194
- Foo = 23
195
- Bar = Hash.new
196
- Quuz = 'foo'.freeze
197
- Zyxxy = Class.new.new
198
- end
199
- EOS
200
- expect(src).not_to reek_of(:IrresponsibleModule)
201
- end
164
+ expect(src).to reek_of(:IrresponsibleModule, context: 'Alfa::Bravo')
165
+ end
202
166
 
203
- context 'when a smell is reported' do
204
- let(:detector) { build(:smell_detector, smell_type: :IrresponsibleModule) }
167
+ it 'reports structs defined through assignment' do
168
+ src = <<-EOS
169
+ # Alfa is responsible, but Bravo is not
170
+ #{scope} Alfa
171
+ Bravo = Struct.new(:charlie)
172
+ end
173
+ EOS
174
+
175
+ expect(src).to reek_of(:IrresponsibleModule, context: 'Alfa::Bravo')
176
+ end
177
+
178
+ it 'does not report constants that are not classes' do
179
+ src = <<-EOS
180
+ #{scope} Alfa
181
+ Bravo = 23
182
+ Charlie = Hash.new
183
+ Delta = ''.freeze
184
+ Echo = Class.new.new
185
+ end
186
+ EOS
205
187
 
206
- it_should_behave_like 'SmellDetector'
188
+ expect(src).not_to reek_of(:IrresponsibleModule)
189
+ end
207
190
  end
208
191
  end
@@ -1,107 +1,63 @@
1
1
  require_relative '../../spec_helper'
2
- require_lib 'reek/context/code_context'
3
2
  require_lib 'reek/smells/long_parameter_list'
4
- require_relative 'smell_detector_shared'
5
3
 
6
4
  RSpec.describe Reek::Smells::LongParameterList do
7
- context 'for methods with few parameters' do
8
- it 'should report nothing for no parameters' do
9
- expect('def simple; f(3);true; end').not_to reek_of(:LongParameterList)
10
- end
11
-
12
- it 'should report nothing for 1 parameter' do
13
- expect('def simple(yep) f(3);true end').not_to reek_of(:LongParameterList)
14
- end
15
-
16
- it 'should report nothing for 2 parameters' do
17
- expect('def simple(yep,zero) f(3);true end').not_to reek_of(:LongParameterList)
18
- end
19
-
20
- it 'should not count an optional block' do
21
- src = 'def simple(alpha, yep, zero, &opt) f(3); true end'
22
- expect(src).not_to reek_of(:LongParameterList)
23
- end
24
-
25
- it 'should not report inner block with too many parameters' do
26
- src = '
27
- def simple(yep,zero)
28
- m[3]; rand(34); f.each { |arga, argb, argc, argd| true}
5
+ it 'reports the right values' do
6
+ src = <<-EOS
7
+ class Alfa
8
+ def bravo(charlie, delta, echo, foxtrot)
29
9
  end
30
- '
31
- expect(src).not_to reek_of(:LongParameterList)
32
- end
33
-
34
- describe 'and default values' do
35
- it 'should report nothing for 1 parameter' do
36
- expect('def simple(zero=nil) f(3);false end').not_to reek_of(:LongParameterList)
37
10
  end
11
+ EOS
12
+
13
+ expect(src).to reek_of(:LongParameterList,
14
+ lines: [2],
15
+ context: 'Alfa#bravo',
16
+ message: 'has 4 parameters',
17
+ source: 'string',
18
+ count: 4)
19
+ end
38
20
 
39
- it 'should report nothing for 2 parameters with 1 default' do
40
- source = 'def simple(yep, zero=nil) f(3); false end'
41
- expect(source).not_to reek_of(:LongParameterList)
42
- end
21
+ it 'does count all occurences' do
22
+ src = <<-EOS
23
+ class Alfa
24
+ def bravo(charlie, delta, echo, foxtrot)
25
+ end
43
26
 
44
- it 'should report nothing for 2 defaulted parameters' do
45
- source = 'def simple(yep=4, zero=nil) f(3); false end'
46
- expect(source).not_to reek_of(:LongParameterList)
27
+ def golf(hotel, india, juliett, kilo)
28
+ end
47
29
  end
48
- end
30
+ EOS
31
+
32
+ expect(src).to reek_of(:LongParameterList,
33
+ lines: [2],
34
+ context: 'Alfa#bravo')
35
+ expect(src).to reek_of(:LongParameterList,
36
+ lines: [5],
37
+ context: 'Alfa#golf')
49
38
  end
50
39
 
51
- describe 'for methods with too many parameters' do
52
- it 'should report 4 parameters' do
53
- src = 'def simple(arga, argb, argc, argd) f(3);true end'
54
- expect(src).to reek_of(:LongParameterList, count: 4)
55
- end
40
+ it 'reports nothing for 3 parameters' do
41
+ expect('def alfa(bravo, charlie, delta); end').not_to reek_of(:LongParameterList)
42
+ end
56
43
 
57
- it 'should report 8 parameters' do
58
- src = 'def simple(arga, argb, argc, argd,arge, argf, argg, argh) f(3);true end'
59
- expect(src).to reek_of(:LongParameterList, count: 8)
60
- end
44
+ it 'does not count an optional block' do
45
+ src = 'def alfa(bravo, charlie, delta, &block); end'
46
+ expect(src).not_to reek_of(:LongParameterList)
47
+ end
61
48
 
62
- describe 'and default values' do
63
- it 'should report 3 with 1 defaulted' do
64
- src = 'def simple(polly, queue, yep, zero=nil) f(3);false end'
65
- expect(src).to reek_of(:LongParameterList, count: 4)
49
+ it 'does not report inner block with too many parameters' do
50
+ src = <<-EOS
51
+ def alfa(bravo)
52
+ bravo.each { |charlie, delta, echo, foxtrot| }
66
53
  end
54
+ EOS
67
55
 
68
- it 'should report with 3 defaulted' do
69
- src = 'def simple(aarg, polly=2, yep=:truth, zero=nil) f(3);false end'
70
- expect(src).to reek_of(:LongParameterList, count: 4)
71
- end
72
- end
56
+ expect(src).not_to reek_of(:LongParameterList)
73
57
  end
74
- end
75
-
76
- RSpec.describe Reek::Smells::LongParameterList do
77
- let(:detector) { build(:smell_detector, smell_type: :LongParameterList) }
78
-
79
- it_should_behave_like 'SmellDetector'
80
-
81
- context 'when a smell is reported' do
82
- let(:warning) do
83
- src = <<-EOS
84
- def badguy(arga, argb, argc, argd)
85
- f(3)
86
- true
87
- end
88
- EOS
89
- ctx = Reek::Context::CodeContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
90
- detector.sniff(ctx).first
91
- end
92
-
93
- it_should_behave_like 'common fields set correctly'
94
-
95
- it 'reports the number of parameters' do
96
- expect(warning.parameters[:count]).to eq(4)
97
- end
98
-
99
- it 'reports the line number of the method' do
100
- expect(warning.lines).to eq([1])
101
- end
102
58
 
103
- it 'has the right message' do
104
- expect(warning.message).to eq('has 4 parameters')
105
- end
59
+ it 'reports 4 parameters with default parameters' do
60
+ src = 'def alfa(bravo = 1, charlie = 2, delta = 3, echo = 4); end'
61
+ expect(src).to reek_of(:LongParameterList)
106
62
  end
107
63
  end