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,373 @@
1
+ require 'pp'
2
+ require 'strscan'
3
+ require 'puppet-lint/lexer/token'
4
+ require 'set'
5
+
6
+ class PuppetLint
7
+ # Internal: A generic error thrown by the lexer when it encounters something
8
+ # it can't handle.
9
+ class LexerError < StandardError
10
+ # Internal: Get the Integer line number of the location of the error.
11
+ attr_reader :line_no
12
+
13
+ # Internal: Get the Integer column number of the location of the error.
14
+ attr_reader :column
15
+
16
+ # Internal: Initialise a new PuppetLint::LexerError object.
17
+ #
18
+ # line_no - The Integer line number of the location of the error.
19
+ # column - The Integer column number of the location of the error.
20
+ def initialize(line_no, column)
21
+ @line_no = line_no
22
+ @column = column
23
+ end
24
+ end
25
+
26
+ # Internal: The puppet-lint lexer. Converts your manifest into its tokenised
27
+ # form.
28
+ class Lexer
29
+ def initialize
30
+ @line_no = 1
31
+ @column = 1
32
+ end
33
+
34
+ # Internal: A Hash whose keys are Strings representing reserved keywords in
35
+ # the Puppet DSL.
36
+ KEYWORDS = {
37
+ 'class' => true,
38
+ 'case' => true,
39
+ 'default' => true,
40
+ 'define' => true,
41
+ 'import' => true,
42
+ 'if' => true,
43
+ 'else' => true,
44
+ 'elsif' => true,
45
+ 'inherits' => true,
46
+ 'node' => true,
47
+ 'and' => true,
48
+ 'or' => true,
49
+ 'undef' => true,
50
+ 'true' => true,
51
+ 'false' => true,
52
+ 'in' => true,
53
+ 'unless' => true,
54
+ }
55
+
56
+ # Internal: A Hash whose keys are Symbols representing token types which
57
+ # a regular expression can follow.
58
+ REGEX_PREV_TOKENS = {
59
+ :NODE => true,
60
+ :LBRACE => true,
61
+ :RBRACE => true,
62
+ :MATCH => true,
63
+ :NOMATCH => true,
64
+ :COMMA => true,
65
+ }
66
+
67
+ # Internal: An Array of Arrays containing tokens that can be described by
68
+ # a single regular expression. Each sub-Array contains 2 elements, the
69
+ # name of the token as a Symbol and a regular expression describing the
70
+ # value of the token.
71
+ KNOWN_TOKENS = [
72
+ [:CLASSREF, /\A(((::){0,1}[A-Z][-\w]*)+)/],
73
+ [:NUMBER, /\A\b((?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?))\b/],
74
+ [:NAME, /\A(((::)?[a-z0-9][-\w]*)(::[a-z0-9][-\w]*)*)/],
75
+ [:LBRACK, /\A(\[)/],
76
+ [:RBRACK, /\A(\])/],
77
+ [:LBRACE, /\A(\{)/],
78
+ [:RBRACE, /\A(\})/],
79
+ [:LPAREN, /\A(\()/],
80
+ [:RPAREN, /\A(\))/],
81
+ [:ISEQUAL, /\A(==)/],
82
+ [:MATCH, /\A(=~)/],
83
+ [:FARROW, /\A(=>)/],
84
+ [:EQUALS, /\A(=)/],
85
+ [:APPENDS, /\A(\+=)/],
86
+ [:PARROW, /\A(\+>)/],
87
+ [:PLUS, /\A(\+)/],
88
+ [:GREATEREQUAL, /\A(>=)/],
89
+ [:RSHIFT, /\A(>>)/],
90
+ [:GREATERTHAN, /\A(>)/],
91
+ [:LESSEQUAL, /\A(<=)/],
92
+ [:LLCOLLECT, /\A(<<\|)/],
93
+ [:OUT_EDGE, /\A(<-)/],
94
+ [:OUT_EDGE_SUB, /\A(<~)/],
95
+ [:LCOLLECT, /\A(<\|)/],
96
+ [:LSHIFT, /\A(<<)/],
97
+ [:LESSTHAN, /\A(<)/],
98
+ [:NOMATCH, /\A(!~)/],
99
+ [:NOTEQUAL, /\A(!=)/],
100
+ [:NOT, /\A(!)/],
101
+ [:RRCOLLECT, /\A(\|>>)/],
102
+ [:RCOLLECT, /\A(\|>)/],
103
+ [:IN_EDGE, /\A(->)/],
104
+ [:IN_EDGE_SUB, /\A(~>)/],
105
+ [:MINUS, /\A(-)/],
106
+ [:COMMA, /\A(,)/],
107
+ [:DOT, /\A(\.)/],
108
+ [:COLON, /\A(:)/],
109
+ [:AT, /\A(@)/],
110
+ [:SEMIC, /\A(;)/],
111
+ [:QMARK, /\A(\?)/],
112
+ [:BACKSLASH, /\A(\\)/],
113
+ [:TIMES, /\A(\*)/],
114
+ [:MODULO, /\A(%)/],
115
+ [:PIPE, /\A(\|)/],
116
+ ]
117
+
118
+ # Internal: A Hash whose keys are Symbols representing token types which
119
+ # are considered to be formatting tokens (i.e. tokens that don't contain
120
+ # code).
121
+ FORMATTING_TOKENS = {
122
+ :WHITESPACE => true,
123
+ :NEWLINE => true,
124
+ :COMMENT => true,
125
+ :MLCOMMENT => true,
126
+ :SLASH_COMMENT => true,
127
+ :INDENT => true,
128
+ }
129
+
130
+ # Internal: Access the internal token storage.
131
+ #
132
+ # Returns an Array of PuppetLint::Lexer::Toxen objects.
133
+ def tokens
134
+ @tokens ||= []
135
+ end
136
+
137
+ # Internal: Convert a Puppet manifest into tokens.
138
+ #
139
+ # code - The Puppet manifest to be tokenised as a String.
140
+ #
141
+ # Returns an Array of PuppetLint::Lexer::Token objects.
142
+ # Raises PuppetLint::LexerError if it encounters unexpected characters
143
+ # (usually the result of syntax errors).
144
+ def tokenise(code)
145
+ i = 0
146
+
147
+ while i < code.size
148
+ chunk = code[i..-1]
149
+
150
+ found = false
151
+
152
+ KNOWN_TOKENS.each do |type, regex|
153
+ if value = chunk[regex, 1]
154
+ length = value.size
155
+ if type == :NAME
156
+ if KEYWORDS.include? value
157
+ tokens << new_token(value.upcase.to_sym, value, length)
158
+ else
159
+ tokens << new_token(type, value, length)
160
+ end
161
+ else
162
+ tokens << new_token(type, value, length)
163
+ end
164
+ i += length
165
+ found = true
166
+ break
167
+ end
168
+ end
169
+
170
+ unless found
171
+ if var_name = chunk[/\A\$((::)?([\w-]+::)*[\w-]+(\[.+?\])*)/, 1]
172
+ length = var_name.size + 1
173
+ tokens << new_token(:VARIABLE, var_name, length)
174
+
175
+ elsif chunk.match(/\A'(.*?)'/m)
176
+ str_content = StringScanner.new(code[i+1..-1]).scan_until(/(\A|[^\\])(\\\\)*'/m)
177
+ length = str_content.size + 1
178
+ tokens << new_token(:SSTRING, str_content[0..-2], length)
179
+
180
+ elsif chunk.match(/\A"/)
181
+ str_contents = StringScanner.new(code[i+1..-1]).scan_until(/(\A|[^\\])(\\\\)*"/m)
182
+ _ = code[0..i].split("\n")
183
+ interpolate_string(str_contents, _.count, _.last.length)
184
+ length = str_contents.size + 1
185
+
186
+ elsif comment = chunk[/\A(#.*)/, 1]
187
+ length = comment.size
188
+ comment.sub!(/#/, '')
189
+ tokens << new_token(:COMMENT, comment, length)
190
+
191
+ elsif slash_comment = chunk[/\A(\/\/.*)/, 1]
192
+ length = slash_comment.size
193
+ slash_comment.sub!(/\/\//, '')
194
+ tokens << new_token(:SLASH_COMMENT, slash_comment, length)
195
+
196
+ elsif mlcomment = chunk[/\A(\/\*.*?\*\/)/m, 1]
197
+ length = mlcomment.size
198
+ mlcomment_raw = mlcomment.dup
199
+ mlcomment.sub!(/\A\/\* ?/, '')
200
+ mlcomment.sub!(/ ?\*\/\Z/, '')
201
+ mlcomment.gsub!(/^ *\*/, '')
202
+ tokens << new_token(:MLCOMMENT, mlcomment, length)
203
+ tokens.last.raw = mlcomment_raw
204
+
205
+ elsif chunk.match(/\A\/.*?\//) && possible_regex?
206
+ str_content = StringScanner.new(code[i+1..-1]).scan_until(/(\A|[^\\])(\\\\)*\//m)
207
+ length = str_content.size + 1
208
+ tokens << new_token(:REGEX, str_content[0..-2], length)
209
+
210
+ elsif eolindent = chunk[/\A((\r\n|\r|\n)[ \t]+)/m, 1]
211
+ eol = eolindent[/\A([\r\n]+)/m, 1]
212
+ indent = eolindent[/\A[\r\n]+([ \t]+)/m, 1]
213
+ tokens << new_token(:NEWLINE, eol, eol.size)
214
+ tokens << new_token(:INDENT, indent, indent.size)
215
+ length = indent.size + eol.size
216
+
217
+ elsif whitespace = chunk[/\A([ \t]+)/, 1]
218
+ length = whitespace.size
219
+ tokens << new_token(:WHITESPACE, whitespace, length)
220
+
221
+ elsif eol = chunk[/\A(\r\n|\r|\n)/, 1]
222
+ length = eol.size
223
+ tokens << new_token(:NEWLINE, eol, length)
224
+
225
+ elsif chunk.match(/\A\//)
226
+ length = 1
227
+ tokens << new_token(:DIV, '/', length)
228
+
229
+ else
230
+ raise PuppetLint::LexerError.new(@line_no, @column)
231
+ end
232
+
233
+ i += length
234
+ end
235
+ end
236
+
237
+ tokens
238
+ end
239
+
240
+ # Internal: Given the tokens already processed, determine if the next token
241
+ # could be a regular expression.
242
+ #
243
+ # Returns true if the next token could be a regex, otherwise return false.
244
+ def possible_regex?
245
+ prev_token = tokens.reject { |r|
246
+ FORMATTING_TOKENS.include? r.type
247
+ }.last
248
+
249
+ return true if prev_token.nil?
250
+
251
+ if REGEX_PREV_TOKENS.include? prev_token.type
252
+ true
253
+ else
254
+ false
255
+ end
256
+ end
257
+
258
+ # Internal: Create a new PuppetLint::Lexer::Token object, calculate its
259
+ # line number and column and then add it to the Linked List of tokens.
260
+ #
261
+ # type - The Symbol token type.
262
+ # value - The token value.
263
+ # length - The Integer length of the token's value.
264
+ # opts - A Hash of additional values required to determine line number and
265
+ # column:
266
+ # :line - The Integer line number if calculated externally.
267
+ # :column - The Integer column number if calculated externally.
268
+ #
269
+ # Returns the instantiated PuppetLint::Lexer::Token object.
270
+ def new_token(type, value, length, opts = {})
271
+ column = opts[:column] || @column
272
+ line_no = opts[:line] || @line_no
273
+
274
+ token = Token.new(type, value, line_no, column)
275
+ unless tokens.last.nil?
276
+ token.prev_token = tokens.last
277
+ tokens.last.next_token = token
278
+
279
+ unless FORMATTING_TOKENS.include?(token.type)
280
+ prev_nf_idx = tokens.rindex { |r| ! FORMATTING_TOKENS.include? r.type }
281
+ unless prev_nf_idx.nil?
282
+ prev_nf_token = tokens[prev_nf_idx]
283
+ prev_nf_token.next_code_token = token
284
+ token.prev_code_token = prev_nf_token
285
+ end
286
+ end
287
+ end
288
+
289
+ @column += length
290
+ if type == :NEWLINE
291
+ @line_no += 1
292
+ @column = 1
293
+ end
294
+
295
+ token
296
+ end
297
+
298
+ # Internal: Split a string on multiple terminators, excluding escaped
299
+ # terminators.
300
+ #
301
+ # string - The String to be split.
302
+ # terminators - The String of terminators that the String should be split
303
+ # on.
304
+ #
305
+ # Returns an Array consisting of two Strings, the String up to the first
306
+ # terminator and the terminator that was found.
307
+ def get_string_segment(string, terminators)
308
+ str = string.scan_until(/([^\\]|^|[^\\])([\\]{2})*[#{terminators}]+/)
309
+ begin
310
+ [str[0..-2], str[-1,1]]
311
+ rescue
312
+ [nil, nil]
313
+ end
314
+ end
315
+
316
+ # Internal: Tokenise the contents of a double quoted string.
317
+ #
318
+ # string - The String to be tokenised.
319
+ # line - The Integer line number of the start of the passed string.
320
+ # column - The Integer column number of the start of the passed string.
321
+ #
322
+ # Returns nothing.
323
+ def interpolate_string(string, line, column)
324
+ ss = StringScanner.new(string)
325
+ first = true
326
+ value, terminator = get_string_segment(ss, '"$')
327
+ until value.nil?
328
+ if terminator == "\""
329
+ if first
330
+ tokens << new_token(:STRING, value, value.size + 2, :line => line, :column => column)
331
+ first = false
332
+ else
333
+ line += value.scan(/(\r\n|\r|\n)/).size
334
+ token_column = column + (ss.pos - value.size)
335
+ tokens << new_token(:DQPOST, value, value.size + 1, :line => line, :column => token_column)
336
+ end
337
+ else
338
+ if first
339
+ tokens << new_token(:DQPRE, value, value.size + 1, :line => line, :column => column)
340
+ first = false
341
+ else
342
+ line += value.scan(/(\r\n|\r|\n)/).size
343
+ token_column = column + (ss.pos - value.size)
344
+ tokens << new_token(:DQMID, value, value.size, :line => line, :column => token_column)
345
+ end
346
+ if ss.scan(/\{/).nil?
347
+ var_name = ss.scan(/(::)?([\w-]+::)*[\w-]+/)
348
+ if var_name.nil?
349
+ token_column = column + ss.pos - 1
350
+ tokens << new_token(:DQMID, "$", 1, :line => line, :column => token_column)
351
+ else
352
+ token_column = column + (ss.pos - var_name.size)
353
+ tokens << new_token(:UNENC_VARIABLE, var_name, var_name.size, :line => line, :column => token_column)
354
+ end
355
+ else
356
+ contents = ss.scan_until(/\}/)[0..-2]
357
+ if contents.match(/\A(::)?([\w-]+::)*[\w-]+(\[.+?\])*/)
358
+ contents = "$#{contents}"
359
+ end
360
+ lexer = PuppetLint::Lexer.new
361
+ lexer.tokenise(contents)
362
+ lexer.tokens.each do |token|
363
+ tok_col = column + token.column + (ss.pos - contents.size - 1)
364
+ tok_line = token.line + line - 1
365
+ tokens << new_token(token.type, token.value, token.value.size, :line => tok_line, :column => tok_col)
366
+ end
367
+ end
368
+ end
369
+ value, terminator = get_string_segment(ss, '"$')
370
+ end
371
+ end
372
+ end
373
+ end
@@ -0,0 +1,101 @@
1
+ class PuppetLint
2
+ class Lexer
3
+ # Public: Stores a fragment of the manifest and the information about its
4
+ # location in the manifest.
5
+ class Token
6
+ # Public: Returns the Symbol type of the Token.
7
+ attr_accessor :type
8
+
9
+ # Public: Returns the String value of the Token.
10
+ attr_accessor :value
11
+
12
+ # Public: Returns the raw value of the Token.
13
+ attr_accessor :raw
14
+
15
+ # Public: Returns the Integer line number of the manifest text where
16
+ # the Token can be found.
17
+ attr_reader :line
18
+
19
+ # Public: Returns the Integer column number of the line of the manifest
20
+ # text where the Token can be found.
21
+ attr_reader :column
22
+
23
+ # Public: Gets/sets the next token in the manifest.
24
+ attr_accessor :next_token
25
+
26
+ # Public: Gets/sets the previous token in the manifest.
27
+ attr_accessor :prev_token
28
+
29
+ # Public: Gets/sets the next code token (skips whitespace, comments,
30
+ # etc) in the manifest.
31
+ attr_accessor :next_code_token
32
+
33
+ # Public: Gets/sets the previous code tokne (skips whitespace,
34
+ # comments, etc) in the manifest.
35
+ attr_accessor :prev_code_token
36
+
37
+ # Public: Initialise a new Token object.
38
+ #
39
+ # type - An upper case Symbol describing the type of Token.
40
+ # value - The String value of the Token.
41
+ # line - The Integer line number where the Token can be found in the
42
+ # manifest.
43
+ # column - The Integer number of characters from the start of the line to
44
+ # the start of the Token.
45
+ #
46
+ # Returns the instantiated Token.
47
+ def initialize(type, value, line, column)
48
+ @value = value
49
+ @type = type
50
+ @line = line
51
+ @column = column
52
+ @next_token = nil
53
+ @prev_token = nil
54
+ @next_code_token = nil
55
+ @prev_code_token = nil
56
+ end
57
+
58
+ # Public: Produce a human friendly description of the Token when
59
+ # inspected.
60
+ #
61
+ # Returns a String describing the Token.
62
+ def inspect
63
+ "<Token #{@type.inspect} (#{@value}) @#{@line}:#{@column}>"
64
+ end
65
+
66
+ # Public: Produce a Puppet DSL representation of a Token.
67
+ #
68
+ # Returns a Puppet DSL String.
69
+ def to_manifest
70
+ case @type
71
+ when :STRING
72
+ "\"#{@value}\""
73
+ when :SSTRING
74
+ "'#{@value}'"
75
+ when :DQPRE
76
+ "\"#{@value}"
77
+ when :DQPOST
78
+ "#{@value}\""
79
+ when :VARIABLE
80
+ if !@prev_code_token.nil? && [:DQPRE, :DQMID].include?(@prev_code_token.type)
81
+ "${#{@value}}"
82
+ else
83
+ "$#{@value}"
84
+ end
85
+ when :UNENC_VARIABLE
86
+ "$#{@value}"
87
+ when :NEWLINE
88
+ "\n"
89
+ when :COMMENT
90
+ "##{@value}"
91
+ when :REGEX
92
+ "/#{@value}/"
93
+ when :MLCOMMENT
94
+ @raw
95
+ else
96
+ @value
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end