haml-edge 2.1.44 → 2.1.45
Sign up to get free protection for your applications and to get access to all the features.
- data/EDGE_GEM_VERSION +1 -1
- data/README.md +5 -1
- data/VERSION +1 -1
- data/extra/haml-mode.el +111 -58
- data/lib/haml/buffer.rb +1 -1
- data/lib/haml/precompiler.rb +110 -14
- data/lib/sass/script/number.rb +2 -2
- data/test/haml/engine_test.rb +105 -0
- metadata +22 -3
data/EDGE_GEM_VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.1.
|
1
|
+
2.1.45
|
data/README.md
CHANGED
@@ -57,11 +57,15 @@ check out the [YARD documentation](http://haml-lang.com/docs/yardoc).
|
|
57
57
|
### Haml
|
58
58
|
|
59
59
|
The most basic element of Haml
|
60
|
-
is a shorthand for creating HTML
|
60
|
+
is a shorthand for creating HTML:
|
61
61
|
|
62
62
|
%tagname{:attr1 => 'value1', :attr2 => 'value2'} Contents
|
63
63
|
|
64
64
|
No end-tag is needed; Haml handles that automatically.
|
65
|
+
If you prefer HTML-style attributes, you can also use:
|
66
|
+
|
67
|
+
%tagname(attr1='value1' attr2='value2') Contents
|
68
|
+
|
65
69
|
Adding `class` and `id` attributes is even easier.
|
66
70
|
Haml uses the same syntax as the CSS that styles the document:
|
67
71
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.1.
|
1
|
+
2.1.45
|
data/extra/haml-mode.el
CHANGED
@@ -61,8 +61,12 @@ if the next line could be nested within this line.
|
|
61
61
|
The function can also return a positive integer to indicate
|
62
62
|
a specific level to which the current line could be indented.")
|
63
63
|
|
64
|
+
(defconst haml-tag-beg-re
|
65
|
+
"^ *\\(?:[%\\.#][a-z0-9_:\\-]*\\)+\\(?:(.*)\\|{.*}\\|\\[.*\\]\\)*"
|
66
|
+
"A regexp matching the beginning of a Haml tag, through (), {}, and [].")
|
67
|
+
|
64
68
|
(defvar haml-block-openers
|
65
|
-
`(
|
69
|
+
`(,(concat haml-tag-beg-re "[><]*[ \t]*$")
|
66
70
|
"^ *[&!]?[-=~].*do[ \t]*\\(|.*|[ \t]*\\)?$"
|
67
71
|
,(concat "^ *[&!]?[-=~][ \t]*\\("
|
68
72
|
(regexp-opt '("if" "unless" "while" "until" "else"
|
@@ -122,53 +126,73 @@ For example, this will highlight all of the following:
|
|
122
126
|
%p= 'baz'
|
123
127
|
%p{:foo => 'bar'}[@bar]= 'baz'"
|
124
128
|
(when (re-search-forward "^ *[%.#]" limit t)
|
125
|
-
(
|
129
|
+
(forward-char -1)
|
130
|
+
|
131
|
+
;; Highlight tag, classes, and ids
|
132
|
+
(while (haml-move "\\([.#%]\\)[a-z0-9_:\\-]*")
|
133
|
+
(put-text-property (match-beginning 0) (match-end 0) 'face
|
134
|
+
(case (char-after (match-beginning 1))
|
135
|
+
(?% font-lock-function-name-face)
|
136
|
+
(?# font-lock-keyword-face)
|
137
|
+
(?. font-lock-type-face))))
|
138
|
+
|
139
|
+
(block loop
|
140
|
+
(while t
|
141
|
+
(let ((eol (save-excursion (end-of-line) (point))))
|
142
|
+
(case (char-after)
|
143
|
+
;; Highlight obj refs
|
144
|
+
(?\[
|
145
|
+
(let ((beg (point)))
|
146
|
+
(haml-limited-forward-sexp eol)
|
147
|
+
(haml-fontify-region-as-ruby beg (point))))
|
148
|
+
;; Highlight new attr hashes
|
149
|
+
(?\(
|
150
|
+
(forward-char 1)
|
151
|
+
(while
|
152
|
+
(and (haml-parse-new-attr-hash
|
153
|
+
(lambda (type beg end)
|
154
|
+
(case type
|
155
|
+
(name (put-text-property beg end 'face font-lock-constant-face))
|
156
|
+
(value (haml-fontify-region-as-ruby beg end)))))
|
157
|
+
(not (eobp)))
|
158
|
+
(forward-line 1)
|
159
|
+
(beginning-of-line)))
|
160
|
+
;; Highlight old attr hashes
|
161
|
+
(?\{
|
162
|
+
(let ((beg (point)))
|
163
|
+
(haml-limited-forward-sexp eol)
|
164
|
+
|
165
|
+
;; Check for multiline
|
166
|
+
(while (and (eolp) (eq (char-before) ?,) (not (eobp)))
|
167
|
+
(forward-line)
|
168
|
+
(let ((eol (save-excursion (end-of-line) (point))))
|
169
|
+
;; If no sexps are closed,
|
170
|
+
;; we're still continuing a multiline hash
|
171
|
+
(if (>= (car (parse-partial-sexp (point) eol)) 0)
|
172
|
+
(end-of-line)
|
173
|
+
;; If sexps have been closed,
|
174
|
+
;; set the point at the end of the total sexp
|
175
|
+
(goto-char beg)
|
176
|
+
(haml-limited-forward-sexp eol))))
|
177
|
+
|
178
|
+
(haml-fontify-region-as-ruby (+ 1 beg) (point))))
|
179
|
+
(t (return-from loop))))))
|
180
|
+
|
181
|
+
;; Move past end chars
|
182
|
+
(when (looking-at "[<>&!]+") (goto-char (match-end 0)))
|
183
|
+
;; Highlight script
|
184
|
+
(if (looking-at "\\([=~]\\) \\(.*\\)$")
|
185
|
+
(haml-fontify-region-as-ruby (match-beginning 2) (match-end 2))
|
186
|
+
;; Give font-lock something to highlight
|
126
187
|
(forward-char -1)
|
188
|
+
(looking-at "\\(\\)"))
|
189
|
+
t))
|
127
190
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
(?# font-lock-keyword-face)
|
134
|
-
(?. font-lock-type-face)))
|
135
|
-
(goto-char (match-end 0)))
|
136
|
-
|
137
|
-
;; Highlight obj refs
|
138
|
-
(when (eq (char-after) ?\[)
|
139
|
-
(let ((beg (point)))
|
140
|
-
(haml-limited-forward-sexp eol)
|
141
|
-
(haml-fontify-region-as-ruby beg (point))))
|
142
|
-
|
143
|
-
;; Highlight attr hashes
|
144
|
-
(when (eq (char-after) ?\{)
|
145
|
-
(let ((beg (point)))
|
146
|
-
(haml-limited-forward-sexp eol)
|
147
|
-
|
148
|
-
;; Check for multiline
|
149
|
-
(while (and (eolp) (eq (char-before) ?,) (not (eobp)))
|
150
|
-
(forward-line)
|
151
|
-
(let ((eol (save-excursion (end-of-line) (point))))
|
152
|
-
;; If no sexps are closed,
|
153
|
-
;; we're still continuing a multiline hash
|
154
|
-
(if (>= (car (parse-partial-sexp (point) eol)) 0)
|
155
|
-
(end-of-line)
|
156
|
-
;; If sexps have been closed,
|
157
|
-
;; set the point at the end of the total sexp
|
158
|
-
(goto-char beg)
|
159
|
-
(haml-limited-forward-sexp eol))))
|
160
|
-
|
161
|
-
(haml-fontify-region-as-ruby (+ 1 beg) (point))))
|
162
|
-
|
163
|
-
;; Move past end chars
|
164
|
-
(when (looking-at "[<>&!]+") (goto-char (match-end 0)))
|
165
|
-
;; Highlight script
|
166
|
-
(if (looking-at "\\([=~]\\) \\(.*\\)$")
|
167
|
-
(haml-fontify-region-as-ruby (match-beginning 2) (match-end 2))
|
168
|
-
;; Give font-lock something to highlight
|
169
|
-
(forward-char -1)
|
170
|
-
(looking-at "\\(\\)"))
|
171
|
-
t)))
|
191
|
+
(defun haml-move (re)
|
192
|
+
"Try matching and moving to the end of a regular expression."
|
193
|
+
(when (looking-at re)
|
194
|
+
(goto-char (match-end 0))
|
195
|
+
t))
|
172
196
|
|
173
197
|
(defun haml-highlight-interpolation (limit)
|
174
198
|
"Highlight Ruby interpolation (#{foo})."
|
@@ -441,10 +465,8 @@ character of the next line."
|
|
441
465
|
"Returns t if the current line can have lines nested beneath it."
|
442
466
|
(let ((attr-props (haml-parse-multiline-attr-hash)))
|
443
467
|
(when attr-props
|
444
|
-
(end-of-line)
|
445
468
|
(return-from haml-indent-p
|
446
|
-
(if (
|
447
|
-
(beginning-of-line)
|
469
|
+
(if (haml-unclosed-attr-hash-p) (cdr (assq 'hash-indent attr-props))
|
448
470
|
(list (+ (cdr (assq 'indent attr-props)) haml-indent-offset) nil)))))
|
449
471
|
(loop for opener in haml-block-openers
|
450
472
|
if (looking-at opener) return t
|
@@ -464,20 +486,51 @@ beginning the hash."
|
|
464
486
|
(save-excursion
|
465
487
|
(while t
|
466
488
|
(beginning-of-line)
|
467
|
-
(if (looking-at
|
489
|
+
(if (looking-at (eval-when-compile (concat haml-tag-beg-re "\\([{(]\\)")))
|
468
490
|
(progn
|
469
491
|
(goto-char (- (match-end 0) 1))
|
470
492
|
(haml-limited-forward-sexp (save-excursion (end-of-line) (point)))
|
471
493
|
(return-from haml-parse-multiline-attr-hash
|
472
|
-
(
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
494
|
+
(when (or (string-equal (match-string 1) "(") (eq (char-before) ?,))
|
495
|
+
`((indent . ,(current-indentation))
|
496
|
+
(hash-indent . ,(- (match-end 0) (match-beginning 0)))
|
497
|
+
(point . ,(match-beginning 0))))))
|
498
|
+
(when (bobp) (return-from haml-parse-multiline-attr-hash))
|
477
499
|
(forward-line -1)
|
478
|
-
(
|
479
|
-
|
480
|
-
|
500
|
+
(unless (haml-unclosed-attr-hash-p)
|
501
|
+
(return-from haml-parse-multiline-attr-hash))))))
|
502
|
+
|
503
|
+
(defun* haml-unclosed-attr-hash-p ()
|
504
|
+
"Return t if this line has an unclosed attribute hash, new or old."
|
505
|
+
(save-excursion
|
506
|
+
(end-of-line)
|
507
|
+
(when (eq (char-before) ?,) (return-from haml-unclosed-attr-hash-p t))
|
508
|
+
(re-search-backward "(\\|^")
|
509
|
+
(haml-move "(")
|
510
|
+
(haml-parse-new-attr-hash)))
|
511
|
+
|
512
|
+
(defun* haml-parse-new-attr-hash (&optional (fn (lambda (type beg end) ())))
|
513
|
+
"Parse a new-style attribute hash on this line, and returns
|
514
|
+
t if it's not finished on the current line.
|
515
|
+
|
516
|
+
FN should take three parameters: TYPE, BEG, and END.
|
517
|
+
TYPE is the type of text parsed ('name or 'value)
|
518
|
+
and BEG and END delimit that text in the buffer."
|
519
|
+
(let ((eol (save-excursion (end-of-line) (point))))
|
520
|
+
(while (not (haml-move ")"))
|
521
|
+
(haml-move " *")
|
522
|
+
(unless (haml-move "[a-z0-9_:\\-]+")
|
523
|
+
(return-from haml-parse-new-attr-hash (haml-move " *$")))
|
524
|
+
(funcall fn 'name (match-beginning 0) (match-end 0))
|
525
|
+
(haml-move " *")
|
526
|
+
(when (haml-move "=")
|
527
|
+
(haml-move " *")
|
528
|
+
(unless (looking-at "[\"'@a-z]") (return-from haml-parse-new-attr-hash))
|
529
|
+
(let ((beg (point)))
|
530
|
+
(haml-limited-forward-sexp eol)
|
531
|
+
(funcall fn 'value beg (point)))
|
532
|
+
(haml-move " *")))
|
533
|
+
nil))
|
481
534
|
|
482
535
|
(defun haml-compute-indentation ()
|
483
536
|
"Calculate the maximum sensible indentation for the current line."
|
data/lib/haml/buffer.rb
CHANGED
@@ -252,7 +252,7 @@ RUBY
|
|
252
252
|
|
253
253
|
if to['class'] && from['class']
|
254
254
|
# Make sure we don't duplicate class names
|
255
|
-
from['class'] = (from['class'].split(' ') | to['class'].split(' ')).join(' ')
|
255
|
+
from['class'] = (from['class'].split(' ') | to['class'].split(' ')).sort.join(' ')
|
256
256
|
elsif to['class'] || from['class']
|
257
257
|
from['class'] ||= to['class']
|
258
258
|
end
|
data/lib/haml/precompiler.rb
CHANGED
@@ -456,8 +456,6 @@ END
|
|
456
456
|
end
|
457
457
|
|
458
458
|
def parse_static_hash(text)
|
459
|
-
return {} unless text
|
460
|
-
|
461
459
|
attributes = {}
|
462
460
|
scanner = StringScanner.new(text)
|
463
461
|
scanner.scan(/\s+/)
|
@@ -512,21 +510,38 @@ END
|
|
512
510
|
def parse_tag(line)
|
513
511
|
raise SyntaxError.new("Invalid tag: \"#{line}\".") unless match = line.scan(/%([-:\w]+)([-\w\.\#]*)(.*)/)[0]
|
514
512
|
tag_name, attributes, rest = match
|
515
|
-
|
513
|
+
new_attributes_hash = old_attributes_hash = last_line = object_ref = nil
|
514
|
+
attributes_hashes = []
|
515
|
+
while rest
|
516
|
+
case rest[0]
|
517
|
+
when ?{
|
518
|
+
break if old_attributes_hash
|
519
|
+
old_attributes_hash, rest, last_line = parse_old_attributes(rest)
|
520
|
+
attributes_hashes << [:old, old_attributes_hash]
|
521
|
+
when ?(
|
522
|
+
break if new_attributes_hash
|
523
|
+
new_attributes_hash, rest, last_line = parse_new_attributes(rest)
|
524
|
+
attributes_hashes << [:new, new_attributes_hash]
|
525
|
+
when ?[
|
526
|
+
break if object_ref
|
527
|
+
object_ref, rest = balance(rest, ?[, ?])
|
528
|
+
else; break
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
516
532
|
if rest
|
517
|
-
object_ref, rest = balance(rest, ?[, ?]) if rest[0] == ?[
|
518
|
-
attributes_hash, rest, last_line = parse_attributes(rest) if rest[0] == ?{ && attributes_hash.nil?
|
519
533
|
nuke_whitespace, action, value = rest.scan(/(<>|><|[><])?([=\/\~&!])?(.*)?/)[0]
|
520
534
|
nuke_whitespace ||= ''
|
521
535
|
nuke_outer_whitespace = nuke_whitespace.include? '>'
|
522
536
|
nuke_inner_whitespace = nuke_whitespace.include? '<'
|
523
537
|
end
|
538
|
+
|
524
539
|
value = value.to_s.strip
|
525
|
-
[tag_name, attributes,
|
540
|
+
[tag_name, attributes, attributes_hashes, object_ref, nuke_outer_whitespace,
|
526
541
|
nuke_inner_whitespace, action, value, last_line || @index]
|
527
542
|
end
|
528
543
|
|
529
|
-
def
|
544
|
+
def parse_old_attributes(line)
|
530
545
|
line = line.dup
|
531
546
|
last_line = @index
|
532
547
|
|
@@ -547,10 +562,77 @@ END
|
|
547
562
|
return attributes_hash, rest, last_line
|
548
563
|
end
|
549
564
|
|
565
|
+
def parse_new_attributes(line)
|
566
|
+
line = line.dup
|
567
|
+
scanner = StringScanner.new(line)
|
568
|
+
last_line = @index
|
569
|
+
attributes = {}
|
570
|
+
|
571
|
+
scanner.scan(/\(\s*/)
|
572
|
+
until (name, value = parse_new_attribute(scanner)).first.nil?
|
573
|
+
if name == false
|
574
|
+
text = (Haml::Shared.balance(line, ?(, ?)) || [line]).first
|
575
|
+
raise Haml::SyntaxError.new("Invalid attribute list: #{text.inspect}.", last_line - 1)
|
576
|
+
end
|
577
|
+
attributes[name] = value
|
578
|
+
scanner.scan(/\s*/)
|
579
|
+
|
580
|
+
if scanner.eos?
|
581
|
+
line << " " << @next_line.text
|
582
|
+
last_line += 1
|
583
|
+
next_line
|
584
|
+
scanner.scan(/\s*/)
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
static_attributes = {}
|
589
|
+
dynamic_attributes = "{"
|
590
|
+
attributes.each do |name, (type, val)|
|
591
|
+
if type == :static
|
592
|
+
static_attributes[name] = val
|
593
|
+
else
|
594
|
+
dynamic_attributes << name.inspect << " => " << val << ","
|
595
|
+
end
|
596
|
+
end
|
597
|
+
dynamic_attributes << "}"
|
598
|
+
dynamic_attributes = nil if dynamic_attributes == "{}"
|
599
|
+
|
600
|
+
return [static_attributes, dynamic_attributes], scanner.rest, last_line
|
601
|
+
end
|
602
|
+
|
603
|
+
def parse_new_attribute(scanner)
|
604
|
+
unless name = scanner.scan(/[-:\w]+/)
|
605
|
+
return if scanner.scan(/\)/)
|
606
|
+
return false
|
607
|
+
end
|
608
|
+
|
609
|
+
scanner.scan(/\s*/)
|
610
|
+
return name, [:static, true] unless scanner.scan(/=/) #/end
|
611
|
+
|
612
|
+
scanner.scan(/\s*/)
|
613
|
+
unless quote = scanner.scan(/["']/)
|
614
|
+
return false unless var = scanner.scan(/(@@?|\$)?\w+/)
|
615
|
+
return name, [:dynamic, var]
|
616
|
+
end
|
617
|
+
|
618
|
+
re = /((?:\\.|\#[^{]|[^#{quote}\\#])*)(#{quote}|#\{)/
|
619
|
+
content = []
|
620
|
+
loop do
|
621
|
+
return false unless scanner.scan(re)
|
622
|
+
content << [:str, scanner[1].gsub(/\\(.)/, '\1')]
|
623
|
+
break if scanner[2] == quote
|
624
|
+
content << [:ruby, balance(scanner, ?{, ?}, 1).first[0...-1]]
|
625
|
+
end
|
626
|
+
|
627
|
+
return name, [:static, content.first[1]] if content.size == 1
|
628
|
+
return name, [:dynamic,
|
629
|
+
'"' + content.map {|(t, v)| t == :str ? v.inspect[1...-1] : "\#{#{v}}"}.join + '"']
|
630
|
+
end
|
631
|
+
|
550
632
|
# Parses a line that will render as an XHTML tag, and adds the code that will
|
551
633
|
# render that tag to <tt>@precompiled</tt>.
|
552
634
|
def render_tag(line)
|
553
|
-
tag_name, attributes,
|
635
|
+
tag_name, attributes, attributes_hashes, object_ref, nuke_outer_whitespace,
|
554
636
|
nuke_inner_whitespace, action, value, last_line = parse_tag(line)
|
555
637
|
|
556
638
|
raise SyntaxError.new("Illegal element: classes and ids must have values.") if attributes =~ /[\.#](\.|#|\z)/
|
@@ -597,10 +679,17 @@ END
|
|
597
679
|
|
598
680
|
object_ref = "nil" if object_ref.nil? || @options[:suppress_eval]
|
599
681
|
|
600
|
-
static_attributes = parse_static_hash(attributes_hash) # Try pre-compiling a static attributes hash
|
601
|
-
attributes_hash = nil if static_attributes || @options[:suppress_eval]
|
602
682
|
attributes = parse_class_and_id(attributes)
|
603
|
-
|
683
|
+
attributes_hashes.map! do |syntax, attributes_hash|
|
684
|
+
if syntax == :old
|
685
|
+
static_attributes = parse_static_hash(attributes_hash)
|
686
|
+
attributes_hash = nil if static_attributes || @options[:suppress_eval]
|
687
|
+
else
|
688
|
+
static_attributes, attributes_hash = attributes_hash
|
689
|
+
end
|
690
|
+
Buffer.merge_attrs(attributes, static_attributes) if static_attributes
|
691
|
+
attributes_hash
|
692
|
+
end.compact!
|
604
693
|
|
605
694
|
raise SyntaxError.new("Illegal nesting: nesting within a self-closing tag is illegal.", @next_line.index) if block_opened? && self_closing
|
606
695
|
raise SyntaxError.new("Illegal nesting: content can't be both given on the same line as %#{tag_name} and nested within it.", @next_line.index) if block_opened? && !value.empty?
|
@@ -614,7 +703,7 @@ END
|
|
614
703
|
(nuke_inner_whitespace && block_opened?)
|
615
704
|
|
616
705
|
# Check if we can render the tag directly to text and not process it in the buffer
|
617
|
-
if object_ref == "nil" &&
|
706
|
+
if object_ref == "nil" && attributes_hashes.empty? && !preserve_script
|
618
707
|
tag_closed = !block_opened? && !self_closing && !parse
|
619
708
|
|
620
709
|
open_tag = prerender_tag(tag_name, self_closing, attributes)
|
@@ -633,11 +722,18 @@ END
|
|
633
722
|
else
|
634
723
|
flush_merged_text
|
635
724
|
content = value.empty? || parse ? 'nil' : value.dump
|
636
|
-
|
725
|
+
if attributes_hashes.empty?
|
726
|
+
attributes_hashes = ''
|
727
|
+
elsif attributes_hashes.size == 1
|
728
|
+
attributes_hashes = ", #{attributes_hashes.first}"
|
729
|
+
else
|
730
|
+
attributes_hashes = ", (#{attributes_hashes.join(").merge(")})"
|
731
|
+
end
|
732
|
+
|
637
733
|
args = [tag_name, self_closing, !block_opened?, preserve_tag, escape_html,
|
638
734
|
attributes, nuke_outer_whitespace, nuke_inner_whitespace
|
639
735
|
].map { |v| v.inspect }.join(', ')
|
640
|
-
push_silent "_hamlout.open_tag(#{args}, #{object_ref}, #{content}#{
|
736
|
+
push_silent "_hamlout.open_tag(#{args}, #{object_ref}, #{content}#{attributes_hashes})"
|
641
737
|
@dont_tab_up_next_text = @dont_indent_next_line = dont_indent_next_line
|
642
738
|
end
|
643
739
|
|
data/lib/sass/script/number.rb
CHANGED
@@ -269,9 +269,9 @@ module Sass::Script
|
|
269
269
|
# An incompatible coercion, e.g. between px and cm, will raise an error.
|
270
270
|
#
|
271
271
|
# @param num_units [Array<String>] The numerator units to coerce this number into.
|
272
|
-
# See {
|
272
|
+
# See {\#numerator\_units}
|
273
273
|
# @param den_units [Array<String>] The denominator units to coerce this number into.
|
274
|
-
# See {
|
274
|
+
# See {\#denominator\_units}
|
275
275
|
# @return [Number] The number with the new units
|
276
276
|
# @raise [Sass::UnitConversionError] if the given units are incompatible with the number's
|
277
277
|
# current units
|
data/test/haml/engine_test.rb
CHANGED
@@ -23,6 +23,7 @@ class EngineTest < Test::Unit::TestCase
|
|
23
23
|
"." => "Illegal element: classes and ids must have values.",
|
24
24
|
".#" => "Illegal element: classes and ids must have values.",
|
25
25
|
".{} a" => "Illegal element: classes and ids must have values.",
|
26
|
+
".() a" => "Illegal element: classes and ids must have values.",
|
26
27
|
".= a" => "Illegal element: classes and ids must have values.",
|
27
28
|
"%p..a" => "Illegal element: classes and ids must have values.",
|
28
29
|
"%a/ b" => "Self-closing tags can't have content.",
|
@@ -47,6 +48,12 @@ class EngineTest < Test::Unit::TestCase
|
|
47
48
|
"%p\n foo\n%p\n bar" => ["The line was indented 2 levels deeper than the previous line.", 4],
|
48
49
|
"%p\n foo\n %p\n bar" => ["The line was indented 3 levels deeper than the previous line.", 4],
|
49
50
|
"%p\n \tfoo" => ["Indentation can't use both tabs and spaces.", 2],
|
51
|
+
"%p(" => "Invalid attribute list: \"(\".",
|
52
|
+
"%p(foo=\nbar)" => ["Invalid attribute list: \"(foo=\".", 1],
|
53
|
+
"%p(foo=)" => "Invalid attribute list: \"(foo=)\".",
|
54
|
+
"%p(foo 'bar')" => "Invalid attribute list: \"(foo 'bar')\".",
|
55
|
+
"%p(foo 'bar'\nbaz='bang')" => ["Invalid attribute list: \"(foo 'bar'\".", 1],
|
56
|
+
"%p(foo='bar'\nbaz 'bang'\nbip='bop')" => ["Invalid attribute list: \"(foo='bar' baz 'bang'\".", 2],
|
50
57
|
|
51
58
|
# Regression tests
|
52
59
|
"- raise 'foo'\n\n\n\nbar" => ["foo", 1],
|
@@ -805,6 +812,104 @@ END
|
|
805
812
|
assert_equal %{<!DOCTYPE html>\n}, render('!!!', :format => :html5)
|
806
813
|
end
|
807
814
|
|
815
|
+
# New attributes
|
816
|
+
|
817
|
+
def test_basic_new_attributes
|
818
|
+
assert_equal("<a>bar</a>\n", render("%a() bar"))
|
819
|
+
assert_equal("<a href='foo'>bar</a>\n", render("%a(href='foo') bar"))
|
820
|
+
assert_equal("<a b='c' c='d' d='e'>baz</a>\n", render(%q{%a(b="c" c='d' d="e") baz}))
|
821
|
+
end
|
822
|
+
|
823
|
+
def test_new_attribute_ids
|
824
|
+
assert_equal("<div id='foo_bar'></div>\n", render("#foo(id='bar')"))
|
825
|
+
assert_equal("<div id='foo_bar_baz'></div>\n", render("#foo{:id => 'bar'}(id='baz')"))
|
826
|
+
assert_equal("<div id='foo_baz_bar'></div>\n", render("#foo(id='baz'){:id => 'bar'}"))
|
827
|
+
foo = User.new(42)
|
828
|
+
assert_equal("<div class='struct_user' id='foo_baz_bar_struct_user_42'></div>\n",
|
829
|
+
render("#foo(id='baz'){:id => 'bar'}[foo]", :locals => {:foo => foo}))
|
830
|
+
assert_equal("<div class='struct_user' id='foo_baz_bar_struct_user_42'></div>\n",
|
831
|
+
render("#foo(id='baz')[foo]{:id => 'bar'}", :locals => {:foo => foo}))
|
832
|
+
assert_equal("<div class='struct_user' id='foo_baz_bar_struct_user_42'></div>\n",
|
833
|
+
render("#foo[foo](id='baz'){:id => 'bar'}", :locals => {:foo => foo}))
|
834
|
+
assert_equal("<div class='struct_user' id='foo_bar_baz_struct_user_42'></div>\n",
|
835
|
+
render("#foo[foo]{:id => 'bar'}(id='baz')", :locals => {:foo => foo}))
|
836
|
+
end
|
837
|
+
|
838
|
+
def test_new_attribute_classes
|
839
|
+
assert_equal("<div class='bar foo'></div>\n", render(".foo(class='bar')"))
|
840
|
+
assert_equal("<div class='bar baz foo'></div>\n", render(".foo{:class => 'bar'}(class='baz')"))
|
841
|
+
assert_equal("<div class='bar baz foo'></div>\n", render(".foo(class='baz'){:class => 'bar'}"))
|
842
|
+
foo = User.new(42)
|
843
|
+
assert_equal("<div class='bar baz foo struct_user' id='struct_user_42'></div>\n",
|
844
|
+
render(".foo(class='baz'){:class => 'bar'}[foo]", :locals => {:foo => foo}))
|
845
|
+
assert_equal("<div class='bar baz foo struct_user' id='struct_user_42'></div>\n",
|
846
|
+
render(".foo[foo](class='baz'){:class => 'bar'}", :locals => {:foo => foo}))
|
847
|
+
assert_equal("<div class='bar baz foo struct_user' id='struct_user_42'></div>\n",
|
848
|
+
render(".foo[foo]{:class => 'bar'}(class='baz')", :locals => {:foo => foo}))
|
849
|
+
end
|
850
|
+
|
851
|
+
def test_dynamic_new_attributes
|
852
|
+
assert_equal("<a href='12'>bar</a>\n", render("%a(href=foo) bar", :locals => {:foo => 12}))
|
853
|
+
assert_equal("<a b='12' c='13' d='14'>bar</a>\n", render("%a(b=b c='13' d=d) bar", :locals => {:b => 12, :d => 14}))
|
854
|
+
end
|
855
|
+
|
856
|
+
def test_new_attribute_interpolation
|
857
|
+
assert_equal("<a href='12'>bar</a>\n", render('%a(href="1#{1 + 1}") bar'))
|
858
|
+
assert_equal("<a href='2: 2, 3: 3'>bar</a>\n", render(%q{%a(href='2: #{1 + 1}, 3: #{foo}') bar}, :locals => {:foo => 3}))
|
859
|
+
assert_equal(%Q{<a href='1\#{1 + 1}'>bar</a>\n}, render('%a(href="1\#{1 + 1}") bar'))
|
860
|
+
end
|
861
|
+
|
862
|
+
def test_truthy_new_attributes
|
863
|
+
assert_equal("<a href='href'>bar</a>\n", render("%a(href) bar"))
|
864
|
+
assert_equal("<a bar='baz' href>bar</a>\n", render("%a(href bar='baz') bar", :format => :html5))
|
865
|
+
assert_equal("<a href='href'>bar</a>\n", render("%a(href=true) bar"))
|
866
|
+
assert_equal("<a>bar</a>\n", render("%a(href=false) bar"))
|
867
|
+
end
|
868
|
+
|
869
|
+
def test_new_attribute_parsing
|
870
|
+
assert_equal("<a a2='b2'>bar</a>\n", render("%a(a2=b2) bar", :locals => {:b2 => 'b2'}))
|
871
|
+
assert_equal(%Q{<a a='foo"bar'>bar</a>\n}, render(%q{%a(a="#{'foo"bar'}") bar})) #'
|
872
|
+
assert_equal(%Q{<a a="foo'bar">bar</a>\n}, render(%q{%a(a="#{"foo'bar"}") bar})) #'
|
873
|
+
assert_equal(%Q{<a a='foo"bar'>bar</a>\n}, render(%q{%a(a='foo"bar') bar}))
|
874
|
+
assert_equal(%Q{<a a="foo'bar">bar</a>\n}, render(%q{%a(a="foo'bar") bar}))
|
875
|
+
assert_equal("<a a:b='foo'>bar</a>\n", render("%a(a:b='foo') bar"))
|
876
|
+
assert_equal("<a a='foo' b='bar'>bar</a>\n", render("%a(a = 'foo' b = 'bar') bar"))
|
877
|
+
assert_equal("<a a='foo' b='bar'>bar</a>\n", render("%a(a = foo b = bar) bar", :locals => {:foo => 'foo', :bar => 'bar'}))
|
878
|
+
assert_equal("<a a='foo'>(b='bar')</a>\n", render("%a(a='foo')(b='bar')"))
|
879
|
+
assert_equal("<a a='foo)bar'>baz</a>\n", render("%a(a='foo)bar') baz"))
|
880
|
+
assert_equal("<a a='foo'>baz</a>\n", render("%a( a = 'foo' ) baz"))
|
881
|
+
end
|
882
|
+
|
883
|
+
def test_new_attribute_escaping
|
884
|
+
assert_equal(%Q{<a a='foo " bar'>bar</a>\n}, render(%q{%a(a="foo \" bar") bar}))
|
885
|
+
assert_equal(%Q{<a a='foo \\" bar'>bar</a>\n}, render(%q{%a(a="foo \\\\\" bar") bar}))
|
886
|
+
|
887
|
+
assert_equal(%Q{<a a="foo ' bar">bar</a>\n}, render(%q{%a(a='foo \' bar') bar}))
|
888
|
+
assert_equal(%Q{<a a="foo \\' bar">bar</a>\n}, render(%q{%a(a='foo \\\\\' bar') bar}))
|
889
|
+
|
890
|
+
assert_equal(%Q{<a a='foo \\ bar'>bar</a>\n}, render(%q{%a(a="foo \\\\ bar") bar}))
|
891
|
+
assert_equal(%Q{<a a='foo \#{1 + 1} bar'>bar</a>\n}, render(%q{%a(a="foo \#{1 + 1} bar") bar}))
|
892
|
+
end
|
893
|
+
|
894
|
+
def test_multiline_new_attribute
|
895
|
+
assert_equal("<a a='b' c='d'>bar</a>\n", render("%a(a='b'\n c='d') bar"))
|
896
|
+
assert_equal("<a a='b' b='c' c='d' d='e' e='f' f='j'>bar</a>\n",
|
897
|
+
render("%a(a='b' b='c'\n c='d' d=e\n e='f' f='j') bar", :locals => {:e => 'e'}))
|
898
|
+
end
|
899
|
+
|
900
|
+
def test_new_and_old_attributes
|
901
|
+
assert_equal("<a a='b' c='d'>bar</a>\n", render("%a(a='b'){:c => 'd'} bar"))
|
902
|
+
assert_equal("<a a='b' c='d'>bar</a>\n", render("%a{:c => 'd'}(a='b') bar"))
|
903
|
+
assert_equal("<a a='b' c='d'>bar</a>\n", render("%a(c='d'){:a => 'b'} bar"))
|
904
|
+
assert_equal("<a a='b' c='d'>bar</a>\n", render("%a{:a => 'b'}(c='d') bar"))
|
905
|
+
|
906
|
+
assert_equal("<a a='d'>bar</a>\n", render("%a{:a => 'b'}(a='d') bar"))
|
907
|
+
assert_equal("<a a='b'>bar</a>\n", render("%a(a='d'){:a => 'b'} bar"))
|
908
|
+
|
909
|
+
assert_equal("<a a='b' b='c' c='d' d='e'>bar</a>\n",
|
910
|
+
render("%a{:a => 'b',\n:b => 'c'}(c='d'\nd='e') bar"))
|
911
|
+
end
|
912
|
+
|
808
913
|
# Encodings
|
809
914
|
|
810
915
|
unless Haml::Util.ruby1_8?
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: haml-edge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.45
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Weizenbaum
|
@@ -12,8 +12,27 @@ cert_chain: []
|
|
12
12
|
|
13
13
|
date: 2009-07-04 00:00:00 -04:00
|
14
14
|
default_executable:
|
15
|
-
dependencies:
|
16
|
-
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: yard
|
18
|
+
type: :development
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.2.3
|
25
|
+
version:
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: maruku
|
28
|
+
type: :development
|
29
|
+
version_requirement:
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.5.9
|
35
|
+
version:
|
17
36
|
description: Haml (HTML Abstraction Markup Language) is a layer on top of XHTML or XML that's designed to express the structure of XHTML or XML documents in a non-repetitive, elegant, easy way, using indentation rather than closing tags and allowing Ruby to be embedded with ease. It was originally envisioned as a plugin for Ruby on Rails, but it can function as a stand-alone templating engine.
|
18
37
|
email: haml@googlegroups.com
|
19
38
|
executables:
|