reek 4.3.0 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5e3c2e9cc70f29c322ad9284d8412aafc7d1dba9
4
- data.tar.gz: b2bbee88bc846020a28cb27214d0ea09a1fbb1c7
3
+ metadata.gz: 9e0d256e7194e6839716a3817b6fe951985f4fc8
4
+ data.tar.gz: ec2e207fe63cd0c8cd5b48071e660bd83ccb1cc6
5
5
  SHA512:
6
- metadata.gz: cc8a77b31dcbc0be82506493b24654f299cd21c5f8ecf2484d962a73363072c372d09d8d9e58223197c6fb9934a0de0f42481bf131146297d3f653194219110c
7
- data.tar.gz: 5fca779e7aa91f5a7e6b943fd3923f4cada5a50364e3952ed30def4a16dd112b3267bcca1fde743e627008cc534c9c82ba223dd4a4f8502bfb346a7b2da5154f
6
+ metadata.gz: 6a2f747bdbded9c2610d934c23b07a72b001a93a9a9ed99d20b9e2bdea7c6ed5e7e667c8e05713b1e77e148294fb8e4cd34d606e197829744491db395a0c964b
7
+ data.tar.gz: 16d71aee67557e3f4d78cba1d45c8452032ccf76148c57b0c50650d0bff4f8fbcb4ecc9020df33a88746a80cce65235231e5b9a4f610e187a47a43baba27b1bf
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Change log
2
2
 
3
+ ## 4.4.0 (2016-08-24)
4
+
5
+ * (waldyr) Add ignored nodes parameter to local_nodes
6
+ * (waldyr) Add Instance Variable Assumption smell detector
7
+ * (waldyr) Remove memoized instance variables from accounting of TooManyInstanceVariables smell
8
+
3
9
  ## 4.3.0 (2016-08-23)
4
10
 
5
11
  * (backus) Add ManualDispatch smell.
data/CONTRIBUTING.md CHANGED
@@ -105,6 +105,9 @@ git rebase -i master
105
105
  # squash squash squash
106
106
  git push -f origin
107
107
  ```
108
+ ## Failing Cucumber Scenarios
109
+
110
+ If there is a failing scenario and you can not figure out why it is failing, just run the failing scenario: `bundle exec cucumber features/failing_scenario.feature:line`. By doing so Aruba will leave its set up in the `tmp/aruba` directory. You can then `cd` into this directory and run Reek the same way the cucumber scenario actually ran it. This way you can debug scenario failures that can be very opaque sometimes.
108
111
 
109
112
  ## Versioning policy
110
113
 
data/README.md CHANGED
@@ -510,6 +510,8 @@ Just add this to your configuration file:
510
510
  max_allowed_nesting: 2
511
511
  UnusedPrivateMethod:
512
512
  enabled: false
513
+ InstanceVariableAssumption:
514
+ enabled: false
513
515
  "app/helpers":
514
516
  IrresponsibleModule:
515
517
  enabled: false
data/defaults.reek CHANGED
@@ -24,6 +24,9 @@ DuplicateMethodCall:
24
24
  FeatureEnvy:
25
25
  enabled: true
26
26
  exclude: []
27
+ InstanceVariableAssumption:
28
+ enabled: true
29
+ exclude: []
27
30
  IrresponsibleModule:
28
31
  enabled: true
29
32
  exclude: []
@@ -49,10 +49,12 @@ Feature: Directory directives
49
49
  When I run `reek -c web_app/config.reek web_app/`
50
50
  Then it reports:
51
51
  """
52
+ web_app/app/controllers/users_controller.rb -- 1 warning:
53
+ [1]:InstanceVariableAssumption: UsersController assumes too much for instance variable @user [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
52
54
  web_app/app/models/user.rb -- 2 warnings:
53
55
  [1]:IrresponsibleModule: User has no descriptive comment [https://github.com/troessner/reek/blob/master/docs/Irresponsible-Module.md]
54
56
  [2]:UnusedParameters: User#logged_in_with_role has unused parameter 'r' [https://github.com/troessner/reek/blob/master/docs/Unused-Parameters.md]
55
- 2 total warnings
57
+ 3 total warnings
56
58
  """
57
59
 
58
60
  Scenario: Ignore trailing slashes
@@ -118,12 +120,13 @@ Feature: Directory directives
118
120
  When I run `reek -c web_app/config.reek web_app/`
119
121
  Then it reports:
120
122
  """
121
- web_app/app/controllers/users_controller.rb -- 2 warnings:
123
+ web_app/app/controllers/users_controller.rb -- 3 warnings:
124
+ [1]:InstanceVariableAssumption: UsersController assumes too much for instance variable @user [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
122
125
  [1]:IrresponsibleModule: UsersController has no descriptive comment [https://github.com/troessner/reek/blob/master/docs/Irresponsible-Module.md]
123
126
  [4]:NestedIterators: UsersController#show contains iterators nested 2 deep [https://github.com/troessner/reek/blob/master/docs/Nested-Iterators.md]
124
127
  web_app/app/models/user.rb -- 1 warning:
125
128
  [2]:UnusedParameters: User#logged_in_with_role has unused parameter 'r' [https://github.com/troessner/reek/blob/master/docs/Unused-Parameters.md]
126
- 3 total warnings
129
+ 4 total warnings
127
130
  """
128
131
 
129
132
  Scenario: Use the default directive if there is no directory directive
@@ -163,11 +166,13 @@ Feature: Directory directives
163
166
  When I run `reek -c config.reek other/ web_app/`
164
167
  Then it reports:
165
168
  """
166
- other/projects_controller.rb -- 1 warning:
169
+ other/projects_controller.rb -- 2 warnings:
170
+ [1]:InstanceVariableAssumption: ProjectController assumes too much for instance variable @project [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
167
171
  [4]:NestedIterators: ProjectController#show contains iterators nested 2 deep [https://github.com/troessner/reek/blob/master/docs/Nested-Iterators.md]
168
- web_app/app/controllers/users_controller.rb -- 1 warning:
172
+ web_app/app/controllers/users_controller.rb -- 2 warnings:
173
+ [1]:InstanceVariableAssumption: UsersController assumes too much for instance variable @user [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
169
174
  [1]:IrresponsibleModule: UsersController has no descriptive comment [https://github.com/troessner/reek/blob/master/docs/Irresponsible-Module.md]
170
- 2 total warnings
175
+ 4 total warnings
171
176
  """
172
177
 
173
178
  Scenario: Abort on non-existent smell type in directory directive
@@ -11,7 +11,7 @@ Feature: Basic smell detection
11
11
  Then the exit status indicates smells
12
12
  And it reports:
13
13
  """
14
- inline.rb -- 48 warnings:
14
+ inline.rb -- 51 warnings:
15
15
  BooleanParameter: Inline::C#parse_signature has boolean parameter 'raw' [https://github.com/troessner/reek/blob/master/docs/Boolean-Parameter.md]
16
16
  ClassVariable: Inline declares the class variable @@directory [https://github.com/troessner/reek/blob/master/docs/Class-Variable.md]
17
17
  ClassVariable: Inline declares the class variable @@rootdir [https://github.com/troessner/reek/blob/master/docs/Class-Variable.md]
@@ -32,6 +32,9 @@ Feature: Basic smell detection
32
32
  DuplicateMethodCall: Inline::C#initialize calls stack.empty? 2 times [https://github.com/troessner/reek/blob/master/docs/Duplicate-Method-Call.md]
33
33
  DuplicateMethodCall: Module#inline calls Inline.const_get(lang) 2 times [https://github.com/troessner/reek/blob/master/docs/Duplicate-Method-Call.md]
34
34
  DuplicateMethodCall: Module#inline calls options[:testing] 2 times [https://github.com/troessner/reek/blob/master/docs/Duplicate-Method-Call.md]
35
+ InstanceVariableAssumption: Inline::C assumes too much for instance variable @module_name [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
36
+ InstanceVariableAssumption: Inline::C assumes too much for instance variable @so_name [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
37
+ InstanceVariableAssumption: Inline::C assumes too much for instance variable @types [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
35
38
  IrresponsibleModule: CompilationError has no descriptive comment [https://github.com/troessner/reek/blob/master/docs/Irresponsible-Module.md]
36
39
  IrresponsibleModule: Dir has no descriptive comment [https://github.com/troessner/reek/blob/master/docs/Irresponsible-Module.md]
37
40
  IrresponsibleModule: File has no descriptive comment [https://github.com/troessner/reek/blob/master/docs/Irresponsible-Module.md]
@@ -60,7 +63,7 @@ Feature: Basic smell detection
60
63
  UncommunicativeVariableName: Inline::C#module_name has the variable name 'x' [https://github.com/troessner/reek/blob/master/docs/Uncommunicative-Variable-Name.md]
61
64
  UncommunicativeVariableName: Inline::C#parse_signature has the variable name 'x' [https://github.com/troessner/reek/blob/master/docs/Uncommunicative-Variable-Name.md]
62
65
  UtilityFunction: Inline::C#strip_comments doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/master/docs/Utility-Function.md]
63
- optparse.rb -- 124 warnings:
66
+ optparse.rb -- 126 warnings:
64
67
  Attribute: OptionParser#banner is a writable attribute [https://github.com/troessner/reek/blob/master/docs/Attribute.md]
65
68
  Attribute: OptionParser#default_argv is a writable attribute [https://github.com/troessner/reek/blob/master/docs/Attribute.md]
66
69
  Attribute: OptionParser#program_name is a writable attribute [https://github.com/troessner/reek/blob/master/docs/Attribute.md]
@@ -115,6 +118,8 @@ Feature: Basic smell detection
115
118
  FeatureEnvy: OptionParser::List#accept refers to pat more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/master/docs/Feature-Envy.md]
116
119
  FeatureEnvy: OptionParser::List#add_banner refers to opt more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/master/docs/Feature-Envy.md]
117
120
  FeatureEnvy: OptionParser::List#summarize refers to opt more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/master/docs/Feature-Envy.md]
121
+ InstanceVariableAssumption: OptionParser assumes too much for instance variable @release [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
122
+ InstanceVariableAssumption: OptionParser assumes too much for instance variable @version [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
118
123
  LongParameterList: OptionParser#complete has 4 parameters [https://github.com/troessner/reek/blob/master/docs/Long-Parameter-List.md]
119
124
  LongParameterList: OptionParser#summarize has 4 parameters [https://github.com/troessner/reek/blob/master/docs/Long-Parameter-List.md]
120
125
  LongParameterList: OptionParser::List#complete has 4 parameters [https://github.com/troessner/reek/blob/master/docs/Long-Parameter-List.md]
@@ -185,7 +190,7 @@ Feature: Basic smell detection
185
190
  UnusedParameters: OptionParser::Completion#convert has unused parameter 'opt' [https://github.com/troessner/reek/blob/master/docs/Unused-Parameters.md]
186
191
  UnusedParameters: OptionParser::Switch::NoArgument#parse has unused parameter 'argv' [https://github.com/troessner/reek/blob/master/docs/Unused-Parameters.md]
187
192
  UnusedParameters: OptionParser::Switch::OptionalArgument#parse has unused parameter 'argv' [https://github.com/troessner/reek/blob/master/docs/Unused-Parameters.md]
188
- redcloth.rb -- 105 warnings:
193
+ redcloth.rb -- 110 warnings:
189
194
  Attribute: RedCloth#filter_html is a writable attribute [https://github.com/troessner/reek/blob/master/docs/Attribute.md]
190
195
  Attribute: RedCloth#filter_styles is a writable attribute [https://github.com/troessner/reek/blob/master/docs/Attribute.md]
191
196
  Attribute: RedCloth#hard_breaks is a writable attribute [https://github.com/troessner/reek/blob/master/docs/Attribute.md]
@@ -220,6 +225,11 @@ Feature: Basic smell detection
220
225
  FeatureEnvy: RedCloth#blocks refers to blk more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/master/docs/Feature-Envy.md]
221
226
  FeatureEnvy: RedCloth#clean_white_space refers to text more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/master/docs/Feature-Envy.md]
222
227
  FeatureEnvy: RedCloth#pba refers to text more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/master/docs/Feature-Envy.md]
228
+ InstanceVariableAssumption: RedCloth assumes too much for instance variable @lite_mode [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
229
+ InstanceVariableAssumption: RedCloth assumes too much for instance variable @pre_list [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
230
+ InstanceVariableAssumption: RedCloth assumes too much for instance variable @rules [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
231
+ InstanceVariableAssumption: RedCloth assumes too much for instance variable @shelf [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
232
+ InstanceVariableAssumption: RedCloth assumes too much for instance variable @urlrefs [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
223
233
  LongParameterList: RedCloth#textile_bq has 4 parameters [https://github.com/troessner/reek/blob/master/docs/Long-Parameter-List.md]
224
234
  LongParameterList: RedCloth#textile_fn_ has 5 parameters [https://github.com/troessner/reek/blob/master/docs/Long-Parameter-List.md]
225
235
  LongParameterList: RedCloth#textile_p has 4 parameters [https://github.com/troessner/reek/blob/master/docs/Long-Parameter-List.md]
@@ -291,5 +301,5 @@ Feature: Basic smell detection
291
301
  UtilityFunction: RedCloth#lT doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/master/docs/Utility-Function.md]
292
302
  UtilityFunction: RedCloth#no_textile doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/master/docs/Utility-Function.md]
293
303
  UtilityFunction: RedCloth#v_align doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/master/docs/Utility-Function.md]
294
- 277 total warnings
304
+ 287 total warnings
295
305
  """
@@ -68,8 +68,9 @@ module Reek
68
68
  # @param type [Symbol] the type of the nodes we are looking for, e.g. :defs.
69
69
  # @yield block that is executed for every node.
70
70
  #
71
- def local_nodes(type, &blk)
72
- each_node(type, [:casgn, :class, :module], &blk)
71
+ def local_nodes(type, ignored = [], &blk)
72
+ ignored += [:casgn, :class, :module]
73
+ each_node(type, ignored, &blk)
73
74
  end
74
75
 
75
76
  # Iterate over `self` and child contexts.
data/lib/reek/smells.rb CHANGED
@@ -7,6 +7,7 @@ require_relative 'smells/data_clump'
7
7
  require_relative 'smells/duplicate_method_call'
8
8
  require_relative 'smells/feature_envy'
9
9
  require_relative 'smells/irresponsible_module'
10
+ require_relative 'smells/instance_variable_assumption'
10
11
  require_relative 'smells/long_parameter_list'
11
12
  require_relative 'smells/long_yield_list'
12
13
  require_relative 'smells/manual_dispatch'
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'smell_detector'
3
+ require_relative 'smell_warning'
4
+
5
+ module Reek
6
+ module Smells
7
+ #
8
+ # The +InstanceVariableAssumption+ class is responsible for
9
+ # detecting directly access of instance variables in a class
10
+ # that does not define them in its initialize method.
11
+ #
12
+ class InstanceVariableAssumption < SmellDetector
13
+ def self.contexts
14
+ [:class]
15
+ end
16
+
17
+ # Checks +klass+ for instance
18
+ # variables assumptions.
19
+ #
20
+ # @return [Array<SmellWarning>]
21
+ #
22
+ def sniff(ctx)
23
+ method_expressions = ctx.node_instance_methods
24
+
25
+ assumptions = (variables_from_context(method_expressions) -
26
+ variables_from_initialize(method_expressions)).uniq
27
+
28
+ assumptions.map do |assumption|
29
+ build_smell_warning(ctx, assumption)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def build_smell_warning(ctx, assumption)
36
+ message = "assumes too much for instance variable #{assumption}"
37
+
38
+ smell_warning(
39
+ context: ctx,
40
+ lines: [ctx.exp.line],
41
+ message: message,
42
+ parameters: { assumption: assumption })
43
+ end
44
+
45
+ # :reek:UtilityFunction
46
+ def variables_from_initialize(instance_methods)
47
+ initialize_exp = instance_methods.detect do |method|
48
+ method.name == :initialize
49
+ end
50
+
51
+ return [] unless initialize_exp
52
+
53
+ initialize_exp.each_node(:ivasgn).map(&:name)
54
+ end
55
+
56
+ def variables_from_context(instance_methods)
57
+ instance_methods.map do |method|
58
+ method.find_nodes(assumption_nodes, ignored_nodes).map(&:name)
59
+ end.flatten
60
+ end
61
+
62
+ def assumption_nodes
63
+ [:ivar]
64
+ end
65
+
66
+ def ignored_nodes
67
+ [:or_asgn]
68
+ end
69
+ end
70
+ end
71
+ end
@@ -35,7 +35,8 @@ module Reek
35
35
  #
36
36
  def sniff(ctx)
37
37
  max_allowed_ivars = value(MAX_ALLOWED_IVARS_KEY, ctx)
38
- count = ctx.local_nodes(:ivasgn).map { |ivasgn| ivasgn.children.first }.uniq.length
38
+ variables = ctx.local_nodes(:ivasgn, [:or_asgn]).map(&:name)
39
+ count = variables.uniq.size
39
40
  return [] if count <= max_allowed_ivars
40
41
  [smell_warning(
41
42
  context: ctx,
data/lib/reek/version.rb CHANGED
@@ -7,6 +7,6 @@ module Reek
7
7
  # @public
8
8
  module Version
9
9
  # @public
10
- STRING = '4.3.0'.freeze
10
+ STRING = '4.4.0'.freeze
11
11
  end
12
12
  end
@@ -0,0 +1,195 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ require_lib 'reek/smells/instance_variable_assumption'
4
+
5
+ RSpec.describe Reek::Smells::InstanceVariableAssumption do
6
+ describe 'warning' do
7
+ context 'smell line' do
8
+ it 'should report the lines' do
9
+ src = <<-EOS
10
+ class Dummy
11
+ def test
12
+ @a
13
+ end
14
+ end
15
+ EOS
16
+
17
+ expect(src).to reek_of(:InstanceVariableAssumption, lines: [1])
18
+ end
19
+ end
20
+
21
+ context 'smell parameters' do
22
+ it 'should report the lines' do
23
+ src = <<-EOS
24
+ class Dummy
25
+ def test
26
+ @a
27
+ end
28
+ end
29
+ EOS
30
+
31
+ expect(src).to reek_of(:InstanceVariableAssumption, assumption: :@a)
32
+ end
33
+ end
34
+
35
+ context 'smell context' do
36
+ it 'should report the context' do
37
+ src = <<-EOS
38
+ class Dummy
39
+ def test
40
+ @a
41
+ end
42
+ end
43
+ EOS
44
+
45
+ expect(src).to reek_of(:InstanceVariableAssumption, context: 'Dummy')
46
+ end
47
+ end
48
+
49
+ context 'smell message' do
50
+ it 'should report the ivars in the message' do
51
+ message_a = 'assumes too much for instance variable @a'
52
+ message_b = 'assumes too much for instance variable @b'
53
+
54
+ src = <<-EOS
55
+ class Dummy
56
+ def test
57
+ [@a, @b]
58
+ end
59
+ end
60
+ EOS
61
+
62
+ expect(src).to reek_of(:InstanceVariableAssumption, message: message_a)
63
+ expect(src).to reek_of(:InstanceVariableAssumption, message: message_b)
64
+ end
65
+
66
+ it 'should report each ivar once' do
67
+ message_a = 'assumes too much for instance variable @a'
68
+ message_b = 'assumes too much for instance variable @b'
69
+ message_c = 'assumes too much for instance variable @c'
70
+
71
+ src = <<-EOS
72
+ class Dummy
73
+ def test
74
+ [@a, @a, @b, @c]
75
+ end
76
+
77
+ def retest
78
+ @c
79
+ end
80
+ end
81
+ EOS
82
+
83
+ expect(src).to reek_of(:InstanceVariableAssumption, message: message_a)
84
+ expect(src).to reek_of(:InstanceVariableAssumption, message: message_b)
85
+ expect(src).to reek_of(:InstanceVariableAssumption, message: message_c)
86
+ end
87
+ end
88
+ end
89
+
90
+ it 'should not report an empty class' do
91
+ src = <<-EOS
92
+ class Dummy
93
+ end
94
+ EOS
95
+
96
+ expect(src).not_to reek_of(:InstanceVariableAssumption)
97
+ end
98
+
99
+ it 'should not report when lazy initializing' do
100
+ src = <<-EOS
101
+ class Dummy
102
+ def test
103
+ @a ||= 1
104
+ end
105
+ end
106
+ EOS
107
+
108
+ expect(src).not_to reek_of(:InstanceVariableAssumption)
109
+ end
110
+
111
+ it 'should report when making instance variable assumption' do
112
+ src = <<-EOS
113
+ class Dummy
114
+ def test
115
+ @a
116
+ end
117
+ end
118
+ EOS
119
+
120
+ expect(src).to reek_of(:InstanceVariableAssumption)
121
+ end
122
+
123
+ it 'reports variable even if others are initialized' do
124
+ src = <<-EOS
125
+ class Dummy
126
+ def initialize
127
+ @a = 1
128
+ end
129
+
130
+ def test
131
+ [@a, @b]
132
+ end
133
+ end
134
+ EOS
135
+
136
+ expect(src).to reek_of(:InstanceVariableAssumption)
137
+ end
138
+
139
+ context 'inner classes' do
140
+ it 'should report outter class' do
141
+ src = <<-EOS
142
+ class Dummy
143
+ def test
144
+ @a
145
+ end
146
+
147
+ class Dummiest
148
+ end
149
+ end
150
+ EOS
151
+
152
+ expect(src).to reek_of(:InstanceVariableAssumption, context: 'Dummy')
153
+ end
154
+
155
+ it 'should report even if outer class initialize the variable' do
156
+ src = <<-EOS
157
+ class Dummy
158
+ def initialize
159
+ @a = 1
160
+ end
161
+
162
+ class Dummiest
163
+ def test
164
+ @a
165
+ end
166
+ end
167
+ end
168
+ EOS
169
+
170
+ expect(src).to reek_of(:InstanceVariableAssumption, context: 'Dummy::Dummiest')
171
+ end
172
+
173
+ it 'should report inner classes' do
174
+ src = <<-EOS
175
+ class Dummy
176
+ def initialize
177
+ @a = 1
178
+ end
179
+
180
+ class Dummiest
181
+ def initialize
182
+ @b = 1
183
+ end
184
+
185
+ def test
186
+ @c
187
+ end
188
+ end
189
+ end
190
+ EOS
191
+
192
+ expect(src).to reek_of(:InstanceVariableAssumption, context: 'Dummy::Dummiest')
193
+ end
194
+ end
195
+ end
@@ -1,24 +1,24 @@
1
1
  require_relative '../../spec_helper'
2
2
  require_lib 'reek/smells/too_many_instance_variables'
3
- require_relative 'smell_detector_shared'
4
3
 
5
4
  RSpec.describe Reek::Smells::TooManyInstanceVariables do
6
- let(:detector) { build(:smell_detector, smell_type: :TooManyInstanceVariables) }
7
-
8
- it_should_behave_like 'SmellDetector'
9
-
10
- def default_max_ivars
11
- Reek::Smells::TooManyInstanceVariables::DEFAULT_MAX_IVARS
12
- end
13
-
14
- def too_many_ivars
15
- default_max_ivars + 1
16
- end
5
+ context 'reporting smell' do
6
+ it 'reports the smell parameters' do
7
+ src = <<-EOS
8
+ class Empty
9
+ def ivars
10
+ @a = @b = @c = @d = 1
11
+ @e = 1
12
+ end
13
+ end
14
+ EOS
17
15
 
18
- def ivar_sequence(count: default_max_ivars, alphabet: ('a'..'z').to_a)
19
- alphabet.first(count).map do |name|
20
- "@#{name}=#{rand}"
21
- end.join(',')
16
+ expect(src).to reek_of(described_class,
17
+ lines: [1],
18
+ count: 5,
19
+ message: 'has at least 5 instance variables',
20
+ context: 'Empty')
21
+ end
22
22
  end
23
23
 
24
24
  context 'counting instance variables' do
@@ -26,73 +26,130 @@ RSpec.describe Reek::Smells::TooManyInstanceVariables do
26
26
  src = <<-EOS
27
27
  class Empty
28
28
  def ivars
29
- #{ivar_sequence}
29
+ @a = @b = @c = @d = 1
30
30
  end
31
31
  end
32
32
  EOS
33
- expect(src).not_to reek_of(:TooManyInstanceVariables)
33
+ expect(src).not_to reek_of(described_class)
34
+ end
35
+
36
+ it 'has a configurable maximum' do
37
+ src = <<-EOS
38
+ # :reek:TooManyInstanceVariables: { max_instance_variables: 5 }
39
+ class Empty
40
+ def ivars
41
+ @a = @b = @c = @d = 1
42
+ @e = 1
43
+ end
44
+ end
45
+ EOS
46
+ expect(src).not_to reek_of(described_class)
34
47
  end
35
48
 
36
49
  it 'counts each ivar only once' do
37
50
  src = <<-EOS
38
51
  class Empty
39
52
  def ivars
40
- #{ivar_sequence}
41
- #{ivar_sequence}
53
+ @a = @b = @c = @d = 1
54
+ @a = @b = @c = @d = 1
42
55
  end
43
56
  end
44
57
  EOS
45
- expect(src).not_to reek_of(:TooManyInstanceVariables)
58
+ expect(src).not_to reek_of(described_class)
46
59
  end
47
60
 
48
- it 'should report excessive ivars' do
61
+ it 'should not report memoized ivars' do
49
62
  src = <<-EOS
50
63
  class Empty
51
64
  def ivars
52
- #{ivar_sequence(count: too_many_ivars)}
65
+ @a = @b = @c = @d = 1
66
+ @e ||= 1
53
67
  end
54
68
  end
55
69
  EOS
56
- expect(src).to reek_of(:TooManyInstanceVariables)
70
+ expect(src).not_to reek_of(described_class)
57
71
  end
58
72
 
59
- it 'should not report for ivars in 2 extensions' do
73
+ it 'should not count ivars on inner classes altogether' do
60
74
  src = <<-EOS
61
- class Full
62
- def ivars_a
63
- #{ivar_sequence}
75
+ class Empty
76
+ class InnerA
77
+ def ivars
78
+ @a = @b = @c = @d = 1
79
+ end
80
+ end
81
+
82
+ class InnerB
83
+ def ivars
84
+ @e = 1
85
+ end
64
86
  end
65
87
  end
88
+ EOS
89
+ expect(src).not_to reek_of(described_class)
90
+ end
66
91
 
67
- class Full
68
- def ivars_b
69
- #{ivar_sequence}
92
+ it 'should not count ivars on modules altogether' do
93
+ src = <<-EOS
94
+ class Empty
95
+ class InnerA
96
+ def ivars
97
+ @a = @b = @c = @d = 1
98
+ end
99
+ end
100
+
101
+ module InnerB
102
+ def ivars
103
+ @e = 1
104
+ end
70
105
  end
71
106
  end
72
107
  EOS
73
- expect(src).not_to reek_of(:TooManyInstanceVariables)
108
+ expect(src).not_to reek_of(described_class)
74
109
  end
75
- end
76
110
 
77
- context 'when a smell is reported' do
78
- let(:warning) do
111
+ it 'reports excessive ivars' do
79
112
  src = <<-EOS
80
- # Comment
81
113
  class Empty
82
114
  def ivars
83
- #{ivar_sequence(count: too_many_ivars)}
115
+ @a = @b = @c = @d = 1
116
+ @e = 1
117
+ end
118
+ end
119
+ EOS
120
+ expect(src).to reek_of(described_class)
121
+ end
122
+
123
+ it 'reports excessive ivars even in different methods' do
124
+ src = <<-EOS
125
+ class Empty
126
+ def ivars_a
127
+ @a = @b = @c = @d = 1
128
+ end
129
+
130
+ def ivars_b
131
+ @e = 1
84
132
  end
85
133
  end
86
134
  EOS
87
- ctx = Reek::Context::CodeContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
88
- detector.sniff(ctx).first
135
+ expect(src).to reek_of(described_class)
89
136
  end
90
137
 
91
- it_should_behave_like 'common fields set correctly'
138
+ it 'should not report for ivars in 2 extensions' do
139
+ src = <<-EOS
140
+ class Full
141
+ def ivars_a
142
+ @a = @b = @c = @d = 1
143
+ end
144
+ end
92
145
 
93
- it 'reports the correct values' do
94
- expect(warning.parameters[:count]).to eq(too_many_ivars)
95
- expect(warning.lines).to eq([2])
146
+ class Full
147
+ def ivars_b
148
+ @a = @b = @c = @d = 1
149
+ end
150
+ end
151
+ EOS
152
+ expect(src).not_to reek_of(described_class)
96
153
  end
97
154
  end
98
155
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reek
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.0
4
+ version: 4.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Rutherford
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2016-08-23 00:00:00.000000000 Z
14
+ date: 2016-08-24 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: codeclimate-engine-rb
@@ -236,6 +236,7 @@ files:
236
236
  - lib/reek/smells/data_clump.rb
237
237
  - lib/reek/smells/duplicate_method_call.rb
238
238
  - lib/reek/smells/feature_envy.rb
239
+ - lib/reek/smells/instance_variable_assumption.rb
239
240
  - lib/reek/smells/irresponsible_module.rb
240
241
  - lib/reek/smells/long_parameter_list.rb
241
242
  - lib/reek/smells/long_yield_list.rb
@@ -345,6 +346,7 @@ files:
345
346
  - spec/reek/smells/data_clump_spec.rb
346
347
  - spec/reek/smells/duplicate_method_call_spec.rb
347
348
  - spec/reek/smells/feature_envy_spec.rb
349
+ - spec/reek/smells/instance_variable_assumption_spec.rb
348
350
  - spec/reek/smells/irresponsible_module_spec.rb
349
351
  - spec/reek/smells/long_parameter_list_spec.rb
350
352
  - spec/reek/smells/long_yield_list_spec.rb
@@ -410,7 +412,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
410
412
  version: '0'
411
413
  requirements: []
412
414
  rubyforge_project:
413
- rubygems_version: 2.5.1
415
+ rubygems_version: 2.6.4
414
416
  signing_key:
415
417
  specification_version: 4
416
418
  summary: Code smell detector for Ruby