rubocop 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubocop might be problematic. Click here for more details.

Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/README.md +1 -0
  4. data/config/default.yml +12 -0
  5. data/config/enabled.yml +0 -1
  6. data/lib/rubocop.rb +3 -0
  7. data/lib/rubocop/cli.rb +7 -1
  8. data/lib/rubocop/cop/cop.rb +20 -5
  9. data/lib/rubocop/cop/lint/end_alignment.rb +51 -42
  10. data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
  11. data/lib/rubocop/cop/lint/literal_in_condition.rb +59 -9
  12. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -0
  13. data/lib/rubocop/cop/rails/validation.rb +0 -4
  14. data/lib/rubocop/cop/style/collection_methods.rb +28 -10
  15. data/lib/rubocop/cop/style/dot_position.rb +14 -4
  16. data/lib/rubocop/cop/style/if_then_else.rb +0 -51
  17. data/lib/rubocop/cop/style/if_with_semicolon.rb +20 -0
  18. data/lib/rubocop/cop/style/multiline_if_then.rb +47 -0
  19. data/lib/rubocop/cop/style/one_line_conditional.rb +20 -0
  20. data/lib/rubocop/cop/style/op_method.rb +16 -14
  21. data/lib/rubocop/cop/util.rb +4 -0
  22. data/lib/rubocop/cop/variable_inspector.rb +32 -13
  23. data/lib/rubocop/version.rb +1 -1
  24. data/rubocop.gemspec +1 -1
  25. data/spec/rubocop/cli_spec.rb +21 -0
  26. data/spec/rubocop/cops/lint/end_alignment_spec.rb +206 -299
  27. data/spec/rubocop/cops/lint/ensure_return_spec.rb +11 -0
  28. data/spec/rubocop/cops/lint/literal_in_condition_spec.rb +37 -3
  29. data/spec/rubocop/cops/lint/shadowing_outer_local_variable_spec.rb +63 -0
  30. data/spec/rubocop/cops/lint/unused_local_variable_spec.rb +68 -0
  31. data/spec/rubocop/cops/offence_spec.rb +2 -2
  32. data/spec/rubocop/cops/style/collection_methods_spec.rb +32 -28
  33. data/spec/rubocop/cops/style/dot_position_spec.rb +46 -11
  34. data/spec/rubocop/cops/style/multiline_if_then_spec.rb +16 -0
  35. metadata +7 -4
@@ -10,15 +10,25 @@ module Rubocop
10
10
  def on_send(node)
11
11
  return unless node.loc.dot
12
12
 
13
- dot_line = node.loc.dot.line
14
- selector_line = node.loc.selector.line
15
-
16
- if dot_line != selector_line
13
+ unless proper_dot_position?(node)
17
14
  add_offence(:convention, node.loc.dot, MSG)
18
15
  end
19
16
 
20
17
  super
21
18
  end
19
+
20
+ private
21
+
22
+ def proper_dot_position?(node)
23
+ dot_line = node.loc.dot.line
24
+ selector_line = node.loc.selector.line
25
+
26
+ case DotPosition.config['Style'].downcase
27
+ when 'leading' then dot_line == selector_line
28
+ when 'trailing' then dot_line != selector_line
29
+ else fail 'Unknown dot position style selected.'
30
+ end
31
+ end
22
32
  end
23
33
  end
24
34
  end
@@ -24,57 +24,6 @@ module Rubocop
24
24
  end
25
25
  end
26
26
  end
27
-
28
- # Checks for uses of semicolon in if statements.
29
- class IfWithSemicolon < Cop
30
- include IfThenElse
31
-
32
- def offending_line(node)
33
- node.loc.begin.line if node.loc.begin && node.loc.begin.is?(';')
34
- end
35
-
36
- def error_message
37
- 'Never use if x; Use the ternary operator instead.'
38
- end
39
- end
40
-
41
- # Checks for uses of then multi-line if statements.
42
- class MultilineIfThen < Cop
43
- include IfThenElse
44
-
45
- def offending_line(node)
46
- condition, body = *node
47
- next_thing = if body && body.loc.expression
48
- body.loc.expression.begin
49
- else
50
- node.loc.end # No body, use "end".
51
- end
52
- right_after_cond =
53
- Parser::Source::Range.new(next_thing.source_buffer,
54
- condition.loc.expression.end.end_pos,
55
- next_thing.begin_pos)
56
- if right_after_cond.source =~ /\A\s*then\s*(#.*)?\s*\n/
57
- node.loc.expression.begin.line
58
- end
59
- end
60
-
61
- def error_message
62
- 'Never use then for multi-line if/unless.'
63
- end
64
- end
65
-
66
- # Checks for uses of if/then/else/end on a single line.
67
- class OneLineConditional < Cop
68
- include IfThenElse
69
-
70
- def offending_line(node)
71
- node.loc.expression.line unless node.loc.expression.source =~ /\n/
72
- end
73
-
74
- def error_message
75
- 'Favor the ternary operator (?:) over if/then/else/end constructs.'
76
- end
77
- end
78
27
  end
79
28
  end
80
29
  end
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # Checks for uses of semicolon in if statements.
7
+ class IfWithSemicolon < Cop
8
+ include IfThenElse
9
+
10
+ def offending_line(node)
11
+ node.loc.begin.line if node.loc.begin && node.loc.begin.is?(';')
12
+ end
13
+
14
+ def error_message
15
+ 'Never use if x; Use the ternary operator instead.'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # Checks for uses of the `then` keyword in multi-line if statements.
7
+ #
8
+ # This is considered bad practice:
9
+ # @example
10
+ #
11
+ # if cond then
12
+ # end
13
+ #
14
+ # While if statements can contain `then` on the same line:
15
+ # @example
16
+ #
17
+ # if cond then a
18
+ # elsif cond then b
19
+ # end
20
+ class MultilineIfThen < Cop
21
+ include IfThenElse
22
+
23
+ def offending_line(node)
24
+ condition, body, else_clause = *node
25
+ next_thing = if body && body.loc.expression
26
+ body.loc.expression.begin
27
+ elsif else_clause && else_clause.loc.expression
28
+ else_clause.loc.expression.begin
29
+ else
30
+ node.loc.end # No body, use "end".
31
+ end
32
+ right_after_cond =
33
+ Parser::Source::Range.new(next_thing.source_buffer,
34
+ condition.loc.expression.end.end_pos,
35
+ next_thing.begin_pos)
36
+ if right_after_cond.source =~ /\A\s*then\s*(#.*)?\s*\n/
37
+ node.loc.expression.begin.line
38
+ end
39
+ end
40
+
41
+ def error_message
42
+ 'Never use then for multi-line if/unless.'
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # Checks for uses of if/then/else/end on a single line.
7
+ class OneLineConditional < Cop
8
+ include IfThenElse
9
+
10
+ def offending_line(node)
11
+ node.loc.expression.line unless node.loc.expression.source =~ /\n/
12
+ end
13
+
14
+ def error_message
15
+ 'Favor the ternary operator (?:) over if/then/else/end constructs.'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -2,25 +2,27 @@
2
2
 
3
3
  module Rubocop
4
4
  module Cop
5
- # This cop makes sure that certain operator methods have their sole
6
- # parameter named *other*.
7
- class OpMethod < Cop
8
- MSG = 'When defining the %s operator, name its argument *other*.'
5
+ module Style
6
+ # This cop makes sure that certain operator methods have their sole
7
+ # parameter named *other*.
8
+ class OpMethod < Cop
9
+ MSG = 'When defining the %s operator, name its argument *other*.'
9
10
 
10
- BLACKLISTED = [:+@, :-@, :[], :[]=, :<<]
11
+ BLACKLISTED = [:+@, :-@, :[], :[]=, :<<]
11
12
 
12
- TARGET_ARGS = s(:args, s(:arg, :other))
13
+ TARGET_ARGS = s(:args, s(:arg, :other))
13
14
 
14
- def on_def(node)
15
- name, args, _body = *node
15
+ def on_def(node)
16
+ name, args, _body = *node
16
17
 
17
- if name !~ /\A\w/ && !BLACKLISTED.include?(name) &&
18
- args.children.size == 1 && args != TARGET_ARGS
19
- add_offence(:convention, args.children[0].loc.expression,
20
- sprintf(MSG, name))
21
- end
18
+ if name !~ /\A\w/ && !BLACKLISTED.include?(name) &&
19
+ args.children.size == 1 && args != TARGET_ARGS
20
+ add_offence(:convention, args.children[0].loc.expression,
21
+ sprintf(MSG, name))
22
+ end
22
23
 
23
- super
24
+ super
25
+ end
24
26
  end
25
27
  end
26
28
  end
@@ -22,6 +22,10 @@ module Rubocop
22
22
  def block_length(block_node)
23
23
  block_node.loc.end.line - block_node.loc.begin.line
24
24
  end
25
+
26
+ def symbolize_keys(hash)
27
+ Hash[hash.map { |(k, v)| [k.to_sym, v] }] if hash
28
+ end
25
29
  end
26
30
  end
27
31
  end
@@ -6,10 +6,10 @@ module Rubocop
6
6
  # This is intended to be used as mix-in, and the user class may override
7
7
  # some of hook methods.
8
8
  module VariableInspector
9
- VARIABLE_ASSIGNMENT_TYPES = [:lvasgn].freeze
9
+ VARIABLE_ASSIGNMENT_TYPES = [:lvasgn, :match_with_lvasgn].freeze
10
10
  ARGUMENT_DECLARATION_TYPES = [
11
11
  :arg, :optarg, :restarg, :blockarg,
12
- :kwarg, :kwoptarg, :kwsplatarg,
12
+ :kwarg, :kwoptarg, :kwrestarg,
13
13
  :shadowarg
14
14
  ].freeze
15
15
  VARIABLE_DECLARATION_TYPES =
@@ -25,18 +25,19 @@ module Rubocop
25
25
  attr_accessor :used
26
26
  alias_method :used?, :used
27
27
 
28
- def initialize(node)
28
+ def initialize(node, name = nil)
29
29
  unless VARIABLE_DECLARATION_TYPES.include?(node.type)
30
30
  fail ArgumentError,
31
31
  "Node type must be any of #{VARIABLE_DECLARATION_TYPES}, " +
32
32
  "passed #{node.type}"
33
33
  end
34
34
  @node = node
35
+ @name = name.to_sym if name
35
36
  @used = false
36
37
  end
37
38
 
38
39
  def name
39
- @node.children.first
40
+ @name || @node.children.first
40
41
  end
41
42
  end
42
43
 
@@ -100,8 +101,8 @@ module Rubocop
100
101
  scope_stack.count
101
102
  end
102
103
 
103
- def add_variable_entry(variable_declaration_node)
104
- entry = VariableEntry.new(variable_declaration_node)
104
+ def add_variable_entry(variable_declaration_node, name = nil)
105
+ entry = VariableEntry.new(variable_declaration_node, name)
105
106
  invoke_hook(:before_declaring_variable, entry)
106
107
  current_scope.variable_entries[entry.name] = entry
107
108
  invoke_hook(:after_declaring_variable, entry)
@@ -188,14 +189,11 @@ module Rubocop
188
189
  case node.type
189
190
  when *ARGUMENT_DECLARATION_TYPES
190
191
  variable_table.add_variable_entry(node)
191
- when *VARIABLE_ASSIGNMENT_TYPES
192
+ when :lvasgn
192
193
  variable_name = node.children.first
193
- variable_entry = variable_table.find_variable_entry(variable_name)
194
- if variable_entry
195
- variable_entry.used = true
196
- else
197
- variable_table.add_variable_entry(node)
198
- end
194
+ process_variable_assignment(node, variable_name)
195
+ when :match_with_lvasgn
196
+ process_named_captures(node)
199
197
  when *VARIABLE_USE_TYPES
200
198
  variable_name = node.children.first
201
199
  variable_entry = variable_table.find_variable_entry(variable_name)
@@ -256,6 +254,27 @@ module Rubocop
256
254
  end
257
255
  end
258
256
 
257
+ def process_variable_assignment(node, name)
258
+ entry = variable_table.find_variable_entry(name)
259
+ if entry
260
+ entry.used = true
261
+ else
262
+ variable_table.add_variable_entry(node, name)
263
+ end
264
+ end
265
+
266
+ def process_named_captures(match_with_lvasgn_node)
267
+ regexp_string = match_with_lvasgn_node.children[0]
268
+ .children[0]
269
+ .children[0]
270
+ regexp = Regexp.new(regexp_string)
271
+ variable_names = regexp.named_captures.keys
272
+
273
+ variable_names.each do |name|
274
+ process_variable_assignment(match_with_lvasgn_node, name)
275
+ end
276
+ end
277
+
259
278
  # Hooks
260
279
 
261
280
  def before_entering_scope(scope)
@@ -3,7 +3,7 @@
3
3
  module Rubocop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '0.9.0'
6
+ STRING = '0.9.1'
7
7
 
8
8
  MSG = '%s (using Parser %s, running on %s %s %s)'
9
9
 
data/rubocop.gemspec CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |s|
27
27
  s.summary = 'Automatic Ruby code style checking tool.'
28
28
 
29
29
  s.add_runtime_dependency('rainbow', '>= 1.1.4')
30
- s.add_runtime_dependency('parser', '2.0.0.beta9')
30
+ s.add_runtime_dependency('parser', '2.0.0.pre1')
31
31
  s.add_development_dependency('rake', '~> 10.0')
32
32
  s.add_development_dependency('rspec', '~> 2.13')
33
33
  s.add_development_dependency('yard', '~> 0.8')
@@ -47,6 +47,7 @@ Usage: rubocop [options] [file1, file2, ...]
47
47
  if no format is specified.
48
48
  -r, --require FILE Require Ruby file.
49
49
  -R, --rails Run extra Rails cops.
50
+ -l, --lint Run only lint cops.
50
51
  -a, --auto-correct Auto-correct offences.
51
52
  -s, --silent Silence summary.
52
53
  -n, --no-color Disable color output.
@@ -252,8 +253,28 @@ Usage: rubocop [options] [file1, file2, ...]
252
253
  ''].join("\n"))
253
254
  end
254
255
 
256
+ it 'runs only lint cops if --lint is passed' do
257
+ create_file('example.rb', ['if 0 ',
258
+ "\ty",
259
+ 'end'])
260
+ # IfUnlessModifier depends on the configuration of LineLength.
261
+ # That configuration might have been set by other spec examples
262
+ # so we reset it to emulate a start from scratch.
263
+ Cop::Style::LineLength.config = nil
264
+
265
+ expect(cli.run(['--format', 'simple', '--lint', 'example.rb'])).to eq(1)
266
+ expect($stdout.string)
267
+ .to eq(['== example.rb ==',
268
+ 'W: 1: 4: Literal 0 appeared in a condition.',
269
+ '',
270
+ '1 file inspected, 1 offence detected',
271
+ ''].join("\n"))
272
+
273
+ end
274
+
255
275
  it 'exits with error if an incorrect cop name is passed to --only' do
256
276
  expect(cli.run(%w(--only 123))).to eq(1)
277
+
257
278
  expect($stderr.string).to eq("Unrecognized cop name: 123.\n")
258
279
  end
259
280
 
@@ -8,10 +8,6 @@ module Rubocop
8
8
  module Lint
9
9
  describe EndAlignment do
10
10
  let(:cop) { EndAlignment.new }
11
- before do
12
- # TODO: Initialize the config to a default {} value. Currently it's nil.
13
- EndAlignment.config = {}
14
- end
15
11
 
16
12
  it 'registers an offence for mismatched class end' do
17
13
  inspect_source(cop,
@@ -77,348 +73,259 @@ module Rubocop
77
73
  expect(cop.offences.size).to eq(1)
78
74
  end
79
75
 
80
- context 'with BlockAlignSchema set to StartOfAssignment' do
81
- before do
82
- EndAlignment.config = { 'BlockAlignSchema' => 'StartOfAssignment' }
83
- end
84
-
85
- it 'accepts end aligned with a variable' do
86
- inspect_source(cop,
87
- ['variable = test do |ala|',
88
- 'end'
89
- ])
90
- expect(cop.offences).to be_empty
91
- end
92
-
93
- it 'registers an offence for mismatched block end with a variable' do
94
- inspect_source(cop,
95
- ['variable = test do |ala|',
96
- ' end'
97
- ])
98
- expect(cop.offences.size).to eq(1)
99
- end
100
-
101
- it 'accepts end aligned with an instance variable' do
102
- inspect_source(cop,
103
- ['@variable = test do |ala|',
104
- 'end'
105
- ])
106
- expect(cop.offences).to be_empty
107
- end
108
-
109
- it 'registers an offence for mismatched block end with an instance variable' do
110
- inspect_source(cop,
111
- ['@variable = test do |ala|',
112
- ' end'
113
- ])
114
- expect(cop.offences.size).to eq(1)
115
- end
116
-
117
- it 'accepts end aligned with a class variable' do
118
- inspect_source(cop,
119
- ['@@variable = test do |ala|',
120
- 'end'
121
- ])
122
- expect(cop.offences).to be_empty
123
- end
124
-
125
- it 'registers an offence for mismatched block end with a class variable' do
126
- inspect_source(cop,
127
- ['@@variable = test do |ala|',
128
- ' end'
129
- ])
130
- expect(cop.offences.size).to eq(1)
131
- end
132
-
133
- it 'accepts end aligned with a global variable' do
134
- inspect_source(cop,
135
- ['$variable = test do |ala|',
136
- 'end'
137
- ])
138
- expect(cop.offences).to be_empty
139
- end
140
-
141
- it 'registers an offence for mismatched block end with a global variable' do
76
+ context 'when the block is a logical operand' do
77
+ it 'accepts a correctly aligned block end' do
142
78
  inspect_source(cop,
143
- ['$variable = test do |ala|',
144
- ' end'
145
- ])
146
- expect(cop.offences.size).to eq(1)
147
- end
148
-
149
- it 'accepts end aligned with a constant' do
150
- inspect_source(cop,
151
- ['CONSTANT = test do |ala|',
152
- 'end'
79
+ ['(value.is_a? Array) && value.all? do |subvalue|',
80
+ ' type_check_value(subvalue, array_type)',
81
+ 'end',
82
+ 'a || b do',
83
+ 'end',
153
84
  ])
154
85
  expect(cop.offences).to be_empty
155
86
  end
87
+ end
156
88
 
157
- it 'registers an offence for mismatched block end with a constant' do
158
- inspect_source(cop,
159
- ['Module::CONSTANT = test do |ala|',
160
- ' end'
161
- ])
162
- expect(cop.offences.size).to eq(1)
163
- end
89
+ it 'accepts end aligned with a variable' do
90
+ inspect_source(cop,
91
+ ['variable = test do |ala|',
92
+ 'end'
93
+ ])
94
+ expect(cop.offences).to be_empty
95
+ end
164
96
 
165
- it 'accepts end aligned with an attribute writer method' do
97
+ context 'and the block is an operand' do
98
+ it 'accepts end aligned with a variable' do
166
99
  inspect_source(cop,
167
- ['parser.child.consumer = lambda do |token|',
168
- ' token << 1',
169
- 'end'
100
+ ['b = 1 + preceding_line.reduce(0) do |a, e|',
101
+ ' a + e.length + newline_length',
102
+ 'end + 1'
170
103
  ])
171
104
  expect(cop.offences).to be_empty
172
105
  end
106
+ end
173
107
 
174
- it 'registers an offence for mismatched block end with an attribute writer method' do
175
- inspect_source(cop,
176
- ['parser.child.consumer = lambda do |token|',
177
- ' token << 1',
178
- ' end'
179
- ])
180
- expect(cop.offences.size).to eq(1)
181
- end
182
-
183
- it 'accepts end aligned with an op-asgn (+=, -=)' do
184
- inspect_source(cop,
185
- ['rb += files.select do |file|',
186
- ' file << something',
187
- 'end'
188
- ])
189
- expect(cop.offences).to be_empty
190
- end
108
+ it 'registers an offence for mismatched block end with a variable' do
109
+ inspect_source(cop,
110
+ ['variable = test do |ala|',
111
+ ' end'
112
+ ])
113
+ expect(cop.offences.size).to eq(1)
114
+ end
191
115
 
192
- it 'registers an offence for mismatched block end with an op-asgn (+=, -=)' do
116
+ context 'when the block is defined on the next line' do
117
+ it 'accepts end aligned with the block expression' do
193
118
  inspect_source(cop,
194
- ['rb += files.select do |file|',
195
- ' file << something',
119
+ ['variable =',
120
+ ' a_long_method_that_dont_fit_on_the_line do |v|',
121
+ ' v.foo',
196
122
  ' end'
197
123
  ])
198
- expect(cop.offences.size).to eq(1)
199
- end
200
-
201
- it 'accepts end aligned with an and-asgn (&&=)' do
202
- inspect_source(cop,
203
- ['variable &&= test do |ala|',
204
- 'end'
205
- ])
206
124
  expect(cop.offences).to be_empty
207
125
  end
208
126
 
209
- it 'registers an offence for mismatched block end with an and-asgn (&&=)' do
127
+ it 'registers an offences for mismatched end alignment' do
210
128
  inspect_source(cop,
211
- ['variable &&= test do |ala|',
212
- ' end'
213
- ])
214
- expect(cop.offences.size).to eq(1)
215
- end
216
-
217
- it 'accepts end aligned with an or-asgn (||=)' do
218
- inspect_source(cop,
219
- ['variable ||= test do |ala|',
129
+ ['variable =',
130
+ ' a_long_method_that_dont_fit_on_the_line do |v|',
131
+ ' v.foo',
220
132
  'end'
221
133
  ])
222
- expect(cop.offences).to be_empty
223
- end
224
-
225
- it 'registers an offence for mismatched block end with an or-asgn (||=)' do
226
- inspect_source(cop,
227
- ['variable ||= test do |ala|',
228
- ' end'
229
- ])
230
134
  expect(cop.offences.size).to eq(1)
231
135
  end
136
+ end
232
137
 
233
- it 'accepts end aligned with a mass assignment' do
234
- inspect_source(cop,
235
- ['var1, var2 = lambda do |test|',
236
- ' [1, 2]',
237
- 'end'
238
- ])
239
- expect(cop.offences).to be_empty
240
- end
138
+ it 'accepts end aligned with an instance variable' do
139
+ inspect_source(cop,
140
+ ['@variable = test do |ala|',
141
+ 'end'
142
+ ])
143
+ expect(cop.offences).to be_empty
144
+ end
241
145
 
242
- it 'registers an offence for mismatched block end with a mass assignment' do
243
- inspect_source(cop,
244
- ['var1, var2 = lambda do |test|',
245
- ' [1, 2]',
246
- ' end'
247
- ])
248
- expect(cop.offences.size).to eq(1)
249
- end
146
+ it 'registers an offence for mismatched block end with an instance variable' do
147
+ inspect_source(cop,
148
+ ['@variable = test do |ala|',
149
+ ' end'
150
+ ])
151
+ expect(cop.offences.size).to eq(1)
250
152
  end
251
153
 
252
- context 'with BlockAlignSchema set to StartOfBlockCommand' do
253
- before do
254
- EndAlignment.config = { 'BlockAlignSchema' => 'StartOfBlockCommand' }
255
- end
154
+ it 'accepts end aligned with a class variable' do
155
+ inspect_source(cop,
156
+ ['@@variable = test do |ala|',
157
+ 'end'
158
+ ])
159
+ expect(cop.offences).to be_empty
160
+ end
256
161
 
257
- it 'accepts end aligned with the method that invokes the block' do
258
- inspect_source(cop,
259
- ['variable = test do |ala|',
260
- ' end'
261
- ])
262
- expect(cop.offences).to be_empty
263
- end
162
+ it 'registers an offence for mismatched block end with a class variable' do
163
+ inspect_source(cop,
164
+ ['@@variable = test do |ala|',
165
+ ' end'
166
+ ])
167
+ expect(cop.offences.size).to eq(1)
168
+ end
264
169
 
265
- it 'registers an offence for mismatched block end with the method that invokes the block' do
266
- inspect_source(cop,
267
- ['variable = test do |ala|',
268
- 'end'
269
- ])
270
- expect(cop.offences.size).to eq(1)
271
- end
170
+ it 'accepts end aligned with a global variable' do
171
+ inspect_source(cop,
172
+ ['$variable = test do |ala|',
173
+ 'end'
174
+ ])
175
+ expect(cop.offences).to be_empty
176
+ end
272
177
 
273
- it 'accepts end aligned with the method when return value is assigned to instance variable' do
274
- inspect_source(cop,
275
- ['@variable = test do |ala|',
276
- ' end'
277
- ])
278
- expect(cop.offences).to be_empty
279
- end
178
+ it 'registers an offence for mismatched block end with a global variable' do
179
+ inspect_source(cop,
180
+ ['$variable = test do |ala|',
181
+ ' end'
182
+ ])
183
+ expect(cop.offences.size).to eq(1)
184
+ end
280
185
 
281
- it 'registers an offence for mismatched block end when return value is assigned to instance variable' do
282
- inspect_source(cop,
283
- ['@variable = test do |ala|',
284
- 'end'
285
- ])
286
- expect(cop.offences.size).to eq(1)
287
- end
186
+ it 'accepts end aligned with a constant' do
187
+ inspect_source(cop,
188
+ ['CONSTANT = test do |ala|',
189
+ 'end'
190
+ ])
191
+ expect(cop.offences).to be_empty
192
+ end
288
193
 
289
- it 'accepts end aligned with the method when return value is assigned to class variable' do
290
- inspect_source(cop,
291
- ['@@variable = test do |ala|',
292
- ' end'
293
- ])
294
- expect(cop.offences).to be_empty
295
- end
194
+ it 'registers an offence for mismatched block end with a constant' do
195
+ inspect_source(cop,
196
+ ['Module::CONSTANT = test do |ala|',
197
+ ' end'
198
+ ])
199
+ expect(cop.offences.size).to eq(1)
200
+ end
296
201
 
297
- it 'registers an offence for mismatched block end when return value is assigned to class variable' do
298
- inspect_source(cop,
299
- ['@@variable = test do |ala|',
300
- 'end'
301
- ])
302
- expect(cop.offences.size).to eq(1)
303
- end
202
+ it 'accepts end aligned with a method call' do
203
+ inspect_source(cop,
204
+ ['parser.childs << lambda do |token|',
205
+ ' token << 1',
206
+ 'end'
207
+ ])
208
+ expect(cop.offences).to be_empty
209
+ end
304
210
 
305
- it 'accepts end aligned with the method when return value is assigned to global variable' do
306
- inspect_source(cop,
307
- ['$variable = test do |ala|',
308
- ' end'
309
- ])
310
- expect(cop.offences).to be_empty
311
- end
211
+ it 'registers an offence for mismatched block end with a method call' do
212
+ inspect_source(cop,
213
+ ['parser.childs << lambda do |token|',
214
+ ' token << 1',
215
+ ' end'
216
+ ])
217
+ expect(cop.offences.size).to eq(1)
218
+ end
312
219
 
313
- it 'registers an offence for mismatched block end when return value is assigned to global variable' do
314
- inspect_source(cop,
315
- ['$variable = test do |ala|',
316
- 'end'
317
- ])
318
- expect(cop.offences.size).to eq(1)
319
- end
220
+ it 'accepts end aligned with a method call with arguments' do
221
+ inspect_source(cop,
222
+ ['@h[:f] = f.each_pair.map do |f, v|',
223
+ ' v = 1',
224
+ 'end'
225
+ ])
226
+ expect(cop.offences).to be_empty
227
+ end
320
228
 
321
- it 'accepts end aligned with the method when return value is assigned to constant' do
322
- inspect_source(cop,
323
- ['CONSTANT = test do |ala|',
324
- ' end'
325
- ])
326
- expect(cop.offences).to be_empty
327
- end
229
+ it 'registers an offence for mismatched end with a method call with arguments' do
230
+ inspect_source(cop,
231
+ ['@h[:f] = f.each_pair.map do |f, v|',
232
+ ' v = 1',
233
+ ' end'
234
+ ])
235
+ expect(cop.offences.size).to eq(1)
236
+ end
328
237
 
329
- it 'registers an offence for mismatched block end when return value is assigned to constant' do
330
- inspect_source(cop,
331
- ['Module::CONSTANT = test do |ala|',
332
- 'end'
333
- ])
334
- expect(cop.offences.size).to eq(1)
335
- end
238
+ it 'does not raise an error for nested block in a method call' do
239
+ inspect_source(cop,
240
+ ['expect(arr.all? { |o| o.valid? })'
241
+ ])
242
+ expect(cop.offences).to be_empty
243
+ end
336
244
 
337
- it 'accepts end aligned with the method when return value is assigned to attribute writer method' do
338
- inspect_source(cop,
339
- ['parser.child.consumer = lambda do |token|',
340
- ' token << 1',
341
- ' end'
342
- ])
343
- expect(cop.offences).to be_empty
344
- end
245
+ it 'accepts end aligned with the outermost method in the method chain that calls the block' do
246
+ inspect_source(cop,
247
+ ['expect(arr.all? do |o|',
248
+ ' o.valid?',
249
+ 'end)'
250
+ ])
251
+ expect(cop.offences).to be_empty
252
+ end
345
253
 
346
- it 'registers an offence for mismatched block end when return value is assigned to attribute writer method' do
347
- inspect_source(cop,
348
- ['parser.child.consumer = lambda do |token|',
349
- ' token << 1',
350
- 'end'
351
- ])
352
- expect(cop.offences.size).to eq(1)
353
- end
254
+ it 'registers an offence for mismatched end aligned with the outermost method in the method chain that calls the block' do
255
+ inspect_source(cop,
256
+ ['expect(arr.all? do |o|',
257
+ ' o.valid?',
258
+ ' end)'
259
+ ])
260
+ expect(cop.offences.size).to eq(1)
261
+ end
354
262
 
355
- it 'accepts end aligned with the method when return value is assigned using op-asgn (+=, -=)' do
356
- inspect_source(cop,
357
- ['rb += files.select do |file|',
358
- ' file << something',
359
- ' end'
360
- ])
361
- expect(cop.offences).to be_empty
362
- end
263
+ it 'accepts end aligned with an op-asgn (+=, -=)' do
264
+ inspect_source(cop,
265
+ ['rb += files.select do |file|',
266
+ ' file << something',
267
+ 'end'
268
+ ])
269
+ expect(cop.offences).to be_empty
270
+ end
363
271
 
364
- it 'registers an offence for mismatched block end when return value is assigned using op-asgn (+=, -=)' do
365
- inspect_source(cop,
366
- ['rb += files.select do |file|',
367
- ' file << something',
368
- 'end'
369
- ])
370
- expect(cop.offences.size).to eq(1)
371
- end
272
+ it 'registers an offence for mismatched block end with an op-asgn (+=, -=)' do
273
+ inspect_source(cop,
274
+ ['rb += files.select do |file|',
275
+ ' file << something',
276
+ ' end'
277
+ ])
278
+ expect(cop.offences.size).to eq(1)
279
+ end
372
280
 
373
- it 'accepts end aligned with the method when return value is assigned using and-asgn (&&=)' do
374
- inspect_source(cop,
375
- ['variable &&= test do |ala|',
376
- ' end'
377
- ])
378
- expect(cop.offences).to be_empty
379
- end
281
+ it 'accepts end aligned with an and-asgn (&&=)' do
282
+ inspect_source(cop,
283
+ ['variable &&= test do |ala|',
284
+ 'end'
285
+ ])
286
+ expect(cop.offences).to be_empty
287
+ end
380
288
 
381
- it 'registers an offence for mismatched block end when return value is assigned using and-asgn (&&=)' do
382
- inspect_source(cop,
383
- ['variable &&= test do |ala|',
384
- 'end'
385
- ])
386
- expect(cop.offences.size).to eq(1)
387
- end
289
+ it 'registers an offence for mismatched block end with an and-asgn (&&=)' do
290
+ inspect_source(cop,
291
+ ['variable &&= test do |ala|',
292
+ ' end'
293
+ ])
294
+ expect(cop.offences.size).to eq(1)
295
+ end
388
296
 
389
- it 'accepts end aligned with the method when return value is assigned using or-asgn (||=)' do
390
- inspect_source(cop,
391
- ['variable ||= test do |ala|',
392
- ' end'
393
- ])
394
- expect(cop.offences).to be_empty
395
- end
297
+ it 'accepts end aligned with an or-asgn (||=)' do
298
+ inspect_source(cop,
299
+ ['variable ||= test do |ala|',
300
+ 'end'
301
+ ])
302
+ expect(cop.offences).to be_empty
303
+ end
396
304
 
397
- it 'registers an offence for mismatched block end when return value is assigned using or-asgn (||=)' do
398
- inspect_source(cop,
399
- ['variable ||= test do |ala|',
400
- 'end'
401
- ])
402
- expect(cop.offences.size).to eq(1)
403
- end
305
+ it 'registers an offence for mismatched block end with an or-asgn (||=)' do
306
+ inspect_source(cop,
307
+ ['variable ||= test do |ala|',
308
+ ' end'
309
+ ])
310
+ expect(cop.offences.size).to eq(1)
311
+ end
404
312
 
405
- it 'accepts end aligned with the method when return value is assigned using mass assignment' do
406
- inspect_source(cop,
407
- ['var1, var2 = lambda do |test|',
408
- ' [1, 2]',
409
- ' end'
410
- ])
411
- expect(cop.offences).to be_empty
412
- end
313
+ it 'accepts end aligned with a mass assignment' do
314
+ inspect_source(cop,
315
+ ['var1, var2 = lambda do |test|',
316
+ ' [1, 2]',
317
+ 'end'
318
+ ])
319
+ expect(cop.offences).to be_empty
320
+ end
413
321
 
414
- it 'registers an offence for mismatched block end when return value is assigned using mass assignment' do
415
- inspect_source(cop,
416
- ['var1, var2 = lambda do |test|',
417
- ' [1, 2]',
418
- 'end'
419
- ])
420
- expect(cop.offences.size).to eq(1)
421
- end
322
+ it 'registers an offence for mismatched block end with a mass assignment' do
323
+ inspect_source(cop,
324
+ ['var1, var2 = lambda do |test|',
325
+ ' [1, 2]',
326
+ ' end'
327
+ ])
328
+ expect(cop.offences.size).to eq(1)
422
329
  end
423
330
  end
424
331
  end