hamlit 2.9.5-java → 2.13.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +17 -11
  4. data/CHANGELOG.md +52 -0
  5. data/Gemfile +2 -8
  6. data/LICENSE.txt +26 -23
  7. data/REFERENCE.md +13 -4
  8. data/benchmark/dynamic_merger/benchmark.rb +25 -0
  9. data/benchmark/dynamic_merger/hello.haml +50 -0
  10. data/benchmark/dynamic_merger/hello.string +50 -0
  11. data/bin/bench +3 -3
  12. data/bin/update-haml +125 -0
  13. data/ext/hamlit/hamlit.c +0 -1
  14. data/hamlit.gemspec +3 -1
  15. data/lib/hamlit/attribute_builder.rb +2 -2
  16. data/lib/hamlit/attribute_compiler.rb +3 -3
  17. data/lib/hamlit/compiler/children_compiler.rb +18 -4
  18. data/lib/hamlit/compiler/comment_compiler.rb +8 -5
  19. data/lib/hamlit/compiler/tag_compiler.rb +0 -4
  20. data/lib/hamlit/dynamic_merger.rb +67 -0
  21. data/lib/hamlit/engine.rb +5 -6
  22. data/lib/hamlit/filters/escaped.rb +1 -1
  23. data/lib/hamlit/filters/markdown.rb +1 -0
  24. data/lib/hamlit/filters/plain.rb +0 -4
  25. data/lib/hamlit/filters/preserve.rb +1 -1
  26. data/lib/hamlit/filters/text_base.rb +1 -1
  27. data/lib/hamlit/filters/tilt_base.rb +1 -1
  28. data/lib/hamlit/html.rb +8 -0
  29. data/lib/hamlit/parser.rb +6 -2
  30. data/lib/hamlit/parser/haml_attribute_builder.rb +164 -0
  31. data/lib/hamlit/parser/haml_buffer.rb +20 -130
  32. data/lib/hamlit/parser/haml_compiler.rb +1 -553
  33. data/lib/hamlit/parser/haml_error.rb +29 -25
  34. data/lib/hamlit/parser/haml_escapable.rb +1 -0
  35. data/lib/hamlit/parser/haml_generator.rb +1 -0
  36. data/lib/hamlit/parser/haml_helpers.rb +41 -59
  37. data/lib/hamlit/parser/{haml_xss_mods.rb → haml_helpers/xss_mods.rb} +20 -15
  38. data/lib/hamlit/parser/haml_options.rb +53 -66
  39. data/lib/hamlit/parser/haml_parser.rb +103 -71
  40. data/lib/hamlit/parser/haml_temple_engine.rb +123 -0
  41. data/lib/hamlit/parser/haml_util.rb +10 -40
  42. data/lib/hamlit/rails_template.rb +1 -1
  43. data/lib/hamlit/string_splitter.rb +10 -78
  44. data/lib/hamlit/template.rb +1 -1
  45. data/lib/hamlit/temple_line_counter.rb +31 -0
  46. data/lib/hamlit/version.rb +1 -1
  47. metadata +58 -24
  48. data/lib/hamlit/hamlit.su +0 -0
  49. data/lib/hamlit/parser/MIT-LICENSE +0 -20
  50. data/lib/hamlit/parser/README.md +0 -30
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'strscan'
2
- require 'hamlit/parser/haml_util'
3
- require 'hamlit/parser/haml_error'
4
4
 
5
5
  module Hamlit
6
6
  class HamlParser
7
- include ::Hamlit::HamlUtil
7
+ include Hamlit::HamlUtil
8
8
 
9
9
  attr_reader :root
10
10
 
@@ -61,7 +61,7 @@ module Hamlit
61
61
  SILENT_SCRIPT,
62
62
  ESCAPE,
63
63
  FILTER
64
- ]
64
+ ].freeze
65
65
 
66
66
  # The value of the character that designates that a line is part
67
67
  # of a multiline string.
@@ -75,8 +75,8 @@ module Hamlit
75
75
  #
76
76
  BLOCK_WITH_SPACES = /do\s*\|\s*[^\|]*\s+\|\z/
77
77
 
78
- MID_BLOCK_KEYWORDS = %w[else elsif rescue ensure end when]
79
- START_BLOCK_KEYWORDS = %w[if begin case unless]
78
+ MID_BLOCK_KEYWORDS = %w[else elsif rescue ensure end when].freeze
79
+ START_BLOCK_KEYWORDS = %w[if begin case unless].freeze
80
80
  # Try to parse assignments to block starters as best as possible
81
81
  START_BLOCK_KEYWORD_REGEX = /(?:\w+(?:,\s*\w+)*\s*=\s*)?(#{START_BLOCK_KEYWORDS.join('|')})/
82
82
  BLOCK_KEYWORD_REGEX = /^-?\s*(?:(#{MID_BLOCK_KEYWORDS.join('|')})|#{START_BLOCK_KEYWORD_REGEX.source})\b/
@@ -90,14 +90,16 @@ module Hamlit
90
90
  ID_KEY = 'id'.freeze
91
91
  CLASS_KEY = 'class'.freeze
92
92
 
93
- def initialize(template, options)
94
- @options = options
93
+ def initialize(options)
94
+ @options = HamlOptions.wrap(options)
95
95
  # Record the indent levels of "if" statements to validate the subsequent
96
96
  # elsif and else statements are indented at the appropriate level.
97
97
  @script_level_stack = []
98
98
  @template_index = 0
99
99
  @template_tabs = 0
100
+ end
100
101
 
102
+ def call(template)
101
103
  match = template.rstrip.scan(/(([ \t]+)?(.*?))(?:\Z|\r\n|\r|\n)/m)
102
104
  # discard the last match which is always blank
103
105
  match.pop
@@ -106,16 +108,14 @@ module Hamlit
106
108
  end
107
109
  # Append special end-of-document marker
108
110
  @template << Line.new(nil, '-#', '-#', @template.size, self, true)
109
- end
110
111
 
111
- def parse
112
112
  @root = @parent = ParseNode.new(:root)
113
113
  @flat = false
114
114
  @filter_buffer = nil
115
115
  @indentation = nil
116
116
  @line = next_line
117
117
 
118
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:indenting_at_start), @line.index) if @line.tabs != 0
118
+ raise HamlSyntaxError.new(HamlError.message(:indenting_at_start), @line.index) if @line.tabs != 0
119
119
 
120
120
  loop do
121
121
  next_line
@@ -138,7 +138,7 @@ module Hamlit
138
138
  end
139
139
 
140
140
  if !flat? && @next_line.tabs - @line.tabs > 1
141
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:deeper_indenting, @next_line.tabs - @line.tabs), @next_line.index)
141
+ raise HamlSyntaxError.new(HamlError.message(:deeper_indenting, @next_line.tabs - @line.tabs), @next_line.index)
142
142
  end
143
143
 
144
144
  @line = @next_line
@@ -146,7 +146,7 @@ module Hamlit
146
146
  # Close all the open tags
147
147
  close until @parent.type == :root
148
148
  @root
149
- rescue ::Hamlit::HamlError => e
149
+ rescue Hamlit::HamlError => e
150
150
  e.backtrace.unshift "#{@options.filename}:#{(e.line ? e.line + 1 : @line.index + 1) + @options.line - 1}"
151
151
  raise
152
152
  end
@@ -158,7 +158,7 @@ module Hamlit
158
158
  @indentation = line.whitespace
159
159
 
160
160
  if @indentation.include?(?\s) && @indentation.include?(?\t)
161
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:cant_use_tabs_and_spaces), line.index)
161
+ raise HamlSyntaxError.new(HamlError.message(:cant_use_tabs_and_spaces), line.index)
162
162
  end
163
163
 
164
164
  @flat_spaces = @indentation * (@template_tabs+1) if flat?
@@ -169,17 +169,17 @@ module Hamlit
169
169
  return tabs if line.whitespace == @indentation * tabs
170
170
  return @template_tabs + 1 if flat? && line.whitespace =~ /^#{@flat_spaces}/
171
171
 
172
- message = ::Hamlit::HamlError.message(:inconsistent_indentation,
172
+ message = HamlError.message(:inconsistent_indentation,
173
173
  human_indentation(line.whitespace),
174
174
  human_indentation(@indentation)
175
175
  )
176
- raise ::Hamlit::HamlSyntaxError.new(message, line.index)
176
+ raise HamlSyntaxError.new(message, line.index)
177
177
  end
178
178
 
179
179
  private
180
180
 
181
181
  # @private
182
- class Line < Struct.new(:whitespace, :text, :full, :index, :parser, :eod)
182
+ Line = Struct.new(:whitespace, :text, :full, :index, :parser, :eod) do
183
183
  alias_method :eod?, :eod
184
184
 
185
185
  # @private
@@ -195,14 +195,39 @@ module Hamlit
195
195
  end
196
196
 
197
197
  # @private
198
- class ParseNode < Struct.new(:type, :line, :value, :parent, :children)
198
+ ParseNode = Struct.new(:type, :line, :value, :parent, :children) do
199
199
  def initialize(*args)
200
200
  super
201
201
  self.children ||= []
202
202
  end
203
203
 
204
204
  def inspect
205
- %Q[(#{type} #{value.inspect}#{children.each_with_object('') {|c, s| s << "\n#{c.inspect.gsub!(/^/, ' ')}"}})]
205
+ %Q[(#{type} #{value.inspect}#{children.each_with_object(''.dup) {|c, s| s << "\n#{c.inspect.gsub!(/^/, ' ')}"}})].dup
206
+ end
207
+ end
208
+
209
+ # @param [String] new - Hash literal including dynamic values.
210
+ # @param [String] old - Hash literal including dynamic values or Ruby literal of multiple Hashes which MUST be interpreted as method's last arguments.
211
+ DynamicAttributes = Struct.new(:new, :old) do
212
+ undef :old=
213
+ def old=(value)
214
+ unless value =~ /\A{.*}\z/m
215
+ raise ArgumentError.new('Old attributes must start with "{" and end with "}"')
216
+ end
217
+ self[:old] = value
218
+ end
219
+
220
+ # This will be a literal for Hamlit::HamlBuffer#attributes's last argument, `attributes_hashes`.
221
+ def to_literal
222
+ [new, stripped_old].compact.join(', ')
223
+ end
224
+
225
+ private
226
+
227
+ # For `%foo{ { foo: 1 }, bar: 2 }`, :old is "{ { foo: 1 }, bar: 2 }" and this method returns " { foo: 1 }, bar: 2 " for last argument.
228
+ def stripped_old
229
+ return nil if old.nil?
230
+ old.sub!(/\A{/, '').sub!(/}\z/m, '')
206
231
  end
207
232
  end
208
233
 
@@ -264,7 +289,7 @@ module Hamlit
264
289
  end
265
290
 
266
291
  def block_keyword(text)
267
- return unless keyword = text.scan(BLOCK_KEYWORD_REGEX)[0]
292
+ return unless (keyword = text.scan(BLOCK_KEYWORD_REGEX)[0])
268
293
  keyword[0] || keyword[1]
269
294
  end
270
295
 
@@ -275,20 +300,20 @@ module Hamlit
275
300
 
276
301
  def plain(line, escape_html = nil)
277
302
  if block_opened?
278
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:illegal_nesting_plain), @next_line.index)
303
+ raise HamlSyntaxError.new(HamlError.message(:illegal_nesting_plain), @next_line.index)
279
304
  end
280
305
 
281
306
  unless contains_interpolation?(line.text)
282
307
  return ParseNode.new(:plain, line.index + 1, :text => line.text)
283
308
  end
284
309
 
285
- escape_html = @options.escape_html if escape_html.nil?
286
- line.text = ::Hamlit::HamlUtil.unescape_interpolation(line.text)
310
+ escape_html = @options.escape_html && @options.mime_type != 'text/plain' if escape_html.nil?
311
+ line.text = unescape_interpolation(line.text)
287
312
  script(line, false).tap { |n| n.value[:escape_interpolation] = true if escape_html }
288
313
  end
289
314
 
290
315
  def script(line, escape_html = nil, preserve = false)
291
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:no_ruby_code, '=')) if line.text.empty?
316
+ raise HamlSyntaxError.new(HamlError.message(:no_ruby_code, '=')) if line.text.empty?
292
317
  line = handle_ruby_multiline(line)
293
318
  escape_html = @options.escape_html if escape_html.nil?
294
319
 
@@ -300,12 +325,12 @@ module Hamlit
300
325
  end
301
326
 
302
327
  def flat_script(line, escape_html = nil)
303
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:no_ruby_code, '~')) if line.text.empty?
328
+ raise HamlSyntaxError.new(HamlError.message(:no_ruby_code, '~')) if line.text.empty?
304
329
  script(line, escape_html, :preserve)
305
330
  end
306
331
 
307
332
  def silent_script(line)
308
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:no_end), line.index) if line.text[1..-1].strip == 'end'
333
+ raise HamlSyntaxError.new(HamlError.message(:no_end), line.index) if line.text[1..-1].strip == 'end'
309
334
 
310
335
  line = handle_ruby_multiline(line)
311
336
  keyword = block_keyword(line.text)
@@ -314,7 +339,7 @@ module Hamlit
314
339
 
315
340
  if ["else", "elsif", "when"].include?(keyword)
316
341
  if @script_level_stack.empty?
317
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:missing_if, keyword), @line.index)
342
+ raise Hamlit::HamlSyntaxError.new(HamlError.message(:missing_if, keyword), @line.index)
318
343
  end
319
344
 
320
345
  if keyword == 'when' and !@script_level_stack.last[2]
@@ -325,8 +350,8 @@ module Hamlit
325
350
  end
326
351
 
327
352
  if @script_level_stack.last[1] != @line.tabs
328
- message = ::Hamlit::HamlError.message(:bad_script_indent, keyword, @script_level_stack.last[1], @line.tabs)
329
- raise ::Hamlit::HamlSyntaxError.new(message, @line.index)
353
+ message = HamlError.message(:bad_script_indent, keyword, @script_level_stack.last[1], @line.tabs)
354
+ raise Hamlit::HamlSyntaxError.new(message, @line.index)
330
355
  end
331
356
  end
332
357
 
@@ -363,7 +388,6 @@ module Hamlit
363
388
 
364
389
  preserve_tag = @options.preserve.include?(tag_name)
365
390
  nuke_inner_whitespace ||= preserve_tag
366
- preserve_tag = false if @options.ugly
367
391
  escape_html = (action == '&' || (action != '!' && @options.escape_html))
368
392
 
369
393
  case action
@@ -372,7 +396,7 @@ module Hamlit
372
396
  when '='
373
397
  parse = true
374
398
  if value[0] == ?=
375
- value = ::Hamlit::HamlUtil.unescape_interpolation(value[1..-1].strip)
399
+ value = unescape_interpolation(value[1..-1].strip)
376
400
  escape_interpolation = true if escape_html
377
401
  escape_html = false
378
402
  end
@@ -381,50 +405,47 @@ module Hamlit
381
405
  parse = true
382
406
  preserve_script = (value[0] == ?~)
383
407
  if value[1] == ?=
384
- value = ::Hamlit::HamlUtil.unescape_interpolation(value[2..-1].strip)
408
+ value = unescape_interpolation(value[2..-1].strip)
385
409
  escape_interpolation = true if escape_html
386
410
  escape_html = false
387
411
  else
388
412
  value = value[1..-1].strip
389
413
  end
390
414
  elsif contains_interpolation?(value)
391
- value = ::Hamlit::HamlUtil.unescape_interpolation(value)
415
+ value = unescape_interpolation(value)
392
416
  escape_interpolation = true if escape_html
393
417
  parse = true
394
418
  escape_html = false
395
419
  end
396
420
  else
397
421
  if contains_interpolation?(value)
398
- value = ::Hamlit::HamlUtil.unescape_interpolation(value)
399
- escape_interpolation = true if escape_html
422
+ value = unescape_interpolation(value, escape_html)
400
423
  parse = true
401
424
  escape_html = false
402
425
  end
403
426
  end
404
427
 
405
- attributes = ::Hamlit::HamlParser.parse_class_and_id(attributes)
406
- attributes_list = []
428
+ attributes = HamlParser.parse_class_and_id(attributes)
429
+ dynamic_attributes = DynamicAttributes.new
407
430
 
408
431
  if attributes_hashes[:new]
409
432
  static_attributes, attributes_hash = attributes_hashes[:new]
410
- ::Hamlit::HamlBuffer.merge_attrs(attributes, static_attributes) if static_attributes
411
- attributes_list << attributes_hash
433
+ HamlAttributeBuilder.merge_attributes!(attributes, static_attributes) if static_attributes
434
+ dynamic_attributes.new = attributes_hash
412
435
  end
413
436
 
414
437
  if attributes_hashes[:old]
415
438
  static_attributes = parse_static_hash(attributes_hashes[:old])
416
- ::Hamlit::HamlBuffer.merge_attrs(attributes, static_attributes) if static_attributes
417
- attributes_list << attributes_hashes[:old] unless static_attributes || @options.suppress_eval
439
+ HamlAttributeBuilder.merge_attributes!(attributes, static_attributes) if static_attributes
440
+ dynamic_attributes.old = attributes_hashes[:old] unless static_attributes || @options.suppress_eval
418
441
  end
419
442
 
420
- attributes_list.compact!
421
-
422
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:illegal_nesting_self_closing), @next_line.index) if block_opened? && self_closing
423
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:no_ruby_code, action), last_line - 1) if parse && value.empty?
424
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:self_closing_content), last_line - 1) if self_closing && !value.empty?
443
+ raise HamlSyntaxError.new(HamlError.message(:illegal_nesting_self_closing), @next_line.index) if block_opened? && self_closing
444
+ raise HamlSyntaxError.new(HamlError.message(:no_ruby_code, action), last_line - 1) if parse && value.empty?
445
+ raise HamlSyntaxError.new(HamlError.message(:self_closing_content), last_line - 1) if self_closing && !value.empty?
425
446
 
426
447
  if block_opened? && !value.empty? && !is_ruby_multiline?(value)
427
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:illegal_nesting_line, tag_name), @next_line.index)
448
+ raise HamlSyntaxError.new(HamlError.message(:illegal_nesting_line, tag_name), @next_line.index)
428
449
  end
429
450
 
430
451
  self_closing ||= !!(!block_opened? && value.empty? && @options.autoclose.any? {|t| t === tag_name})
@@ -433,7 +454,7 @@ module Hamlit
433
454
  line = handle_ruby_multiline(line) if parse
434
455
 
435
456
  ParseNode.new(:tag, line.index + 1, :name => tag_name, :attributes => attributes,
436
- :attributes_hashes => attributes_list, :self_closing => self_closing,
457
+ :dynamic_attributes => dynamic_attributes, :self_closing => self_closing,
437
458
  :nuke_inner_whitespace => nuke_inner_whitespace,
438
459
  :nuke_outer_whitespace => nuke_outer_whitespace, :object_ref => object_ref,
439
460
  :escape_html => escape_html, :preserve_tag => preserve_tag,
@@ -462,13 +483,13 @@ module Hamlit
462
483
 
463
484
  if contains_interpolation?(text)
464
485
  parse = true
465
- text = slow_unescape_interpolation(text)
486
+ text = unescape_interpolation(text)
466
487
  else
467
488
  parse = false
468
489
  end
469
490
 
470
491
  if block_opened? && !text.empty?
471
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:illegal_nesting_content), @next_line.index)
492
+ raise HamlSyntaxError.new(Hamlit::HamlError.message(:illegal_nesting_content), @next_line.index)
472
493
  end
473
494
 
474
495
  ParseNode.new(:comment, @line.index + 1, :conditional => conditional, :text => text, :revealed => revealed, :parse => parse)
@@ -476,13 +497,13 @@ module Hamlit
476
497
 
477
498
  # Renders an XHTML doctype or XML shebang.
478
499
  def doctype(text)
479
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:illegal_nesting_header), @next_line.index) if block_opened?
500
+ raise HamlSyntaxError.new(HamlError.message(:illegal_nesting_header), @next_line.index) if block_opened?
480
501
  version, type, encoding = text[3..-1].strip.downcase.scan(DOCTYPE_REGEX)[0]
481
502
  ParseNode.new(:doctype, @line.index + 1, :version => version, :type => type, :encoding => encoding)
482
503
  end
483
504
 
484
505
  def filter(name)
485
- raise ::Hamlit::HamlError.new(::Hamlit::HamlError.message(:invalid_filter_name, name)) unless name =~ /^\w+$/
506
+ raise HamlError.new(HamlError.message(:invalid_filter_name, name)) unless name =~ /^\w+$/
486
507
 
487
508
  if filter_opened?
488
509
  @flat = true
@@ -519,7 +540,7 @@ module Hamlit
519
540
 
520
541
  # Post-process case statements to normalize the nesting of "when" clauses
521
542
  return unless node.value[:keyword] == "case"
522
- return unless first = node.children.first
543
+ return unless (first = node.children.first)
523
544
  return unless first.type == :silent_script && first.value[:keyword] == "when"
524
545
  return if first.children.empty?
525
546
  # If the case node has a "when" child with children, it's the
@@ -531,7 +552,7 @@ module Hamlit
531
552
 
532
553
  alias :close_script :close_silent_script
533
554
 
534
- # This is a class method so it can be accessed from {Haml::Helpers}.
555
+ # This is a class method so it can be accessed from {Hamlit::HamlHelpers}.
535
556
  #
536
557
  # Iterates through the classes and ids supplied through `.`
537
558
  # and `#` syntax, and returns a hash with them as attributes,
@@ -540,7 +561,7 @@ module Hamlit
540
561
  attributes = {}
541
562
  return attributes if list.empty?
542
563
 
543
- list.scan(/([#.])([-:_a-zA-Z0-9]+)/) do |type, property|
564
+ list.scan(/([#.])([-:_a-zA-Z0-9\@]+)/) do |type, property|
544
565
  case type
545
566
  when '.'
546
567
  if attributes[CLASS_KEY]
@@ -555,16 +576,22 @@ module Hamlit
555
576
  attributes
556
577
  end
557
578
 
579
+ # This method doesn't use Hamlit::HamlAttributeParser because currently it depends on Ripper and Rubinius doesn't provide it.
580
+ # Ideally this logic should be placed in Hamlit::HamlAttributeParser instead of here and this method should use it.
581
+ #
582
+ # @param [String] text - Hash literal or text inside old attributes
583
+ # @return [Hash,nil] - Return nil if text is not static Hash literal
558
584
  def parse_static_hash(text)
559
585
  attributes = {}
560
586
  return attributes if text.empty?
561
587
 
588
+ text = text[1...-1] # strip brackets
562
589
  scanner = StringScanner.new(text)
563
590
  scanner.scan(/\s+/)
564
591
  until scanner.eos?
565
- return unless key = scanner.scan(LITERAL_VALUE_REGEX)
592
+ return unless (key = scanner.scan(LITERAL_VALUE_REGEX))
566
593
  return unless scanner.scan(/\s*=>\s*/)
567
- return unless value = scanner.scan(LITERAL_VALUE_REGEX)
594
+ return unless (value = scanner.scan(LITERAL_VALUE_REGEX))
568
595
  return unless scanner.scan(/\s*(?:,|$)\s*/)
569
596
  attributes[eval(key).to_s] = eval(value).to_s
570
597
  end
@@ -573,13 +600,13 @@ module Hamlit
573
600
 
574
601
  # Parses a line into tag_name, attributes, attributes_hash, object_ref, action, value
575
602
  def parse_tag(text)
576
- match = text.scan(/%([-:\w]+)([-:\w.#]*)(.+)?/)[0]
577
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:invalid_tag, text)) unless match
603
+ match = text.scan(/%([-:\w]+)([-:\w.#\@]*)(.+)?/)[0]
604
+ raise HamlSyntaxError.new(HamlError.message(:invalid_tag, text)) unless match
578
605
 
579
606
  tag_name, attributes, rest = match
580
607
 
581
608
  if !attributes.empty? && (attributes =~ /[.#](\.|#|\z)/)
582
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:illegal_element))
609
+ raise HamlSyntaxError.new(HamlError.message(:illegal_element))
583
610
  end
584
611
 
585
612
  new_attributes_hash = old_attributes_hash = last_line = nil
@@ -624,14 +651,17 @@ module Hamlit
624
651
  nuke_inner_whitespace, action, value, last_line || @line.index + 1]
625
652
  end
626
653
 
654
+ # @return [String] attributes_hash - Hash literal starting with `{` and ending with `}`
655
+ # @return [String] rest
656
+ # @return [Integer] last_line
627
657
  def parse_old_attributes(text)
628
658
  text = text.dup
629
659
  last_line = @line.index + 1
630
660
 
631
661
  begin
632
662
  attributes_hash, rest = balance(text, ?{, ?})
633
- rescue ::Hamlit::HamlSyntaxError => e
634
- if text.strip[-1] == ?, && e.message == ::Hamlit::HamlError.message(:unbalanced_brackets)
663
+ rescue HamlSyntaxError => e
664
+ if text.strip[-1] == ?, && e.message == HamlError.message(:unbalanced_brackets)
635
665
  text << "\n#{@next_line.text}"
636
666
  last_line += 1
637
667
  next_line
@@ -641,10 +671,12 @@ module Hamlit
641
671
  raise e
642
672
  end
643
673
 
644
- attributes_hash = attributes_hash[1...-1] if attributes_hash
645
674
  return attributes_hash, rest, last_line
646
675
  end
647
676
 
677
+ # @return [Array<Hash,String,nil>] - [static_attributes (Hash), dynamic_attributes (nil or String starting with `{` and ending with `}`)]
678
+ # @return [String] rest
679
+ # @return [Integer] last_line
648
680
  def parse_new_attributes(text)
649
681
  scanner = StringScanner.new(text)
650
682
  last_line = @line.index + 1
@@ -656,9 +688,9 @@ module Hamlit
656
688
  break if name.nil?
657
689
 
658
690
  if name == false
659
- scanned = ::Hamlit::HamlUtil.balance(text, ?(, ?))
691
+ scanned = Hamlit::HamlUtil.balance(text, ?(, ?))
660
692
  text = scanned ? scanned.first : text
661
- raise ::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:invalid_attribute_list, text.inspect), last_line - 1)
693
+ raise Hamlit::HamlSyntaxError.new(HamlError.message(:invalid_attribute_list, text.inspect), last_line - 1)
662
694
  end
663
695
  attributes[name] = value
664
696
  scanner.scan(/\s*/)
@@ -672,7 +704,7 @@ module Hamlit
672
704
  end
673
705
 
674
706
  static_attributes = {}
675
- dynamic_attributes = "{"
707
+ dynamic_attributes = "{".dup
676
708
  attributes.each do |name, (type, val)|
677
709
  if type == :static
678
710
  static_attributes[name] = val
@@ -687,7 +719,7 @@ module Hamlit
687
719
  end
688
720
 
689
721
  def parse_new_attribute(scanner)
690
- unless name = scanner.scan(/[-:\w]+/)
722
+ unless (name = scanner.scan(/[-:\w]+/))
691
723
  return if scanner.scan(/\)/)
692
724
  return false
693
725
  end
@@ -696,8 +728,8 @@ module Hamlit
696
728
  return name, [:static, true] unless scanner.scan(/=/) #/end
697
729
 
698
730
  scanner.scan(/\s*/)
699
- unless quote = scanner.scan(/["']/)
700
- return false unless var = scanner.scan(/(@@?|\$)?\w+/)
731
+ unless (quote = scanner.scan(/["']/))
732
+ return false unless (var = scanner.scan(/(@@?|\$)?\w+/))
701
733
  return name, [:dynamic, var]
702
734
  end
703
735
 
@@ -712,7 +744,7 @@ module Hamlit
712
744
 
713
745
  return name, [:static, content.first[1]] if content.size == 1
714
746
  return name, [:dynamic,
715
- %!"#{content.each_with_object('') {|(t, v), s| s << (t == :str ? inspect_obj(v)[1...-1] : "\#{#{v}}")}}"!]
747
+ %!"#{content.each_with_object(''.dup) {|(t, v), s| s << (t == :str ? inspect_obj(v)[1...-1] : "\#{#{v}}")}}"!]
716
748
  end
717
749
 
718
750
  def next_line
@@ -780,7 +812,7 @@ module Hamlit
780
812
  end
781
813
 
782
814
  def balance(*args)
783
- ::Hamlit::HamlUtil.balance(*args) or raise(::Hamlit::HamlSyntaxError.new(::Hamlit::HamlError.message(:unbalanced_brackets)))
815
+ Hamlit::HamlUtil.balance(*args) or raise(HamlSyntaxError.new(HamlError.message(:unbalanced_brackets)))
784
816
  end
785
817
 
786
818
  def block_opened?