puppet-lint 2.3.6 → 2.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
- SHA1:
3
- metadata.gz: 299ce7a01574b87c32ac76798f691800ef27fc2c
4
- data.tar.gz: 4f3f73a44040dbfc0d6f3b2bfb6535b000d3bdf1
2
+ SHA256:
3
+ metadata.gz: b67dfbcf1aff9be2449b52eb8ff66db18cf025ad69ce6dee4f3e8a7ae4155980
4
+ data.tar.gz: 2eec8d5d37d1deeaaf9e26ca6ad24e7f841e137bb9de99e61736675862f6bffc
5
5
  SHA512:
6
- metadata.gz: 920ee6f31d30184faf6c288902f53387bba45df38976a854c7e837647520e8162e140303fad43a6b7de70be4c1b3efd1cede9fc2f93b377e0773442f66fe239d
7
- data.tar.gz: ab9bb35509a161c70c73b4880b737e39416884d6709c166df95817b3fd6f6efce5329ca856f50644705907c776b631c61f658ecfa2bae1c7972e79310fc45cb4
6
+ metadata.gz: 80e81796c7aa00827859e45f6586105bbeb1c16c5a813e3130e8ff1fa11272c012dd86563d21172862a00852f49c0b0df2015881c83e15b62e208e117c85e938
7
+ data.tar.gz: f21481a188185489015c3fa7dff8bd3d00e5eec505a547abc4c7633805c41e275f311eec37f5c4a93899ea77fb43a530ba25588fdbb0f78dc043f904d6716c1b
@@ -45,7 +45,7 @@ Metrics/BlockNesting:
45
45
  # Offense count: 2
46
46
  # Configuration parameters: CountComments.
47
47
  Metrics/ClassLength:
48
- Max: 383
48
+ Max: 384
49
49
 
50
50
  # Offense count: 20
51
51
  Metrics/CyclomaticComplexity:
@@ -64,7 +64,7 @@ Metrics/MethodLength:
64
64
 
65
65
  # Offense count: 18
66
66
  Metrics/PerceivedComplexity:
67
- Max: 25
67
+ Max: 28
68
68
 
69
69
  # Offense count: 1
70
70
  # Cop supports --auto-correct.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  language: ruby
3
+ dist: trusty
3
4
  sudo: false
4
- before_install: gem update --system && gem install bundler
5
5
  branches:
6
6
  only:
7
7
  - master
@@ -15,10 +15,12 @@ rvm:
15
15
  - 1.9.3
16
16
  - 2.0.0
17
17
  - 2.1.10
18
- - 2.2.7
19
- - 2.3.4
20
- - 2.4.1
18
+ - 2.2.10
19
+ - 2.3.8
20
+ - 2.4.7
21
+ - 2.5.6
22
+ - 2.6.4
21
23
  matrix:
22
24
  include:
23
- - rvm: 2.4.1
25
+ - rvm: 2.6.4
24
26
  env: CHECK=rubocop
@@ -1,5 +1,58 @@
1
1
  # Change Log
2
2
 
3
+ ## [2.4.0](https://github.com/rodjek/puppet-lint/tree/2.4.0) (2019-10-08)
4
+ [Full Changelog](https://github.com/rodjek/puppet-lint/compare/2.3.6...2.4.0)
5
+
6
+ **Fixed bugs:**
7
+
8
+ - Command line options do not override options from config files [\#879](https://github.com/rodjek/puppet-lint/issues/879)
9
+ - Fix for variables\_not\_enclosed incorrectly handles variables followed by a dash [\#836](https://github.com/rodjek/puppet-lint/issues/836)
10
+ - Syntax error on Pattern data type [\#833](https://github.com/rodjek/puppet-lint/issues/833)
11
+ - Error with puppet-lint --fix: NoMethodError: undefined method `next\_token' for nil:NilClass [\#831](https://github.com/rodjek/puppet-lint/issues/831)
12
+ - TypeError: no implicit conversion of nil into String [\#830](https://github.com/rodjek/puppet-lint/issues/830)
13
+ - Selector with 'default' case disables check for missing default in outer case statement [\#829](https://github.com/rodjek/puppet-lint/issues/829)
14
+ - undefined method `next\_token' for nil:NilClass [\#824](https://github.com/rodjek/puppet-lint/issues/824)
15
+ - NoMethodError: undefined method `next\_token' for nil:NilClass [\#790](https://github.com/rodjek/puppet-lint/issues/790)
16
+ - Puppet-lint --fix silently removes necessary $ inside double quoted strings [\#773](https://github.com/rodjek/puppet-lint/issues/773)
17
+ - It looks like puppet-lint has encountered an error that it doesn't know how to handle [\#768](https://github.com/rodjek/puppet-lint/issues/768)
18
+ - puppet-lint lexer string interpolation needs to be updated to match PUP-5887 changes [\#747](https://github.com/rodjek/puppet-lint/issues/747)
19
+ - Syntax error causes 'Whoops!' [\#740](https://github.com/rodjek/puppet-lint/issues/740)
20
+ - "quoted boolean value found" in hash value should not raise a warning. [\#474](https://github.com/rodjek/puppet-lint/issues/474)
21
+
22
+ **Closed issues:**
23
+
24
+ - Error when running puppet-lint [\#862](https://github.com/rodjek/puppet-lint/issues/862)
25
+ - puppet-lint crashes with mispelled namespace seperators [\#853](https://github.com/rodjek/puppet-lint/issues/853)
26
+ - NoMethodError: undefined method `prev\_token' for nil:NilClass [\#845](https://github.com/rodjek/puppet-lint/issues/845)
27
+ - Lint incorrectly errors on quoted bool [\#844](https://github.com/rodjek/puppet-lint/issues/844)
28
+ - Type\[\]\] raises NoMethodError [\#843](https://github.com/rodjek/puppet-lint/issues/843)
29
+ - Whoops! It looks like puppet-lint has encountered an error that it doesn't know how to handle. [\#842](https://github.com/rodjek/puppet-lint/issues/842)
30
+ - Whoops! It looks like puppet-lint has encountered an error that it doesn't [\#838](https://github.com/rodjek/puppet-lint/issues/838)
31
+ - Incorrectly wrapped hash variable inside double quotes [\#826](https://github.com/rodjek/puppet-lint/issues/826)
32
+ - Test puppet-lint against Ruby 2.5.x [\#818](https://github.com/rodjek/puppet-lint/issues/818)
33
+ - nested ensure misdetected as not coming first. [\#410](https://github.com/rodjek/puppet-lint/issues/410)
34
+
35
+ **Merged pull requests:**
36
+
37
+ - Handle unenclosed variables followed by dashes when fixing [\#881](https://github.com/rodjek/puppet-lint/pull/881) ([rodjek](https://github.com/rodjek))
38
+ - Let command line args override config from files [\#880](https://github.com/rodjek/puppet-lint/pull/880) ([usev6](https://github.com/usev6))
39
+ - Ignore hash keys when checking resource parameter order [\#877](https://github.com/rodjek/puppet-lint/pull/877) ([rodjek](https://github.com/rodjek))
40
+ - Only look for 'default' at first level of 'case' statement [\#876](https://github.com/rodjek/puppet-lint/pull/876) ([usev6](https://github.com/usev6))
41
+ - Report syntax error on unbalanced braces [\#875](https://github.com/rodjek/puppet-lint/pull/875) ([rodjek](https://github.com/rodjek))
42
+ - Include hash/array references when enclosing variables [\#874](https://github.com/rodjek/puppet-lint/pull/874) ([rodjek](https://github.com/rodjek))
43
+ - Disable quoted\_booleans check by default [\#873](https://github.com/rodjek/puppet-lint/pull/873) ([rodjek](https://github.com/rodjek))
44
+ - Test against Ruby 2.5 & 2.6 [\#872](https://github.com/rodjek/puppet-lint/pull/872) ([rodjek](https://github.com/rodjek))
45
+ - README - Add GitHub Actions action [\#868](https://github.com/rodjek/puppet-lint/pull/868) ([ScottBrenner](https://github.com/ScottBrenner))
46
+ - Update TravisCI config to use trusty image [\#867](https://github.com/rodjek/puppet-lint/pull/867) ([rodjek](https://github.com/rodjek))
47
+ - Use the default travis rubygems & bundler [\#860](https://github.com/rodjek/puppet-lint/pull/860) ([rodjek](https://github.com/rodjek))
48
+ - Add `Sensitive` to the list of KNOWN\_TOKEN TYPES [\#858](https://github.com/rodjek/puppet-lint/pull/858) ([alexjfisher](https://github.com/alexjfisher))
49
+ - Avoid internal error for typoed namespace [\#855](https://github.com/rodjek/puppet-lint/pull/855) ([usev6](https://github.com/usev6))
50
+ - Use lookahead assertion for matching function name [\#854](https://github.com/rodjek/puppet-lint/pull/854) ([usev6](https://github.com/usev6))
51
+ - Resource: fix nested ensure error. [\#848](https://github.com/rodjek/puppet-lint/pull/848) ([keur](https://github.com/keur))
52
+ - Rewrite double quoted string handling for nested interpolation [\#846](https://github.com/rodjek/puppet-lint/pull/846) ([rodjek](https://github.com/rodjek))
53
+ - Allow for spaces in the heredoc tag [\#841](https://github.com/rodjek/puppet-lint/pull/841) ([jarretlavallee](https://github.com/jarretlavallee))
54
+ - Recognizes multiline regexes [\#835](https://github.com/rodjek/puppet-lint/pull/835) ([jcbollinger](https://github.com/jcbollinger))
55
+
3
56
  ## [2.3.6](https://github.com/rodjek/puppet-lint/tree/2.3.6) (2018-07-09)
4
57
  [Full Changelog](https://github.com/rodjek/puppet-lint/compare/2.3.5...2.3.6)
5
58
 
data/README.md CHANGED
@@ -120,6 +120,18 @@ Or to specify a whitelist of allowed checks, include a line like:
120
120
  --only-checks=trailing_whitespace,hard_tabs,duplicate_params,double_quoted_strings,unquoted_file_mode,only_variable_string,variables_not_enclosed,single_quote_string_with_variables,variable_contains_dash,ensure_not_symlink_target,unquoted_resource_title,relative_classname_inclusion,file_mode,resource_reference_without_title_capital,leading_zero,arrow_alignment,variable_is_lowercase,ensure_first_param,resource_reference_without_whitespace,file_ensure,trailing_comma,leading_zero
121
121
  ```
122
122
 
123
+ Please note that there is an important difference between reading options from the command line and reading options from a configuration file: In the former case the shell interprets one level of quotes. That does not happen in the latter case. So, it would make sense to quote some configuration values on the command line, like so:
124
+
125
+ ```
126
+ $ puppet-lint --ignore-paths 'modules/stdlib/*' modules/
127
+ ```
128
+
129
+ When reading from a configuration file those quotes would be passed on to the option parser -- probably not giving the expected result. Instead the line should read
130
+
131
+ ```
132
+ --ignore-paths=modules/stdlib/*
133
+ ```
134
+
123
135
  ## Testing with Puppet Lint as a Rake task
124
136
 
125
137
  To test your entire Puppet manifest directory, add `require 'puppet-lint/tasks/puppet-lint'` to your Rakefile and then run:
@@ -195,6 +207,12 @@ You can also disable checks when running Puppet Lint through the supplied Rake t
195
207
  PuppetLint.configuration.pattern = "modules"
196
208
  ```
197
209
 
210
+ ## Testing with Puppet Lint as a GitHub Action
211
+
212
+ There is a GitHub Actions action available to get linter feedback in workflows:
213
+
214
+ * [puppet-lint-action](https://github.com/marketplace/actions/puppet-lint-action)
215
+
198
216
  ## Options
199
217
 
200
218
  See `puppet-lint --help` for a full list of command line options and checks.
@@ -13,6 +13,8 @@ environment:
13
13
  - RUBY_VERSION: 22
14
14
  - RUBY_VERSION: 23-x64
15
15
  - RUBY_VERSION: 24-x64
16
+ - RUBY_VERSION: 25-x64
17
+ - RUBY_VERSION: 26-x64
16
18
 
17
19
  matrix:
18
20
  allow_failures:
@@ -201,6 +201,9 @@ class PuppetLint::Data
201
201
  lbrace_idx = tokens[0..index].rindex do |token|
202
202
  token.type == :LBRACE && token.prev_code_token.type != :QMARK
203
203
  end
204
+
205
+ raise PuppetLint::SyntaxError, tokens[index] if lbrace_idx.nil?
206
+
204
207
  tokens[lbrace_idx].prev_code_token
205
208
  end
206
209
 
@@ -212,9 +215,21 @@ class PuppetLint::Data
212
215
  #
213
216
  # Returns an Array of Token objects.
214
217
  def find_resource_param_tokens(resource_tokens)
215
- resource_tokens.select do |token|
216
- token.type == :NAME && token.next_code_token.type == :FARROW
218
+ param_tokens = []
219
+
220
+ iter_token = resource_tokens.first.prev_token
221
+
222
+ until iter_token.nil?
223
+ iter_token = iter_token.next_token_of(:NAME)
224
+
225
+ break unless resource_tokens.include?(iter_token)
226
+
227
+ if iter_token && iter_token.next_code_token.type == :FARROW
228
+ param_tokens << iter_token
229
+ end
217
230
  end
231
+
232
+ param_tokens
218
233
  end
219
234
 
220
235
  # Internal: Calculate the positions of all class definitions within the
@@ -2,8 +2,9 @@
2
2
 
3
3
  require 'pp'
4
4
  require 'strscan'
5
- require 'puppet-lint/lexer/token'
6
5
  require 'set'
6
+ require 'puppet-lint/lexer/token'
7
+ require 'puppet-lint/lexer/string_slurper'
7
8
 
8
9
  class PuppetLint
9
10
  # Internal: A generic error thrown by the lexer when it encounters something
@@ -28,11 +29,15 @@ class PuppetLint
28
29
  @column = column
29
30
  @reason = reason
30
31
  end
32
+
33
+ def to_s
34
+ "PuppetLint::LexerError: Line:#{line_no} Column: #{column} Reason: #{reason}"
35
+ end
31
36
  end
32
37
 
33
38
  # Internal: The puppet-lint lexer. Converts your manifest into its tokenised
34
39
  # form.
35
- class Lexer # rubocop:disable Metrics/ClassLength
40
+ class Lexer
36
41
  def initialize
37
42
  @line_no = 1
38
43
  @column = 1
@@ -101,16 +106,27 @@ class PuppetLint
101
106
  :LPAREN => true,
102
107
  }.freeze
103
108
 
109
+ # Internal: some commonly used regular expressions
110
+ # \t == tab
111
+ # \v == vertical tab
112
+ # \f == form feed
113
+ # \p{Zs} == ASCII + Unicode non-linebreaking whitespace
114
+ WHITESPACE_RE = RUBY_VERSION == '1.8.7' ? %r{[\t\v\f ]} : %r{[\t\v\f\p{Zs}]}
115
+
116
+ LINE_END_RE = %r{(?:\r\n|\r|\n)}
117
+
118
+ NAME_RE = %r{\A((?:(?:::)?[_a-z0-9][-\w]*)(?:::[a-z0-9][-\w]*)*)}
119
+
104
120
  # Internal: An Array of Arrays containing tokens that can be described by
105
121
  # a single regular expression. Each sub-Array contains 2 elements, the
106
122
  # name of the token as a Symbol and a regular expression describing the
107
123
  # value of the token.
108
- NAME_RE = %r{\A(((::)?[_a-z0-9][-\w]*)(::[a-z0-9][-\w]*)*)}
109
124
  KNOWN_TOKENS = [
110
- [:TYPE, %r{\A(Integer|Float|Boolean|Regexp|String|Array|Hash|Resource|Class|Collection|Scalar|Numeric|CatalogEntry|Data|Tuple|Struct|Optional|NotUndef|Variant|Enum|Pattern|Any|Callable|Type|Runtime|Undef|Default)\b}],
125
+ [:WHITESPACE, %r{\A(#{WHITESPACE_RE}+)}],
126
+ [:TYPE, %r{\A(Integer|Float|Boolean|Regexp|String|Array|Hash|Resource|Class|Collection|Scalar|Numeric|CatalogEntry|Data|Tuple|Struct|Optional|NotUndef|Variant|Enum|Pattern|Any|Callable|Type|Runtime|Undef|Default|Sensitive)\b}], # rubocop:disable Metrics/LineLength
111
127
  [:CLASSREF, %r{\A(((::){0,1}[A-Z][-\w]*)+)}],
112
128
  [:NUMBER, %r{\A\b((?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?))\b}],
113
- [:FUNCTION_NAME, %r{#{NAME_RE}\(}],
129
+ [:FUNCTION_NAME, %r{#{NAME_RE}(?=\()}],
114
130
  [:NAME, NAME_RE],
115
131
  [:LBRACK, %r{\A(\[)}],
116
132
  [:RBRACK, %r{\A(\])}],
@@ -166,14 +182,6 @@ class PuppetLint
166
182
  :INDENT => true,
167
183
  }.freeze
168
184
 
169
- # \t == tab
170
- # \v == vertical tab
171
- # \f == form feed
172
- # \p{Zs} == ASCII + Unicode non-linebreaking whitespace
173
- WHITESPACE_RE = RUBY_VERSION == '1.8.7' ? %r{[\t\v\f ]} : %r{[\t\v\f\p{Zs}]}
174
-
175
- LINE_END_RE = %r{(?:\r\n|\r|\n)}
176
-
177
185
  # Internal: Access the internal token storage.
178
186
  #
179
187
  # Returns an Array of PuppetLint::Lexer::Toxen objects.
@@ -200,13 +208,12 @@ class PuppetLint
200
208
  value = chunk[regex, 1]
201
209
  next if value.nil?
202
210
 
203
- length = value.size
211
+ i += value.size
204
212
  tokens << if type == :NAME && KEYWORDS.include?(value)
205
213
  new_token(value.upcase.to_sym, value)
206
214
  else
207
215
  new_token(type, value)
208
216
  end
209
- i += length
210
217
  found = true
211
218
  break
212
219
  end
@@ -215,7 +222,12 @@ class PuppetLint
215
222
 
216
223
  if var_name = chunk[%r{\A\$((::)?(\w+(-\w+)*::)*\w+(-\w+)*(\[.+?\])*)}, 1]
217
224
  length = var_name.size + 1
218
- tokens << new_token(:VARIABLE, var_name)
225
+ opts = if chunk.start_with?('$')
226
+ { :raw => "$#{var_name}" }
227
+ else
228
+ {}
229
+ end
230
+ tokens << new_token(:VARIABLE, var_name, opts)
219
231
 
220
232
  elsif chunk =~ %r{\A'.*?'}m
221
233
  str_content = StringScanner.new(code[i + 1..-1]).scan_until(%r{(\A|[^\\])(\\\\)*'}m)
@@ -223,12 +235,16 @@ class PuppetLint
223
235
  tokens << new_token(:SSTRING, str_content[0..-2])
224
236
 
225
237
  elsif chunk.start_with?('"')
226
- str_contents = slurp_string(code[i + 1..-1])
227
- lines_parsed = code[0..i].split(LINE_END_RE)
228
- interpolate_string(str_contents, lines_parsed.count, lines_parsed.last.length)
229
- length = str_contents.size + 1
238
+ slurper = PuppetLint::Lexer::StringSlurper.new(code[i + 1..-1])
239
+ begin
240
+ string_segments = slurper.parse
241
+ process_string_segments(string_segments)
242
+ length = slurper.consumed_bytes + 1
243
+ rescue PuppetLint::Lexer::StringSlurper::UnterminatedStringError
244
+ raise PuppetLint::LexerError, @line_no, @column, 'unterminated string'
245
+ end
230
246
 
231
- elsif heredoc_name = chunk[%r{\A@\(("?.+?"?(:.+?)?(/.*?)?)\)}, 1]
247
+ elsif heredoc_name = chunk[%r{\A@\(("?.+?"?(:.+?)?#{WHITESPACE_RE}*(/.*?)?)\)}, 1]
232
248
  heredoc_queue << heredoc_name
233
249
  tokens << new_token(:HEREDOC_OPEN, heredoc_name)
234
250
  length = heredoc_name.size + 3
@@ -251,7 +267,7 @@ class PuppetLint
251
267
  mlcomment.gsub!(%r{^ *\*}, '')
252
268
  tokens << new_token(:MLCOMMENT, mlcomment, :raw => mlcomment_raw)
253
269
 
254
- elsif chunk.match(%r{\A/.*?/}) && possible_regex?
270
+ elsif chunk.match(%r{\A/.*?/}m) && possible_regex?
255
271
  str_content = StringScanner.new(code[i + 1..-1]).scan_until(%r{(\A|[^\\])(\\\\)*/}m)
256
272
  length = str_content.size + 1
257
273
  tokens << new_token(:REGEX, str_content[0..-2])
@@ -267,29 +283,16 @@ class PuppetLint
267
283
  length += indent.size
268
284
  else
269
285
  heredoc_tag = heredoc_queue.shift
270
- heredoc_name = heredoc_tag[%r{\A"?(.+?)"?(:.+?)?(/.*)?\Z}, 1]
271
- str_contents = StringScanner.new(code[(i + length)..-1]).scan_until(%r{\|?\s*-?\s*#{heredoc_name}})
272
- interpolate_heredoc(str_contents, heredoc_tag)
273
- length += str_contents.size
286
+ slurper = PuppetLint::Lexer::StringSlurper.new(code[i + length..-1])
287
+ heredoc_segments = slurper.parse_heredoc(heredoc_tag)
288
+ process_heredoc_segments(heredoc_segments)
289
+ length += slurper.consumed_bytes
274
290
  end
275
291
 
276
- elsif whitespace = chunk[%r{\A(#{WHITESPACE_RE}+)}, 1]
277
- length = whitespace.size
278
- tokens << new_token(:WHITESPACE, whitespace)
279
-
280
292
  elsif eol = chunk[%r{\A(#{LINE_END_RE})}, 1]
281
293
  length = eol.size
282
294
  tokens << new_token(:NEWLINE, eol)
283
295
 
284
- unless heredoc_queue.empty?
285
- heredoc_tag = heredoc_queue.shift
286
- heredoc_name = heredoc_tag[%r{\A"?(.+?)"?(:.+?)?(/.*)?\Z}, 1]
287
- str_contents = StringScanner.new(code[(i + length)..-1]).scan_until(%r{\|?\s*-?\s*#{heredoc_name}})
288
- _ = code[0..(i + length)].split(LINE_END_RE)
289
- interpolate_heredoc(str_contents, heredoc_tag)
290
- length += str_contents.size
291
- end
292
-
293
296
  elsif chunk.start_with?('/')
294
297
  length = 1
295
298
  tokens << new_token(:DIV, '/')
@@ -308,22 +311,6 @@ class PuppetLint
308
311
  tokens
309
312
  end
310
313
 
311
- def slurp_string(string)
312
- dq_str_regexp = %r{(\$\{|(\A|[^\\])(\\\\)*")}m
313
- scanner = StringScanner.new(string)
314
- contents = scanner.scan_until(dq_str_regexp)
315
-
316
- if scanner.matched.nil?
317
- raise LexerError.new(@line_no, @column, 'Double quoted string missing closing quote')
318
- end
319
-
320
- until scanner.matched.end_with?('"')
321
- contents += scanner.scan_until(%r{\}}m)
322
- contents += scanner.scan_until(dq_str_regexp)
323
- end
324
- contents
325
- end
326
-
327
314
  # Internal: Given the tokens already processed, determine if the next token
328
315
  # could be a regular expression.
329
316
  #
@@ -403,167 +390,66 @@ class PuppetLint
403
390
  token
404
391
  end
405
392
 
406
- # Internal: Split a string on multiple terminators, excluding escaped
407
- # terminators.
408
- #
409
- # string - The String to be split.
410
- # terminators - The String of terminators that the String should be split
411
- # on.
412
- #
413
- # Returns an Array consisting of two Strings, the String up to the first
414
- # terminator and the terminator that was found.
415
- def get_string_segment(string, terminators)
416
- str = string.scan_until(%r{([^\\]|^|[^\\])([\\]{2})*[#{terminators}]+})
417
- begin
418
- [str[0..-2], str[-1, 1]]
419
- rescue
420
- [nil, nil]
393
+ def process_string_segments(segments)
394
+ return if segments.empty?
395
+
396
+ if segments.length == 1
397
+ tokens << new_token(:STRING, segments[0][1])
398
+ return
421
399
  end
422
- end
423
400
 
424
- # Internal: Tokenise the contents of a double quoted string.
425
- #
426
- # string - The String to be tokenised.
427
- # line - The Integer line number of the start of the passed string.
428
- # column - The Integer column number of the start of the passed string.
429
- #
430
- # Returns nothing.
431
- def interpolate_string(string, line, column)
432
- ss = StringScanner.new(string)
433
- first = true
434
- value, terminator = get_string_segment(ss, '"$')
435
- until value.nil?
436
- if terminator == '"'
437
- if first
438
- tokens << new_token(:STRING, value, :line => line, :column => column)
439
- first = false
440
- else
441
- token_column = column + (ss.pos - value.size)
442
- tokens << new_token(:DQPOST, value, :line => line, :column => token_column)
443
- line += value.scan(LINE_END_RE).size
444
- @column = column + ss.pos + 1
445
- @line_no = line
401
+ pre_segment = segments.delete_at(0)
402
+ post_segment = segments.delete_at(-1)
403
+
404
+ tokens << new_token(:DQPRE, pre_segment[1])
405
+ segments.each do |segment|
406
+ case segment[0]
407
+ when :INTERP
408
+ lexer = PuppetLint::Lexer.new
409
+ lexer.tokenise(segment[1])
410
+ lexer.tokens.each_with_index do |t, i|
411
+ type = i.zero? && t.type == :NAME ? :VARIABLE : t.type
412
+ tokens << new_token(type, t.value, :raw => t.raw)
446
413
  end
414
+ when :UNENC_VAR
415
+ tokens << new_token(:UNENC_VARIABLE, segment[1].gsub(%r{\A\$}, ''))
447
416
  else
448
- if first
449
- tokens << new_token(:DQPRE, value, :line => line, :column => column)
450
- first = false
451
- else
452
- token_column = column + (ss.pos - value.size)
453
- tokens << new_token(:DQMID, value, :line => line, :column => token_column)
454
- line += value.scan(LINE_END_RE).size
455
- end
456
- if ss.scan(%r{\{}).nil?
457
- var_name = ss.scan(%r{(::)?(\w+(-\w+)*::)*\w+(-\w+)*})
458
- if var_name.nil?
459
- token_column = column + ss.pos - 1
460
- tokens << new_token(:DQMID, '$', :line => line, :column => token_column)
461
- else
462
- token_column = column + (ss.pos - var_name.size)
463
- tokens << new_token(:UNENC_VARIABLE, var_name, :line => line, :column => token_column)
464
- end
465
- else
466
- line += value.scan(LINE_END_RE).size
467
- contents = ss.scan_until(%r{\}})[0..-2]
468
- raw = contents.dup
469
- if contents.match(%r{\A(::)?([\w-]+::)*[\w-]+(\[.+?\])*}) && !contents.match(%r{\A\w+\(})
470
- contents = "$#{contents}"
471
- end
472
- lexer = PuppetLint::Lexer.new
473
- lexer.tokenise(contents)
474
- lexer.tokens.each do |token|
475
- tok_col = column + token.column + (ss.pos - contents.size - 1)
476
- tok_line = token.line + line - 1
477
- tokens << new_token(token.type, token.value, :line => tok_line, :column => tok_col)
478
- end
479
- if lexer.tokens.length == 1 && lexer.tokens[0].type == :VARIABLE
480
- tokens.last.raw = raw
481
- end
482
- end
417
+ tokens << new_token(:DQMID, segment[1])
483
418
  end
484
- value, terminator = get_string_segment(ss, '"$')
485
419
  end
420
+ tokens << new_token(:DQPOST, post_segment[1])
486
421
  end
487
422
 
488
- # Internal: Tokenise the contents of a heredoc.
489
- #
490
- # string - The String to be tokenised.
491
- # name - The String name/endtext of the heredoc.
492
- #
493
- # Returns nothing.
494
- def interpolate_heredoc(string, name)
495
- ss = StringScanner.new(string)
496
- eos_text = name[%r{\A"?(.+?)"?(:.+?)?(/.*)?\Z}, 1]
497
- first = true
498
- interpolate = name.start_with?('"')
499
- value, terminator = get_heredoc_segment(ss, eos_text, interpolate)
500
- until value.nil?
501
- if terminator =~ %r{\A\|?\s*-?\s*#{Regexp.escape(eos_text)}}
502
- if first
503
- tokens << new_token(:HEREDOC, value, :raw => "#{value}#{terminator}")
504
- first = false
505
- else
506
- tokens << new_token(:HEREDOC_POST, value, :raw => "#{value}#{terminator}")
423
+ def process_heredoc_segments(segments)
424
+ return if segments.empty?
425
+
426
+ end_tag = segments.delete_at(-1)
427
+
428
+ if segments.length == 1
429
+ tokens << new_token(:HEREDOC, segments[0][1], :raw => "#{segments[0][1]}#{end_tag[1]}")
430
+ return
431
+ end
432
+
433
+ pre_segment = segments.delete_at(0)
434
+ post_segment = segments.delete_at(-1)
435
+
436
+ tokens << new_token(:HEREDOC_PRE, pre_segment[1])
437
+ segments.each do |segment|
438
+ case segment[0]
439
+ when :INTERP
440
+ lexer = PuppetLint::Lexer.new
441
+ lexer.tokenise(segment[1])
442
+ lexer.tokens.each_with_index do |t, i|
443
+ type = i.zero? && t.type == :NAME ? :VARIABLE : t.type
444
+ tokens << new_token(type, t.value, :raw => t.raw)
507
445
  end
446
+ when :UNENC_VAR
447
+ tokens << new_token(:UNENC_VARIABLE, segment[1].gsub(%r{\A\$}, ''))
508
448
  else
509
- if first
510
- tokens << new_token(:HEREDOC_PRE, value)
511
- first = false
512
- else
513
- tokens << new_token(:HEREDOC_MID, value)
514
- end
515
- if ss.scan(%r{\{}).nil?
516
- var_name = ss.scan(%r{(::)?(\w+(-\w+)*::)*\w+(-\w+)*})
517
- tokens << if var_name.nil?
518
- new_token(:HEREDOC_MID, '$')
519
- else
520
- new_token(:UNENC_VARIABLE, var_name)
521
- end
522
- else
523
- contents = ss.scan_until(%r{\}})[0..-2]
524
- raw = contents.dup
525
- if contents.match(%r{\A(::)?([\w-]+::)*[\w-]|(\[.+?\])*}) && !contents.match(%r{\A\w+\(})
526
- contents = "$#{contents}" unless contents.start_with?('$')
527
- end
528
-
529
- lexer = PuppetLint::Lexer.new
530
- lexer.tokenise(contents)
531
- lexer.tokens.each do |token|
532
- tokens << new_token(token.type, token.value)
533
- end
534
- if lexer.tokens.length == 1 && lexer.tokens[0].type == :VARIABLE
535
- tokens.last.raw = raw
536
- end
537
- end
449
+ tokens << new_token(:HEREDOC_MID, segment[1])
538
450
  end
539
- value, terminator = get_heredoc_segment(ss, eos_text, interpolate)
540
- end
541
- end
542
-
543
- # Internal: Splits a heredoc String into segments if it is to be
544
- # interpolated.
545
- #
546
- # string - The String heredoc.
547
- # eos_text - The String endtext for the heredoc.
548
- # interpolate - A Boolean that specifies whether this heredoc can contain
549
- # interpolated values (defaults to True).
550
- #
551
- # Returns an Array consisting of two Strings, the String up to the first
552
- # terminator and the terminator that was found.
553
- def get_heredoc_segment(string, eos_text, interpolate = true)
554
- regexp = if interpolate
555
- %r{(([^\\]|^|[^\\])([\\]{2})*[$]+|\|?\s*-?#{Regexp.escape(eos_text)})}
556
- else
557
- %r{\|?\s*-?#{Regexp.escape(eos_text)}}
558
- end
559
-
560
- str = string.scan_until(regexp)
561
- begin
562
- str =~ %r{\A(.*?)([$]+|\|?\s*-?#{Regexp.escape(eos_text)})\Z}m
563
- [Regexp.last_match(1), Regexp.last_match(2)]
564
- rescue
565
- [nil, nil]
566
451
  end
452
+ tokens << new_token(:HEREDOC_POST, post_segment[1], :raw => "#{post_segment[1]}#{end_tag[1]}")
567
453
  end
568
454
  end
569
455
  end