puppet-lint 0.4.0.pre1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/.travis.yml +3 -4
  2. data/Gemfile +2 -5
  3. data/README.md +2 -149
  4. data/Rakefile +0 -5
  5. data/lib/puppet-lint.rb +74 -20
  6. data/lib/puppet-lint/bin.rb +20 -85
  7. data/lib/puppet-lint/checkplugin.rb +158 -12
  8. data/lib/puppet-lint/checks.rb +39 -222
  9. data/lib/puppet-lint/configuration.rb +12 -31
  10. data/lib/puppet-lint/data.rb +329 -0
  11. data/lib/puppet-lint/lexer.rb +37 -30
  12. data/lib/puppet-lint/lexer/token.rb +14 -16
  13. data/lib/puppet-lint/monkeypatches/string_prepend.rb +6 -0
  14. data/lib/puppet-lint/optparser.rb +105 -0
  15. data/lib/puppet-lint/plugins.rb +28 -9
  16. data/lib/puppet-lint/plugins/check_classes.rb +162 -238
  17. data/lib/puppet-lint/plugins/check_comments.rb +40 -25
  18. data/lib/puppet-lint/plugins/check_conditionals.rb +16 -20
  19. data/lib/puppet-lint/plugins/check_documentation.rb +14 -20
  20. data/lib/puppet-lint/plugins/check_nodes.rb +23 -0
  21. data/lib/puppet-lint/plugins/check_resources.rb +127 -141
  22. data/lib/puppet-lint/plugins/check_strings.rb +133 -107
  23. data/lib/puppet-lint/plugins/check_variables.rb +11 -11
  24. data/lib/puppet-lint/plugins/check_whitespace.rb +86 -92
  25. data/lib/puppet-lint/tasks/puppet-lint.rb +17 -1
  26. data/lib/puppet-lint/version.rb +1 -1
  27. data/puppet-lint.gemspec +4 -2
  28. data/spec/fixtures/test/manifests/ignore.pp +1 -0
  29. data/spec/fixtures/test/manifests/ignore_reason.pp +1 -0
  30. data/spec/puppet-lint/bin_spec.rb +104 -84
  31. data/spec/puppet-lint/configuration_spec.rb +19 -19
  32. data/spec/puppet-lint/ignore_overrides_spec.rb +97 -0
  33. data/spec/puppet-lint/lexer/token_spec.rb +9 -9
  34. data/spec/puppet-lint/lexer_spec.rb +352 -325
  35. data/spec/puppet-lint/plugins/check_classes/autoloader_layout_spec.rb +77 -23
  36. data/spec/puppet-lint/plugins/check_classes/class_inherits_from_params_class_spec.rb +14 -12
  37. data/spec/puppet-lint/plugins/check_classes/inherits_across_namespaces_spec.rb +18 -14
  38. data/spec/puppet-lint/plugins/check_classes/names_containing_dash_spec.rb +30 -30
  39. data/spec/puppet-lint/plugins/check_classes/nested_classes_or_defines_spec.rb +31 -26
  40. data/spec/puppet-lint/plugins/check_classes/parameter_order_spec.rb +34 -28
  41. data/spec/puppet-lint/plugins/check_classes/right_to_left_relationship_spec.rb +14 -12
  42. data/spec/puppet-lint/plugins/check_classes/variable_scope_spec.rb +74 -30
  43. data/spec/puppet-lint/plugins/check_comments/slash_comments_spec.rb +27 -20
  44. data/spec/puppet-lint/plugins/check_comments/star_comments_spec.rb +78 -13
  45. data/spec/puppet-lint/plugins/check_conditionals/case_without_default_spec.rb +17 -12
  46. data/spec/puppet-lint/plugins/check_conditionals/selector_inside_resource_spec.rb +13 -10
  47. data/spec/puppet-lint/plugins/check_documentation/documentation_spec.rb +21 -16
  48. data/spec/puppet-lint/plugins/check_nodes/unquoted_node_name_spec.rb +69 -0
  49. data/spec/puppet-lint/plugins/check_resources/duplicate_params_spec.rb +42 -38
  50. data/spec/puppet-lint/plugins/check_resources/ensure_first_param_spec.rb +22 -10
  51. data/spec/puppet-lint/plugins/check_resources/ensure_not_symlink_target_spec.rb +81 -18
  52. data/spec/puppet-lint/plugins/check_resources/file_mode_spec.rb +69 -112
  53. data/spec/puppet-lint/plugins/check_resources/unquoted_file_mode_spec.rb +27 -20
  54. data/spec/puppet-lint/plugins/check_resources/unquoted_resource_title_spec.rb +177 -171
  55. data/spec/puppet-lint/plugins/check_strings/double_quoted_strings_spec.rb +165 -88
  56. data/spec/puppet-lint/plugins/check_strings/only_variable_string_spec.rb +97 -22
  57. data/spec/puppet-lint/plugins/check_strings/puppet_url_without_modules_spec.rb +25 -0
  58. data/spec/puppet-lint/plugins/check_strings/quoted_booleans_spec.rb +97 -111
  59. data/spec/puppet-lint/plugins/check_strings/single_quote_string_with_variables_spec.rb +10 -9
  60. data/spec/puppet-lint/plugins/check_strings/variables_not_enclosed_spec.rb +53 -53
  61. data/spec/puppet-lint/plugins/check_variables/variable_contains_dash_spec.rb +26 -14
  62. data/spec/puppet-lint/plugins/check_whitespace/2sp_soft_tabs_spec.rb +10 -9
  63. data/spec/puppet-lint/plugins/check_whitespace/80chars_spec.rb +31 -15
  64. data/spec/puppet-lint/plugins/check_whitespace/arrow_alignment_spec.rb +340 -322
  65. data/spec/puppet-lint/plugins/check_whitespace/hard_tabs_spec.rb +30 -23
  66. data/spec/puppet-lint/plugins/check_whitespace/trailing_whitespace_spec.rb +42 -41
  67. data/spec/puppet-lint_spec.rb +3 -3
  68. data/spec/spec_helper.rb +109 -116
  69. metadata +109 -50
  70. data/spec/puppet-lint/plugins/check_classes/class_parameter_defaults_spec.rb +0 -60
@@ -1,4 +1,6 @@
1
1
  class PuppetLint
2
+ # Public: A singleton class to store the running configuration of
3
+ # puppet-lint.
2
4
  class Configuration
3
5
  # Internal: Add helper methods for a new check to the
4
6
  # PuppetLint::Configuration object.
@@ -38,7 +40,9 @@ class PuppetLint
38
40
  # Public: Catch situations where options are being set for the first time
39
41
  # and create the necessary methods to get & set the option in the future.
40
42
  #
41
- # args[0] - The value to set the option to.
43
+ # args - An Array of values to set the option to.
44
+ # method - The String name of the option.
45
+ # block - Unused.
42
46
  #
43
47
  # Returns nothing.
44
48
  #
@@ -102,22 +106,12 @@ class PuppetLint
102
106
  # Internal: Register a new check.
103
107
  #
104
108
  # check - The String name of the check
105
- # b - The Block containing the logic of the check
109
+ # klass - The Class containing the check logic.
106
110
  #
107
111
  # Returns nothing.
108
- def add_check(check, &b)
112
+ def add_check(check, klass)
109
113
  self.class.add_check(check)
110
- check_method[check] = b
111
- end
112
-
113
- # Internal: Register a new check helper method.
114
- #
115
- # name - The String name of the method.
116
- # b - The Block containing the logic of the helper.
117
- #
118
- # Returns nothing.
119
- def add_helper(name, &b)
120
- helper_method[name] = b
114
+ check_object[check] = klass
121
115
  end
122
116
 
123
117
  # Internal: Access the internal storage for settings.
@@ -130,29 +124,15 @@ class PuppetLint
130
124
  # Internal: Access the internal storage for check method blocks.
131
125
  #
132
126
  # Returns a Hash containing all the check blocks.
133
- def check_method
134
- @check_method ||= {}
127
+ def check_object
128
+ @check_object ||= {}
135
129
  end
136
130
 
137
131
  # Public: Get a list of all the defined checks.
138
132
  #
139
133
  # Returns an Array of String check names.
140
134
  def checks
141
- check_method.keys
142
- end
143
-
144
- # Internal: Access the internal storage for helper method blocks.
145
- #
146
- # Returns a Hash containing all the helper blocks.
147
- def helper_method
148
- @helper_method ||= {}
149
- end
150
-
151
- # Public: Get a list of all the helper methods.
152
- #
153
- # Returns an Array of String method names.
154
- def helpers
155
- helper_method.keys
135
+ check_object.keys
156
136
  end
157
137
 
158
138
  # Public: Clear the PuppetLint::Configuration storage and set some sane
@@ -167,6 +147,7 @@ class PuppetLint
167
147
  self.log_format = ''
168
148
  self.with_context = false
169
149
  self.fix = false
150
+ self.show_ignored = false
170
151
  end
171
152
  end
172
153
  end
@@ -0,0 +1,329 @@
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
+ end
29
+
30
+ # Public: Get the tokenised manifest.
31
+ #
32
+ # Returns an Array of PuppetLint::Lexer::Token objects.
33
+ def tokens
34
+ if caller[0][/`.*'/][1..-2] == 'check'
35
+ @tokens.dup
36
+ else
37
+ @tokens
38
+ end
39
+ end
40
+
41
+ # Internal: Store the path to the manifest file and populate fullpath and
42
+ # filename.
43
+ #
44
+ # val - The path to the file as a String.
45
+ #
46
+ # Returns nothing.
47
+ def path=(val)
48
+ @path = val
49
+ if val.nil?
50
+ @fullpath = nil
51
+ @filename = nil
52
+ else
53
+ @fullpath = File.expand_path(val, ENV['PWD'])
54
+ @filename = File.basename(val)
55
+ end
56
+ end
57
+
58
+ # Internal: Retrieve a list of tokens that represent resource titles
59
+ #
60
+ # Returns an Array of PuppetLint::Lexer::Token objects.
61
+ def title_tokens
62
+ @title_tokens ||= Proc.new do
63
+ result = []
64
+ tokens.each_index do |token_idx|
65
+ if tokens[token_idx].type == :COLON
66
+ # gather a list of tokens that are resource titles
67
+ if tokens[token_idx-1].type == :RBRACK
68
+ array_start_idx = tokens.rindex { |r|
69
+ r.type == :LBRACK
70
+ }
71
+ title_array_tokens = tokens[(array_start_idx + 1)..(token_idx - 2)]
72
+ result += title_array_tokens.select { |token|
73
+ {:STRING => true, :NAME => true}.include? token.type
74
+ }
75
+ else
76
+ next_token = tokens[token_idx].next_code_token
77
+ if next_token.type != :LBRACE
78
+ result << tokens[token_idx - 1]
79
+ end
80
+ end
81
+ end
82
+ end
83
+ result
84
+ end.call
85
+ end
86
+
87
+ # Internal: Calculate the positions of all resource declarations within the
88
+ # tokenised manifest. These positions only point to the content of the
89
+ # resource declarations, they do not include resource types or titles.
90
+ #
91
+ # Returns an Array of Hashes, each containing:
92
+ # :start - An Integer position in the `tokens` Array pointing to the
93
+ # first Token of a resource declaration.
94
+ # :end - An Integer position in the `tokens` Array pointing to the last
95
+ # Token of a resource declaration.
96
+ def resource_indexes
97
+ @resource_indexes ||= Proc.new do
98
+ result = []
99
+ tokens.each_index do |token_idx|
100
+ if tokens[token_idx].type == :COLON
101
+ next_token = tokens[token_idx].next_code_token
102
+ depth = 1
103
+ if next_token.type != :LBRACE
104
+ tokens[(token_idx + 1)..-1].each_index do |idx|
105
+ real_idx = token_idx + idx + 1
106
+ if tokens[real_idx].type == :LBRACE
107
+ depth += 1
108
+ elsif {:SEMIC => true, :RBRACE => true}.include? tokens[real_idx].type
109
+ unless tokens[real_idx].type == :SEMIC && depth > 1
110
+ depth -= 1
111
+ if depth == 0
112
+ result << {
113
+ :start => token_idx + 1,
114
+ :end => real_idx,
115
+ :tokens => tokens[(token_idx + 1)..real_idx],
116
+ :type => find_resource_type_token(token_idx),
117
+ :param_tokens => find_resource_param_tokens(tokens[(token_idx + 1)..real_idx]),
118
+ }
119
+ break
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ result
128
+ end.call
129
+ end
130
+
131
+ # Internal: Find the Token representing the type of a resource definition.
132
+ #
133
+ # index - The Integer pointing to the start of the resource in the `tokens`
134
+ # array.
135
+ #
136
+ # Returns a Token object.
137
+ def find_resource_type_token(index)
138
+ tokens[tokens[0..index].rindex { |token| token.type == :LBRACE }].prev_code_token
139
+ end
140
+
141
+ # Internal: Find all the Token objects representing the parameter names in
142
+ # a resource definition.
143
+ #
144
+ # resource_tokens - An Array of Token objects that comprise the resource
145
+ # definition.
146
+ #
147
+ # Returns an Array of Token objects.
148
+ def find_resource_param_tokens(resource_tokens)
149
+ resource_tokens.select { |token|
150
+ token.type == :NAME && token.next_code_token.type == :FARROW
151
+ }
152
+ end
153
+
154
+ # Internal: Calculate the positions of all class definitions within the
155
+ # `tokens` Array.
156
+ #
157
+ # Returns an Array of Hashes, each containing:
158
+ # :start - An Integer position in the `tokens` Array pointing to the
159
+ # first Token of a class definition.
160
+ # :end - An Integer position in the `tokens` Array pointing to the last
161
+ # Token of a class definition.
162
+ # :tokens - An Array consisting of all the Token objects that make up the
163
+ # class definition.
164
+ def class_indexes
165
+ @class_indexes ||= definition_indexes(:CLASS)
166
+ end
167
+
168
+ # Internal: Calculate the positions of all defined type definitions within
169
+ # the `tokens` Array.
170
+ #
171
+ # Returns an Array of Hashes, each containing:
172
+ # :start - An Integer position in the `tokens` Array pointing to the
173
+ # first Token of a defined type definition.
174
+ # :end - An Integer position in the `tokens` Array pointing to the last
175
+ # Token of a defined type definition.
176
+ # :tokens - An Array consisting of all the Token objects that make up the
177
+ # defined type.
178
+ def defined_type_indexes
179
+ @defined_type_indexes ||= definition_indexes(:DEFINE)
180
+ end
181
+
182
+ # Internal: Calculate the positions of all the specified defintion types
183
+ # within the `tokens` Array.
184
+ #
185
+ # Returns an Array of Hashes, each containing:
186
+ # :start - An Integer position in the `tokens` Array pointing to the
187
+ # first Token of a definition.
188
+ # :end - An Integer position in the `tokens` Array pointing to the last
189
+ # Token of a definition.
190
+ # :tokens - An Array consisting of all the Token objects that make up the
191
+ # definition.
192
+ def definition_indexes(type)
193
+ result = []
194
+ tokens.each_with_index do |token, i|
195
+ if token.type == type
196
+ brace_depth = 0
197
+ paren_depth = 0
198
+ in_params = false
199
+ inherited_class = nil
200
+ tokens[i+1..-1].each_with_index do |definition_token, j|
201
+ case definition_token.type
202
+ when :INHERITS
203
+ inherited_class = definition_token.next_code_token
204
+ when :LPAREN
205
+ in_params = true if paren_depth == 0
206
+ paren_depth += 1
207
+ when :RPAREN
208
+ in_params = false if paren_depth == 1
209
+ paren_depth -= 1
210
+ when :LBRACE
211
+ brace_depth += 1
212
+ when :RBRACE
213
+ brace_depth -= 1
214
+ if brace_depth == 0 && !in_params
215
+ if token.next_code_token.type != :LBRACE
216
+ result << {
217
+ :start => i,
218
+ :end => i + j + 1,
219
+ :tokens => tokens[i..(i + j + 1)],
220
+ :param_tokens => param_tokens(tokens[i..(i + j + 1)]),
221
+ :type => type,
222
+ :name_token => token.next_code_token,
223
+ :inherited_token => inherited_class,
224
+ }
225
+ break
226
+ end
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+ result
233
+ end
234
+
235
+ # Internal: Finds all the tokens that make up the defined type or class
236
+ # definition parameters.
237
+ #
238
+ # these_tokens - An Array of PuppetLint::Lexer::Token objects that make up
239
+ # the defined type or class definition.
240
+ #
241
+ # Returns an Array of PuppetLint::Lexer::Token objects or nil if it takes
242
+ # no parameters.
243
+ def param_tokens(these_tokens)
244
+ depth = 0
245
+ lparen_idx = nil
246
+ rparen_idx = nil
247
+
248
+ these_tokens.each_with_index do |token, i|
249
+ if token.type == :LPAREN
250
+ depth += 1
251
+ lparen_idx = i if depth == 1
252
+ elsif token.type == :RPAREN
253
+ depth -= 1
254
+ if depth == 0
255
+ rparen_idx = i
256
+ break
257
+ end
258
+ end
259
+ end
260
+
261
+ if lparen_idx.nil? or rparen_idx.nil?
262
+ nil
263
+ else
264
+ these_tokens[(lparen_idx + 1)..(rparen_idx - 1)]
265
+ end
266
+ end
267
+
268
+ # Internal: Retrieves a list of token types that are considered to be
269
+ # formatting tokens (whitespace, newlines, etc).
270
+ #
271
+ # Returns an Array of Symbols.
272
+ def formatting_tokens
273
+ @formatting_tokens ||= PuppetLint::Lexer::FORMATTING_TOKENS
274
+ end
275
+
276
+ # Internal: Retrieves a Hash of Sets. Each key is a check name Symbol and
277
+ # the Set of Integers returned lists all the lines that the check results
278
+ # should be ignored on.
279
+ #
280
+ # Returns a Hash of Sets of Integers.
281
+ def ignore_overrides
282
+ @ignore_overrides ||= {}
283
+ end
284
+
285
+ # Internal: Parses all COMMENT, MLCOMMENT and SLASH_COMMENT tokens looking
286
+ # for control comments (comments that enable or disable checks). Builds the
287
+ # contents of the `ignore_overrides` hash.
288
+ #
289
+ # Returns nothing.
290
+ def parse_control_comments
291
+ @ignore_overrides.each_key { |check| @ignore_overrides[check].clear }
292
+
293
+ comment_token_types = Set[:COMMENT, :MLCOMMENT, :SLASH_COMMENT]
294
+
295
+ comment_tokens = tokens.select { |token|
296
+ comment_token_types.include?(token.type)
297
+ }
298
+ control_comment_tokens = comment_tokens.select { |token|
299
+ token.value.strip =~ /\Alint:(ignore:[\w\d]+|endignore)/
300
+ }
301
+
302
+ stack = []
303
+ control_comment_tokens.each do |token|
304
+ control, reason = token.value.strip.split(' ', 2)
305
+ split_control = control.split(':')
306
+ command = split_control[1]
307
+
308
+ if command == 'ignore'
309
+ check = split_control[2].to_sym
310
+
311
+ if token.prev_token && !Set[:NEWLINE, :INDENT].include?(token.prev_token.type)
312
+ # control comment at the end of the line, override applies to
313
+ # a single line only
314
+ (ignore_overrides[check] ||= {})[token.line] = reason
315
+ else
316
+ stack << [token.line, reason, check]
317
+ end
318
+ else
319
+ start = stack.pop
320
+ unless start.nil?
321
+ (start[0]..token.line).each do |i|
322
+ (ignore_overrides[start[2]] ||= {})[i] = start[1]
323
+ end
324
+ end
325
+ end
326
+ end
327
+ end
328
+ end
329
+ end
@@ -4,6 +4,8 @@ require 'puppet-lint/lexer/token'
4
4
  require 'set'
5
5
 
6
6
  class PuppetLint
7
+ # Internal: A generic error thrown by the lexer when it encounters something
8
+ # it can't handle.
7
9
  class LexerError < StandardError
8
10
  # Internal: Get the Integer line number of the location of the error.
9
11
  attr_reader :line_no
@@ -18,16 +20,18 @@ class PuppetLint
18
20
  # at when it encountered the error.
19
21
  def initialize(code, offset)
20
22
  chunk = code[0..offset]
21
- @line_no = chunk.count("\n") + 1
23
+ @line_no = chunk.scan(/(\r\n|\r|\n)/).size + 1
22
24
  if @line_no == 1
23
25
  @column = chunk.length
24
26
  else
25
- @column = chunk.length - chunk.rindex("\n") - 1
27
+ @column = chunk.length - chunk.rindex(/(\r\n|\r|\n)/) - 1
26
28
  end
27
29
  @column = 1 if @column == 0
28
30
  end
29
31
  end
30
32
 
33
+ # Internal: The puppet-lint lexer. Converts your manifest into its tokenised
34
+ # form.
31
35
  class Lexer
32
36
  # Internal: A Hash whose keys are Strings representing reserved keywords in
33
37
  # the Puppet DSL.
@@ -109,6 +113,8 @@ class PuppetLint
109
113
  [:QMARK, /\A(\?)/],
110
114
  [:BACKSLASH, /\A(\\)/],
111
115
  [:TIMES, /\A(\*)/],
116
+ [:MODULO, /\A(%)/],
117
+ [:PIPE, /\A(\|)/],
112
118
  ]
113
119
 
114
120
  # Internal: A Hash whose keys are Symbols representing token types which
@@ -138,8 +144,6 @@ class PuppetLint
138
144
  # Raises PuppetLint::LexerError if it encounters unexpected characters
139
145
  # (usually the result of syntax errors).
140
146
  def tokenise(code)
141
- code.chomp!
142
-
143
147
  i = 0
144
148
 
145
149
  while i < code.size
@@ -165,7 +169,7 @@ class PuppetLint
165
169
  end
166
170
 
167
171
  unless found
168
- if var_name = chunk[/\A\$((::)?([\w-]+::)*[\w-]+)/, 1]
172
+ if var_name = chunk[/\A\$((::)?([\w-]+::)*[\w-]+(\[.+?\])*)/, 1]
169
173
  tokens << new_token(:VARIABLE, var_name, :chunk => code[0..i])
170
174
  i += var_name.size + 1
171
175
 
@@ -182,13 +186,13 @@ class PuppetLint
182
186
 
183
187
  elsif comment = chunk[/\A(#.*)/, 1]
184
188
  comment_size = comment.size
185
- comment.sub!(/# ?/, '')
189
+ comment.sub!(/#/, '')
186
190
  tokens << new_token(:COMMENT, comment, :chunk => code[0..i])
187
191
  i += comment_size
188
192
 
189
193
  elsif slash_comment = chunk[/\A(\/\/.*)/, 1]
190
194
  slash_comment_size = slash_comment.size
191
- slash_comment.sub!(/\/\/ ?/, '')
195
+ slash_comment.sub!(/\/\//, '')
192
196
  tokens << new_token(:SLASH_COMMENT, slash_comment, :chunk => code[0..i])
193
197
  i += slash_comment_size
194
198
 
@@ -206,18 +210,20 @@ class PuppetLint
206
210
  tokens << new_token(:REGEX, str_content[0..-2], :chunk => code[0..i])
207
211
  i += str_content.size + 1
208
212
 
209
- elsif indent = chunk[/\A\r?\n([ \t]+)/m, 1]
210
- tokens << new_token(:NEWLINE, '\n', :chunk => code[0..i])
211
- tokens << new_token(:INDENT, indent, :chunk => code[0..i+1])
212
- i += indent.size + 1
213
+ elsif eolindent = chunk[/\A((\r\n|\r|\n)[ \t]+)/m, 1]
214
+ eol = eolindent[/\A([\r\n]+)/m, 1]
215
+ indent = eolindent[/\A[\r\n]+([ \t]+)/m, 1]
216
+ tokens << new_token(:NEWLINE, eol, :chunk => code[0..i])
217
+ tokens << new_token(:INDENT, indent, :chunk => code[0..i+eol.size])
218
+ i += indent.size + eol.size
213
219
 
214
220
  elsif whitespace = chunk[/\A([ \t]+)/, 1]
215
221
  tokens << new_token(:WHITESPACE, whitespace, :chunk => code[0..i])
216
222
  i += whitespace.size
217
223
 
218
- elsif chunk.match(/\A\r?\n/)
219
- tokens << new_token(:NEWLINE, '\n', :chunk => code[0..i])
220
- i += 1
224
+ elsif eol = chunk[/\A(\r\n|\r|\n)/, 1]
225
+ tokens << new_token(:NEWLINE, eol, :chunk => code[0..i])
226
+ i += eol.size
221
227
 
222
228
  elsif chunk.match(/\A\//)
223
229
  tokens << new_token(:DIV, '/', :chunk => code[0..i])
@@ -265,11 +271,11 @@ class PuppetLint
265
271
  # Returns the instantiated PuppetLint::Lexer::Token object.
266
272
  def new_token(type, value, opts = {})
267
273
  if opts[:chunk]
268
- line_no = opts[:chunk].count("\n") + 1
274
+ line_no = opts[:chunk].scan(/(\r\n|\r|\n)/).size + 1
269
275
  if line_no == 1
270
276
  column = opts[:chunk].length
271
277
  else
272
- column = opts[:chunk].length - opts[:chunk].rindex("\n") - 1
278
+ column = opts[:chunk].length - opts[:chunk].rindex(/(\r\n|\r|\n)/) - 1
273
279
  end
274
280
  column += 1 if column == 0
275
281
  else
@@ -330,7 +336,7 @@ class PuppetLint
330
336
  tokens << new_token(:STRING, value, :line => line, :column => column)
331
337
  first = false
332
338
  else
333
- line += value.count("\n")
339
+ line += value.scan(/(\r\n|\r|\n)/).size
334
340
  token_column = column + (ss.pos - value.size)
335
341
  tokens << new_token(:DQPOST, value, :line => line, :column => token_column)
336
342
  end
@@ -339,29 +345,30 @@ class PuppetLint
339
345
  tokens << new_token(:DQPRE, value, :line => line, :column => column)
340
346
  first = false
341
347
  else
342
- line += value.count("\n")
348
+ line += value.scan(/(\r\n|\r|\n)/).size
343
349
  token_column = column + (ss.pos - value.size)
344
350
  tokens << new_token(:DQMID, value, :line => line, :column => token_column)
345
351
  end
346
352
  if ss.scan(/\{/).nil?
347
353
  var_name = ss.scan(/(::)?([\w-]+::)*[\w-]+/)
348
- unless var_name.nil?
354
+ if var_name.nil?
355
+ token_column = column + ss.pos - 1
356
+ tokens << new_token(:DQMID, "$", :line => line, :column => token_column)
357
+ else
349
358
  token_column = column + (ss.pos - var_name.size)
350
359
  tokens << new_token(:UNENC_VARIABLE, var_name, :line => line, :column => token_column)
351
360
  end
352
361
  else
353
362
  contents = ss.scan_until(/\}/)[0..-2]
354
- if contents.match(/\A(::)?([\w-]+::)*[\w-]+\Z/)
355
- token_column = column + (ss.pos - contents.size - 1)
356
- tokens << new_token(:VARIABLE, contents, :line => line, :column => token_column)
357
- else
358
- lexer = PuppetLint::Lexer.new
359
- lexer.tokenise(contents)
360
- lexer.tokens.each do |token|
361
- tok_col = column + token.column + (ss.pos - contents.size - 1)
362
- tok_line = token.line + line - 1
363
- tokens << new_token(token.type, token.value, :line => tok_line, :column => tok_col)
364
- end
363
+ if contents.match(/\A(::)?([\w-]+::)*[\w-]+(\[.+?\])*/)
364
+ contents = "$#{contents}"
365
+ end
366
+ lexer = PuppetLint::Lexer.new
367
+ lexer.tokenise(contents)
368
+ lexer.tokens.each do |token|
369
+ tok_col = column + token.column + (ss.pos - contents.size - 1)
370
+ tok_line = token.line + line - 1
371
+ tokens << new_token(token.type, token.value, :line => tok_line, :column => tok_col)
365
372
  end
366
373
  end
367
374
  end