hamlit 2.10.0 → 2.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +17 -11
- data/CHANGELOG.md +45 -1
- data/Gemfile +1 -7
- data/LICENSE.txt +26 -23
- data/REFERENCE.md +13 -4
- data/bin/bench +2 -2
- data/bin/update-haml +125 -0
- data/ext/hamlit/hamlit.c +0 -1
- data/lib/hamlit/attribute_builder.rb +2 -2
- data/lib/hamlit/attribute_compiler.rb +3 -3
- data/lib/hamlit/compiler/children_compiler.rb +18 -4
- data/lib/hamlit/compiler/comment_compiler.rb +8 -5
- data/lib/hamlit/filters/escaped.rb +1 -1
- data/lib/hamlit/filters/markdown.rb +1 -0
- data/lib/hamlit/filters/preserve.rb +1 -1
- data/lib/hamlit/filters/text_base.rb +1 -1
- data/lib/hamlit/filters/tilt_base.rb +1 -1
- data/lib/hamlit/html.rb +8 -0
- data/lib/hamlit/parser.rb +6 -2
- data/lib/hamlit/parser/haml_attribute_builder.rb +164 -0
- data/lib/hamlit/parser/haml_buffer.rb +20 -130
- data/lib/hamlit/parser/haml_compiler.rb +1 -553
- data/lib/hamlit/parser/haml_error.rb +29 -25
- data/lib/hamlit/parser/haml_escapable.rb +1 -0
- data/lib/hamlit/parser/haml_generator.rb +1 -0
- data/lib/hamlit/parser/haml_helpers.rb +41 -59
- data/lib/hamlit/parser/{haml_xss_mods.rb → haml_helpers/xss_mods.rb} +20 -15
- data/lib/hamlit/parser/haml_options.rb +53 -66
- data/lib/hamlit/parser/haml_parser.rb +103 -71
- data/lib/hamlit/parser/haml_temple_engine.rb +123 -0
- data/lib/hamlit/parser/haml_util.rb +10 -40
- data/lib/hamlit/rails_template.rb +1 -1
- data/lib/hamlit/string_splitter.rb +1 -0
- data/lib/hamlit/template.rb +1 -1
- data/lib/hamlit/temple_line_counter.rb +31 -0
- data/lib/hamlit/version.rb +1 -1
- metadata +10 -6
- data/lib/hamlit/parser/MIT-LICENSE +0 -20
- 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
|
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(
|
94
|
-
@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
|
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
|
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
|
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
|
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 =
|
172
|
+
message = HamlError.message(:inconsistent_indentation,
|
173
173
|
human_indentation(line.whitespace),
|
174
174
|
human_indentation(@indentation)
|
175
175
|
)
|
176
|
-
raise
|
176
|
+
raise HamlSyntaxError.new(message, line.index)
|
177
177
|
end
|
178
178
|
|
179
179
|
private
|
180
180
|
|
181
181
|
# @private
|
182
|
-
|
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
|
-
|
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
|
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 =
|
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
|
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
|
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
|
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
|
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 =
|
329
|
-
raise
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
406
|
-
|
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
|
-
|
411
|
-
|
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
|
-
|
417
|
-
|
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
|
-
|
421
|
-
|
422
|
-
raise
|
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
|
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
|
-
:
|
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 =
|
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
|
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
|
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
|
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 {
|
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
|
577
|
-
raise
|
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
|
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
|
634
|
-
if text.strip[-1] == ?, && e.message ==
|
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 =
|
691
|
+
scanned = Hamlit::HamlUtil.balance(text, ?(, ?))
|
660
692
|
text = scanned ? scanned.first : text
|
661
|
-
raise
|
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
|
-
|
815
|
+
Hamlit::HamlUtil.balance(*args) or raise(HamlSyntaxError.new(HamlError.message(:unbalanced_brackets)))
|
784
816
|
end
|
785
817
|
|
786
818
|
def block_opened?
|