puppet-lint-halyard 1.1.0.1

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 (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +10 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +20 -0
  6. data/README.md +210 -0
  7. data/Rakefile +14 -0
  8. data/bin/puppet-lint +7 -0
  9. data/lib/puppet-lint.rb +214 -0
  10. data/lib/puppet-lint/bin.rb +79 -0
  11. data/lib/puppet-lint/checkplugin.rb +176 -0
  12. data/lib/puppet-lint/checks.rb +91 -0
  13. data/lib/puppet-lint/configuration.rb +153 -0
  14. data/lib/puppet-lint/data.rb +521 -0
  15. data/lib/puppet-lint/lexer.rb +373 -0
  16. data/lib/puppet-lint/lexer/token.rb +101 -0
  17. data/lib/puppet-lint/monkeypatches.rb +2 -0
  18. data/lib/puppet-lint/monkeypatches/string_percent.rb +52 -0
  19. data/lib/puppet-lint/monkeypatches/string_prepend.rb +13 -0
  20. data/lib/puppet-lint/optparser.rb +118 -0
  21. data/lib/puppet-lint/plugins.rb +74 -0
  22. data/lib/puppet-lint/plugins/check_classes.rb +285 -0
  23. data/lib/puppet-lint/plugins/check_comments.rb +55 -0
  24. data/lib/puppet-lint/plugins/check_conditionals.rb +65 -0
  25. data/lib/puppet-lint/plugins/check_documentation.rb +31 -0
  26. data/lib/puppet-lint/plugins/check_nodes.rb +29 -0
  27. data/lib/puppet-lint/plugins/check_resources.rb +194 -0
  28. data/lib/puppet-lint/plugins/check_strings.rb +174 -0
  29. data/lib/puppet-lint/plugins/check_variables.rb +19 -0
  30. data/lib/puppet-lint/plugins/check_whitespace.rb +170 -0
  31. data/lib/puppet-lint/tasks/puppet-lint.rb +91 -0
  32. data/lib/puppet-lint/version.rb +3 -0
  33. data/puppet-lint.gemspec +24 -0
  34. data/spec/fixtures/test/manifests/fail.pp +2 -0
  35. data/spec/fixtures/test/manifests/ignore.pp +1 -0
  36. data/spec/fixtures/test/manifests/ignore_multiple_block.pp +6 -0
  37. data/spec/fixtures/test/manifests/ignore_multiple_line.pp +2 -0
  38. data/spec/fixtures/test/manifests/ignore_reason.pp +1 -0
  39. data/spec/fixtures/test/manifests/init.pp +3 -0
  40. data/spec/fixtures/test/manifests/malformed.pp +1 -0
  41. data/spec/fixtures/test/manifests/url_interpolation.pp +12 -0
  42. data/spec/fixtures/test/manifests/warning.pp +2 -0
  43. data/spec/puppet-lint/bin_spec.rb +326 -0
  44. data/spec/puppet-lint/configuration_spec.rb +56 -0
  45. data/spec/puppet-lint/ignore_overrides_spec.rb +109 -0
  46. data/spec/puppet-lint/lexer/token_spec.rb +18 -0
  47. data/spec/puppet-lint/lexer_spec.rb +783 -0
  48. data/spec/puppet-lint/plugins/check_classes/autoloader_layout_spec.rb +105 -0
  49. data/spec/puppet-lint/plugins/check_classes/class_inherits_from_params_class_spec.rb +35 -0
  50. data/spec/puppet-lint/plugins/check_classes/inherits_across_namespaces_spec.rb +33 -0
  51. data/spec/puppet-lint/plugins/check_classes/names_containing_dash_spec.rb +45 -0
  52. data/spec/puppet-lint/plugins/check_classes/nested_classes_or_defines_spec.rb +76 -0
  53. data/spec/puppet-lint/plugins/check_classes/parameter_order_spec.rb +73 -0
  54. data/spec/puppet-lint/plugins/check_classes/right_to_left_relationship_spec.rb +25 -0
  55. data/spec/puppet-lint/plugins/check_classes/variable_scope_spec.rb +196 -0
  56. data/spec/puppet-lint/plugins/check_comments/slash_comments_spec.rb +45 -0
  57. data/spec/puppet-lint/plugins/check_comments/star_comments_spec.rb +84 -0
  58. data/spec/puppet-lint/plugins/check_conditionals/case_without_default_spec.rb +98 -0
  59. data/spec/puppet-lint/plugins/check_conditionals/selector_inside_resource_spec.rb +36 -0
  60. data/spec/puppet-lint/plugins/check_documentation/documentation_spec.rb +52 -0
  61. data/spec/puppet-lint/plugins/check_nodes/unquoted_node_name_spec.rb +146 -0
  62. data/spec/puppet-lint/plugins/check_resources/duplicate_params_spec.rb +100 -0
  63. data/spec/puppet-lint/plugins/check_resources/ensure_first_param_spec.rb +55 -0
  64. data/spec/puppet-lint/plugins/check_resources/ensure_not_symlink_target_spec.rb +89 -0
  65. data/spec/puppet-lint/plugins/check_resources/file_mode_spec.rb +113 -0
  66. data/spec/puppet-lint/plugins/check_resources/unquoted_file_mode_spec.rb +45 -0
  67. data/spec/puppet-lint/plugins/check_resources/unquoted_resource_title_spec.rb +216 -0
  68. data/spec/puppet-lint/plugins/check_strings/double_quoted_strings_spec.rb +199 -0
  69. data/spec/puppet-lint/plugins/check_strings/only_variable_string_spec.rb +114 -0
  70. data/spec/puppet-lint/plugins/check_strings/puppet_url_without_modules_spec.rb +62 -0
  71. data/spec/puppet-lint/plugins/check_strings/quoted_booleans_spec.rb +129 -0
  72. data/spec/puppet-lint/plugins/check_strings/single_quote_string_with_variables_spec.rb +17 -0
  73. data/spec/puppet-lint/plugins/check_strings/variables_not_enclosed_spec.rb +73 -0
  74. data/spec/puppet-lint/plugins/check_variables/variable_contains_dash_spec.rb +37 -0
  75. data/spec/puppet-lint/plugins/check_whitespace/2sp_soft_tabs_spec.rb +21 -0
  76. data/spec/puppet-lint/plugins/check_whitespace/80chars_spec.rb +54 -0
  77. data/spec/puppet-lint/plugins/check_whitespace/arrow_alignment_spec.rb +524 -0
  78. data/spec/puppet-lint/plugins/check_whitespace/hard_tabs_spec.rb +45 -0
  79. data/spec/puppet-lint/plugins/check_whitespace/trailing_whitespace_spec.rb +101 -0
  80. data/spec/puppet-lint_spec.rb +20 -0
  81. data/spec/spec_helper.rb +129 -0
  82. metadata +229 -0
@@ -0,0 +1,521 @@
1
+ require 'singleton'
2
+ require 'set'
3
+
4
+ # Public: A singleton class storing all the information about the manifest
5
+ # being analysed.
6
+ class PuppetLint::Data
7
+ include Singleton
8
+
9
+ class << self
10
+ # Internal: Get/Set the full expanded path to the manifest file being
11
+ # checked.
12
+ attr_reader :path, :fullpath, :filename
13
+
14
+ # Internal: Get/Set the raw manifest data, split by \n.
15
+ attr_accessor :manifest_lines
16
+
17
+ # Internal: Store the tokenised manifest.
18
+ #
19
+ # tokens - The Array of PuppetLint::Lexer::Token objects to store.
20
+ #
21
+ # Returns nothing.
22
+ def tokens=(tokens)
23
+ @tokens = tokens
24
+ @title_tokens = nil
25
+ @resource_indexes = nil
26
+ @class_indexes = nil
27
+ @defined_type_indexes = nil
28
+ @function_indexes = nil
29
+ @array_indexes = nil
30
+ @hash_indexes = nil
31
+ @defaults_indexes = nil
32
+ end
33
+
34
+ # Public: Get the tokenised manifest.
35
+ #
36
+ # Returns an Array of PuppetLint::Lexer::Token objects.
37
+ def tokens
38
+ calling_method = begin
39
+ caller[0][/`.*'/][1..-2]
40
+ rescue NoMethodError
41
+ caller[1][/`.*'/][1..-2]
42
+ end
43
+
44
+ if calling_method == 'check'
45
+ @tokens.dup
46
+ else
47
+ @tokens
48
+ end
49
+ end
50
+
51
+ # Internal: Store the path to the manifest file and populate fullpath and
52
+ # filename.
53
+ #
54
+ # val - The path to the file as a String.
55
+ #
56
+ # Returns nothing.
57
+ def path=(val)
58
+ @path = val
59
+ if val.nil?
60
+ @fullpath = nil
61
+ @filename = nil
62
+ else
63
+ @fullpath = File.expand_path(val, ENV['PWD'])
64
+ @filename = File.basename(val)
65
+ end
66
+ end
67
+
68
+ # Internal: Retrieve a list of tokens that represent resource titles
69
+ #
70
+ # Returns an Array of PuppetLint::Lexer::Token objects.
71
+ def title_tokens
72
+ @title_tokens ||= Proc.new do
73
+ result = []
74
+ tokens.each_index do |token_idx|
75
+ if tokens[token_idx].type == :COLON
76
+ # gather a list of tokens that are resource titles
77
+ if tokens[token_idx-1].type == :RBRACK
78
+ array_start_idx = tokens.rindex { |r|
79
+ r.type == :LBRACK
80
+ }
81
+ title_array_tokens = tokens[(array_start_idx + 1)..(token_idx - 2)]
82
+ result += title_array_tokens.select { |token|
83
+ {:STRING => true, :NAME => true}.include? token.type
84
+ }
85
+ else
86
+ next_token = tokens[token_idx].next_code_token
87
+ if next_token.type != :LBRACE
88
+ result << tokens[token_idx - 1]
89
+ end
90
+ end
91
+ end
92
+ end
93
+ result
94
+ end.call
95
+ end
96
+
97
+ # Internal: Calculate the positions of all resource declarations within the
98
+ # tokenised manifest. These positions only point to the content of the
99
+ # resource declarations, they do not include resource types or titles.
100
+ #
101
+ # Returns an Array of Hashes, each containing:
102
+ # :start - An Integer position in the `tokens` Array pointing to the
103
+ # first Token of a resource declaration.
104
+ # :end - An Integer position in the `tokens` Array pointing to the last
105
+ # Token of a resource declaration.
106
+ def resource_indexes
107
+ @resource_indexes ||= Proc.new do
108
+ result = []
109
+ tokens.each_index do |token_idx|
110
+ if tokens[token_idx].type == :COLON
111
+ next_token = tokens[token_idx].next_code_token
112
+ depth = 1
113
+ if next_token && next_token.type != :LBRACE
114
+ tokens[(token_idx + 1)..-1].each_index do |idx|
115
+ real_idx = token_idx + idx + 1
116
+ if tokens[real_idx].type == :LBRACE
117
+ depth += 1
118
+ elsif {:SEMIC => true, :RBRACE => true}.include? tokens[real_idx].type
119
+ unless tokens[real_idx].type == :SEMIC && depth > 1
120
+ depth -= 1
121
+ if depth == 0
122
+ result << {
123
+ :start => token_idx + 1,
124
+ :end => real_idx,
125
+ :tokens => tokens[(token_idx + 1)..real_idx],
126
+ :type => find_resource_type_token(token_idx),
127
+ :param_tokens => find_resource_param_tokens(tokens[(token_idx + 1)..real_idx]),
128
+ }
129
+ break
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ result
138
+ end.call
139
+ end
140
+
141
+ # Internal: Find the Token representing the type of a resource definition.
142
+ #
143
+ # index - The Integer pointing to the start of the resource in the `tokens`
144
+ # array.
145
+ #
146
+ # Returns a Token object.
147
+ def find_resource_type_token(index)
148
+ tokens[tokens[0..index].rindex { |token| token.type == :LBRACE }].prev_code_token
149
+ end
150
+
151
+ # Internal: Find all the Token objects representing the parameter names in
152
+ # a resource definition.
153
+ #
154
+ # resource_tokens - An Array of Token objects that comprise the resource
155
+ # definition.
156
+ #
157
+ # Returns an Array of Token objects.
158
+ def find_resource_param_tokens(resource_tokens)
159
+ resource_tokens.select { |token|
160
+ token.type == :NAME && token.next_code_token.type == :FARROW
161
+ }
162
+ end
163
+
164
+ # Internal: Calculate the positions of all class definitions within the
165
+ # `tokens` Array.
166
+ #
167
+ # Returns an Array of Hashes, each containing:
168
+ # :start - An Integer position in the `tokens` Array pointing to the
169
+ # first Token of a class definition.
170
+ # :end - An Integer position in the `tokens` Array pointing to the last
171
+ # Token of a class definition.
172
+ # :tokens - An Array consisting of all the Token objects that make up the
173
+ # class definition.
174
+ def class_indexes
175
+ @class_indexes ||= definition_indexes(:CLASS)
176
+ end
177
+
178
+ # Internal: Calculate the positions of all defined type definitions within
179
+ # the `tokens` Array.
180
+ #
181
+ # Returns an Array of Hashes, each containing:
182
+ # :start - An Integer position in the `tokens` Array pointing to the
183
+ # first Token of a defined type definition.
184
+ # :end - An Integer position in the `tokens` Array pointing to the last
185
+ # Token of a defined type definition.
186
+ # :tokens - An Array consisting of all the Token objects that make up the
187
+ # defined type.
188
+ def defined_type_indexes
189
+ @defined_type_indexes ||= definition_indexes(:DEFINE)
190
+ end
191
+
192
+ # Internal: Calculate the positions of all node definitions within the
193
+ # `tokens` Array.
194
+ #
195
+ # Returns an Array of Hashes, each containing:
196
+ # :start - An Integer position in the `tokens` Array pointing to the
197
+ # first Token of a defined type definition.
198
+ # :end - An Integer position in the `tokens` Array pointing to the last
199
+ # Token of a defined type definition.
200
+ # :tokens - An Array consisting of all the Token objects that make up the
201
+ # defined type.
202
+ def node_indexes
203
+ @node_indexes ||= definition_indexes(:NODE)
204
+ end
205
+
206
+ # Internal: Calculate the positions of all the specified defintion types
207
+ # within the `tokens` Array.
208
+ #
209
+ # Returns an Array of Hashes, each containing:
210
+ # :start - An Integer position in the `tokens` Array pointing to the
211
+ # first Token of a definition.
212
+ # :end - An Integer position in the `tokens` Array pointing to the last
213
+ # Token of a definition.
214
+ # :tokens - An Array consisting of all the Token objects that make up the
215
+ # definition.
216
+ def definition_indexes(type)
217
+ result = []
218
+ tokens.each_with_index do |token, i|
219
+ if token.type == type
220
+ brace_depth = 0
221
+ paren_depth = 0
222
+ in_params = false
223
+ inherited_class = nil
224
+ tokens[i+1..-1].each_with_index do |definition_token, j|
225
+ case definition_token.type
226
+ when :INHERITS
227
+ inherited_class = definition_token.next_code_token
228
+ when :LPAREN
229
+ in_params = true if paren_depth == 0
230
+ paren_depth += 1
231
+ when :RPAREN
232
+ in_params = false if paren_depth == 1
233
+ paren_depth -= 1
234
+ when :LBRACE
235
+ brace_depth += 1
236
+ when :RBRACE
237
+ brace_depth -= 1
238
+ if brace_depth == 0 && !in_params
239
+ if token.next_code_token.type != :LBRACE
240
+ result << {
241
+ :start => i,
242
+ :end => i + j + 1,
243
+ :tokens => tokens[i..(i + j + 1)],
244
+ :param_tokens => param_tokens(tokens[i..(i + j + 1)]),
245
+ :type => type,
246
+ :name_token => token.next_code_token,
247
+ :inherited_token => inherited_class,
248
+ }
249
+ break
250
+ end
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
256
+ result
257
+ end
258
+
259
+ # Internal: Calculate the positions of all function calls within
260
+ # `tokens` Array.
261
+ #
262
+ # Returns an Array of Hashes, each containing:
263
+ # :start - An Integer position in the `tokens` Array pointing to the
264
+ # first Token of a function call
265
+ # :end - An Integer position in the `tokens` Array pointing to the last
266
+ # Token of a function call
267
+ # :tokens - An Array consisting of all the Token objects that make up the
268
+ # function call.
269
+ def function_indexes
270
+ @function_indexes ||= Proc.new do
271
+ functions = []
272
+ tokens.each_with_index do |token, token_idx|
273
+ if token.type == :NAME && \
274
+ (token_idx == 0 || (token_idx == 1 && tokens[0].type == :WHITESPACE) || token.prev_token.type == :NEWLINE || token.prev_token.type == :INDENT || \
275
+ # function in a function
276
+ (token.prev_code_token && token.prev_code_token.type == :LPAREN))
277
+
278
+ # Hash key
279
+ next if token.next_code_token && token.next_code_token.type == :FARROW
280
+
281
+ level = 0
282
+ real_idx = 0
283
+ in_paren = false
284
+ tokens[token_idx+1..-1].each_with_index do |cur_token, cur_token_idx|
285
+ break if level == 0 && in_paren
286
+ break if level == 0 && cur_token.type == :NEWLINE
287
+
288
+ if cur_token.type == :LPAREN
289
+ level += 1
290
+ in_paren = true
291
+ end
292
+ level -= 1 if cur_token.type == :RPAREN
293
+ real_idx = token_idx + 1 + cur_token_idx
294
+ end
295
+
296
+ functions << {
297
+ :start => token_idx,
298
+ :end => real_idx,
299
+ :tokens => tokens[token_idx..real_idx],
300
+ }
301
+ end
302
+ end
303
+ functions
304
+ end.call
305
+ end
306
+
307
+ # Internal: Calculate the positions of all array values within
308
+ # `tokens` Array.
309
+ #
310
+ # Returns an Array of Hashes, each containing:
311
+ # :start - An Integer position in the `tokens` Array pointing to the
312
+ # first Token of an array value
313
+ # :end - An Integer position in the `tokens` Array pointing to the last
314
+ # Token of an array value
315
+ # :tokens - An Array consisting of all the Token objects that make up the
316
+ # array value.
317
+ def array_indexes
318
+ @array_indexes ||= Proc.new do
319
+ arrays = []
320
+ tokens.each_with_index do |token, token_idx|
321
+ if token.type == :LBRACK
322
+ real_idx = 0
323
+ tokens[token_idx+1..-1].each_with_index do |cur_token, cur_token_idx|
324
+ real_idx = token_idx + 1 + cur_token_idx
325
+ break if cur_token.type == :RBRACK
326
+ end
327
+
328
+ # Ignore resource references
329
+ next if token.prev_code_token && \
330
+ token.prev_code_token.type == :CLASSREF
331
+ arrays << {
332
+ :start => token_idx,
333
+ :end => real_idx,
334
+ :tokens => tokens[token_idx..real_idx],
335
+ }
336
+ end
337
+ end
338
+ arrays
339
+ end.call
340
+ end
341
+
342
+ # Internal: Calculate the positions of all hash values within
343
+ # `tokens` Array.
344
+ #
345
+ # Returns an Array of Hashes, each containing:
346
+ # :start - An Integer position in the `tokens` Array pointing to the
347
+ # first Token of an hash value
348
+ # :end - An Integer position in the `tokens` Array pointing to the last
349
+ # Token of an hash value
350
+ # :tokens - An Array consisting of all the Token objects that make up the
351
+ # hash value.
352
+ def hash_indexes
353
+ @hash_indexes ||= Proc.new do
354
+ hashes = []
355
+ tokens.each_with_index do |token, token_idx|
356
+ next unless token.prev_code_token
357
+ next unless [:EQUALS, :ISEQUAL, :FARROW, :LPAREN].include? token.prev_code_token.type
358
+ if token.type == :LBRACE
359
+ level = 0
360
+ real_idx = 0
361
+ tokens[token_idx+1..-1].each_with_index do |cur_token, cur_token_idx|
362
+ real_idx = token_idx + 1 + cur_token_idx
363
+
364
+ level += 1 if cur_token.type == :LBRACE
365
+ level -= 1 if cur_token.type == :RBRACE
366
+ break if level < 0
367
+ end
368
+
369
+ hashes << {
370
+ :start => token_idx,
371
+ :end => real_idx,
372
+ :tokens => tokens[token_idx..real_idx],
373
+ }
374
+ end
375
+ end
376
+ hashes
377
+ end.call
378
+ end
379
+
380
+ # Internal: Calculate the positions of all defaults declarations within
381
+ # `tokens` Array.
382
+ #
383
+ # Returns an Array of Hashes, each containing:
384
+ # :start - An Integer position in the `tokens` Array pointing to the
385
+ # first Token of the defaults declaration
386
+ # :end - An Integer position in the `tokens` Array pointing to the last
387
+ # Token of the defaults declaration
388
+ # :tokens - An Array consisting of all the Token objects that make up the
389
+ # defaults declaration.
390
+ def defaults_indexes
391
+ @defaults_indexes ||= Proc.new do
392
+ defaults = []
393
+ tokens.each_with_index do |token, token_idx|
394
+ if token.type == :CLASSREF && token.next_code_token && \
395
+ token.next_code_token.type == :LBRACE
396
+ real_idx = 0
397
+
398
+ tokens[token_idx+1..-1].each_with_index do |cur_token, cur_token_idx|
399
+ real_idx = token_idx + 1 + cur_token_idx
400
+ break if cur_token.type == :RBRACE
401
+ end
402
+
403
+ defaults << {
404
+ :start => token_idx,
405
+ :end => real_idx,
406
+ :tokens => tokens[token_idx..real_idx],
407
+ }
408
+ end
409
+ end
410
+ defaults
411
+ end.call
412
+ end
413
+
414
+ # Internal: Finds all the tokens that make up the defined type or class
415
+ # definition parameters.
416
+ #
417
+ # these_tokens - An Array of PuppetLint::Lexer::Token objects that make up
418
+ # the defined type or class definition.
419
+ #
420
+ # Returns an Array of PuppetLint::Lexer::Token objects or nil if it takes
421
+ # no parameters.
422
+ def param_tokens(these_tokens)
423
+ depth = 0
424
+ lparen_idx = nil
425
+ rparen_idx = nil
426
+
427
+ these_tokens.each_with_index do |token, i|
428
+ if token.type == :LPAREN
429
+ depth += 1
430
+ lparen_idx = i if depth == 1
431
+ elsif token.type == :RPAREN
432
+ depth -= 1
433
+ if depth == 0
434
+ rparen_idx = i
435
+ break
436
+ end
437
+ elsif token.type == :LBRACE && depth == 0
438
+ # no parameters
439
+ break
440
+ end
441
+ end
442
+
443
+ if lparen_idx.nil? or rparen_idx.nil?
444
+ nil
445
+ else
446
+ these_tokens[(lparen_idx + 1)..(rparen_idx - 1)]
447
+ end
448
+ end
449
+
450
+ # Internal: Retrieves a list of token types that are considered to be
451
+ # formatting tokens (whitespace, newlines, etc).
452
+ #
453
+ # Returns an Array of Symbols.
454
+ def formatting_tokens
455
+ @formatting_tokens ||= PuppetLint::Lexer::FORMATTING_TOKENS
456
+ end
457
+
458
+ # Internal: Retrieves a Hash of Sets. Each key is a check name Symbol and
459
+ # the Set of Integers returned lists all the lines that the check results
460
+ # should be ignored on.
461
+ #
462
+ # Returns a Hash of Sets of Integers.
463
+ def ignore_overrides
464
+ @ignore_overrides ||= {}
465
+ end
466
+
467
+ # Internal: Parses all COMMENT, MLCOMMENT and SLASH_COMMENT tokens looking
468
+ # for control comments (comments that enable or disable checks). Builds the
469
+ # contents of the `ignore_overrides` hash.
470
+ #
471
+ # Returns nothing.
472
+ def parse_control_comments
473
+ @ignore_overrides.each_key { |check| @ignore_overrides[check].clear }
474
+ control_re = /\A(lint:\S+)(\s+lint:\S+)*(.*)/
475
+
476
+ comment_token_types = Set[:COMMENT, :MLCOMMENT, :SLASH_COMMENT]
477
+
478
+ comment_tokens = tokens.select { |token|
479
+ comment_token_types.include?(token.type)
480
+ }
481
+ control_comment_tokens = comment_tokens.select { |token|
482
+ token.value.strip =~ /\Alint:(ignore:[\w\d]+|endignore)/
483
+ }
484
+
485
+ stack = []
486
+ control_comment_tokens.each do |token|
487
+ comment_data = control_re.match(token.value.strip).to_a[1..-1].compact.map(&:strip)
488
+ if comment_data.last =~ /\Alint:(ignore|endignore)/
489
+ comment_data << ''
490
+ end
491
+ reason = comment_data.pop
492
+ stack_add = []
493
+ comment_data.each do |control|
494
+ split_control = control.split(':')
495
+ command = split_control[1]
496
+
497
+ if command == 'ignore'
498
+ check = split_control[2].to_sym
499
+
500
+ if token.prev_token && !Set[:NEWLINE, :INDENT].include?(token.prev_token.type)
501
+ # control comment at the end of the line, override applies to
502
+ # a single line only
503
+ (ignore_overrides[check] ||= {})[token.line] = reason
504
+ else
505
+ stack_add << [token.line, reason, check]
506
+ end
507
+ else
508
+ stack.pop.each do |start|
509
+ unless start.nil?
510
+ (start[0]..token.line).each do |i|
511
+ (ignore_overrides[start[2]] ||= {})[i] = start[1]
512
+ end
513
+ end
514
+ end
515
+ end
516
+ end
517
+ stack << stack_add unless stack_add.empty?
518
+ end
519
+ end
520
+ end
521
+ end