Skip to content

Commit

Permalink
Fixed closing tags when block is ahead
Browse files Browse the repository at this point in the history
  • Loading branch information
vti committed Feb 7, 2010
1 parent b3b40fd commit 24ad159
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 70 deletions.
163 changes: 100 additions & 63 deletions lib/Text/Haml.pm
Expand Up @@ -80,7 +80,7 @@ sub new {
EOF

$attrs->{filters} = {
plain => sub { $_[0] =~ s/\n*$//; $_[0] },
plain => sub { $_[0] =~ s/\n*$//; $_[0] },
escaped => sub { $_[0] },
preserve => sub { $_[0] =~ s/\n/
/g; $_[0] },
javascript => sub {
Expand Down Expand Up @@ -165,36 +165,38 @@ sub parse {

$self->tape([]);

my $level_token = quotemeta ' ';
my $escape_token = quotemeta '&';
my $unescape_token = quotemeta '!';
my $expr_token = quotemeta '=';
my $tag_start = quotemeta '%';
my $class_start = quotemeta '.';
my $id_start = quotemeta '#';
my $level_token = quotemeta ' ';
my $escape_token = quotemeta '&';
my $unescape_token = quotemeta '!';
my $expr_token = quotemeta '=';
my $tag_start = quotemeta '%';
my $class_start = quotemeta '.';
my $id_start = quotemeta '#';

my $attributes_start = quotemeta '{';
my $attributes_end = quotemeta '}';
my $attribute_arrow = quotemeta '=>';
my $attributes_sep = quotemeta ',';
my $attribute_prefix = quotemeta ':';
my $attribute_name = qr/(?:$STRING_RE|.*?(?= |$attribute_arrow))/;
my $attribute_value = qr/(?:$STRING_RE|[^ $attributes_sep$attributes_end]+)/x;
my $attribute_value =
qr/(?:$STRING_RE|[^ $attributes_sep$attributes_end]+)/x;

my $attributes_start2 = quotemeta '(';
my $attributes_end2 = quotemeta ')';
my $attribute_arrow2 = quotemeta '=';
my $attributes_sep2 = ' ';
my $attributes_sep2 = ' ';
my $attribute_name2 = qr/(?:$STRING_RE|.*?(?= |$attribute_arrow2))/;
my $attribute_value2 = qr/(?:$STRING_RE|[^ $attributes_sep2$attributes_end2]+)/;
my $attribute_value2 =
qr/(?:$STRING_RE|[^ $attributes_sep2$attributes_end2]+)/;

my $filter_token = quotemeta ':';
my $quote = "'";
my $comment_token = quotemeta '-#';
my $trim_in = quotemeta '<';
my $trim_out = quotemeta '>';
my $autoclose_token = quotemeta '/';
my $multiline_token = quotemeta '|';
my $filter_token = quotemeta ':';
my $quote = "'";
my $comment_token = quotemeta '-#';
my $trim_in = quotemeta '<';
my $trim_out = quotemeta '>';
my $autoclose_token = quotemeta '/';
my $multiline_token = quotemeta '|';

my $tag_name = qr/([^
$level_token
Expand Down Expand Up @@ -238,7 +240,8 @@ sub parse {
# Inside a filter
my $prev = $tape->[-1];
if ($prev && $prev->{type} eq 'filter') {
if ($prev->{level} < $el->{level} || ($i + 1 < @lines && $line eq ''))
if ($prev->{level} < $el->{level}
|| ($i + 1 < @lines && $line eq ''))
{
$prev->{text} .= "\n" if $prev->{text};
$prev->{text} .= $line;
Expand All @@ -258,26 +261,25 @@ sub parse {

# Doctype
if ($line =~ m/^!!!(?: ([^ ]+)(?: (.*))?)?$/) {
$el->{type} = 'text';
$el->{type} = 'text';
$el->{escape} = 0;
$el->{text} = $self->_doctype($1, $2);
$el->{text} = $self->_doctype($1, $2);
push @$tape, $el;
next;
}

# HTML comment
if ($line =~ m/^\/(?:\[if (.*)?\])?(?: (.*))?/) {
$el->{type} = 'html_comment';
$el->{if} = $1 if $1;
$el->{if} = $1 if $1;
$el->{text} = $2 if $2;
push @$tape, $el;
next;
}

# Escaping, everything after is a text
if ($line =~ s/^\\//) {
$el->{type} = 'text',
$el->{text} = $line;
$el->{type} = 'text', $el->{text} = $line;
push @$tape, $el;
next;
}
Expand All @@ -292,9 +294,9 @@ sub parse {

# Preserve whitespace
if ($line =~ s/^~ \s*(.*)//) {
$el->{type} = 'text';
$el->{text} = $1;
$el->{expr} = 1;
$el->{type} = 'text';
$el->{text} = $1;
$el->{expr} = 1;
$el->{preserve_whitespace} = 1;
push @$tape, $el;
next;
Expand All @@ -319,9 +321,9 @@ sub parse {
if ($line =~ s/^$class_start$tag_name//) {
my $class = join(' ', split(/\./, $1));

$el->{name} ||= 'div';
$el->{name} ||= 'div';
$el->{class} ||= [];
push @{$el->{class}},$class;
push @{$el->{class}}, $class;
}
elsif ($line =~ s/^$id_start$tag_name//) {
my $id = $1;
Expand All @@ -347,7 +349,8 @@ sub parse {
$attribute_arrow2\s*
$attribute_value2
)
/x)
/x
)
{
my $attrs = [];

Expand All @@ -367,7 +370,8 @@ sub parse {
elsif ($type eq 'perl' && $line =~ s/^$attributes_end//) {
last;
}
elsif ($type eq 'html' && $line =~ s/^$attributes_end2//) {
elsif ($type eq 'html' && $line =~ s/^$attributes_end2//)
{
last;
}
else {
Expand All @@ -377,17 +381,21 @@ sub parse {
($attribute_name)\s*
$attribute_arrow\s*
($attribute_value)\s*
(?:$attributes_sep\s*)?//x)
(?:$attributes_sep\s*)?//x
)
{
$name = $1;
$name = $1;
$value = $2;
}
elsif ($line =~ s/^\s*
elsif (
$line =~ s/^\s*
($attribute_name2)\s*
$attribute_arrow2\s*
($attribute_value2)\s*
(?:$attributes_sep2\s*)?//x) {
$name = $1;
(?:$attributes_sep2\s*)?//x
)
{
$name = $1;
$value = $2;
}
else {
Expand All @@ -403,14 +411,18 @@ sub parse {
if ($value =~ s/^(?:'|")//) {
$value =~ s/(?:'|")$//;
$value =~ s/($UNESCAPE_RE)/$ESCAPE->{$1}/g;
push @$attrs, $name => {type => 'text', text => $value};
push @$attrs,
$name => {type => 'text', text => $value};
}
elsif ($value eq 'true' || $value eq 'false') {
push @$attrs, $name =>
{type => 'boolean', text => $value eq 'true' ? 1 : 0};
push @$attrs, $name => {
type => 'boolean',
text => $value eq 'true' ? 1 : 0
};
}
else {
push @$attrs, $name => {type => 'expr', text => $value};
push @$attrs,
$name => {type => 'expr', text => $value};
}
}
}
Expand Down Expand Up @@ -551,12 +563,17 @@ EOF
}

my $escape = '';
if ((!exists $el->{escape} && $self->escape_html) || (exists
$el->{escape} && $el->{escape} == 1)) {
if ( (!exists $el->{escape} && $self->escape_html)
|| (exists $el->{escape} && $el->{escape} == 1))
{
$escape = 'escape';
}

if ($el->{line} && $prev_el && $prev_el->{level} >= $el->{level}) {
if ( $el->{type} ne 'block'
&& $el->{line}
&& $prev_el
&& $prev_el->{level} >= $el->{level})
{
while (my $poped = pop @$stack) {
my $poped_offset = ' ' x $poped->{level};

Expand All @@ -581,10 +598,10 @@ EOF

my $attrs = '';
if ($el->{attrs}) {
for (my $i = 0; $i < @{$el->{attrs}}; $i+=2) {
my $name = $el->{attrs}->[$i];
for (my $i = 0; $i < @{$el->{attrs}}; $i += 2) {
my $name = $el->{attrs}->[$i];
my $value = $el->{attrs}->[$i + 1];
my $text = $value->{text};
my $text = $value->{text};

if ($name eq 'class') {
$el->{class} ||= [];
Expand Down Expand Up @@ -658,7 +675,14 @@ EOF
&& $self->tape->[$count + 1]->{level} == $el->{level})
)
{
$output .= qq|. "</$el->{name}>"| unless $el->{autoclose};
if ( !$self->tape->[$count + 1]
|| $self->tape->[$count + 1]->{type} ne 'block')
{
$output .= qq|. "</$el->{name}>"| unless $el->{autoclose};
}
else {
push @$stack, $el;
}
}
elsif (!$el->{autoclose}) {
push @$stack, $el;
Expand All @@ -677,7 +701,10 @@ EOF
$output .= qq/;\$_H .= "\n"/;
}
elsif ($el->{text}) {
$output .= '.'.qq/$escape /.'"' . $self->_parse_text($el->{text}) . '"';
$output
.= '.'
. qq/$escape / . '"'
. $self->_parse_text($el->{text}) . '"';
$output .= qq/. "\n"/;
}

Expand Down Expand Up @@ -710,7 +737,8 @@ EOF
die "unknown filter: $el->{name}" unless $filter;

if ($el->{name} eq 'escaped') {
$output = qq/escape "/ . $self->_parse_text($el->{text}) . qq/\n";/;
$output =
qq/escape "/ . $self->_parse_text($el->{text}) . qq/\n";/;
}
else {
$el->{text} = $filter->($el->{text});
Expand Down Expand Up @@ -778,14 +806,14 @@ sub _parse_text {
while (1) {
my $t;
my $escape = 0;
my $found = 0;
my $found = 0;
if ($text =~ s/^(.*?)?(?<!\\)\#{//) {
$found = 1;
$t = $1;
$t = $1;
}
elsif ($text =~ s/^(.*?)?\\\\\#{//) {
$found = 1;
$t = $1;
$found = 1;
$t = $1;
$escape = 1;
}

Expand Down Expand Up @@ -891,7 +919,7 @@ sub _doctype {
my $self = shift;
my ($type, $encoding) = @_;

$type ||= '';
$type ||= '';
$encoding ||= 'utf-8';

$type = lc $type;
Expand All @@ -905,36 +933,45 @@ sub _doctype {

if ($self->format eq 'xhtml') {
if ($type eq 'strict') {
return q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">|;
return
q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">|;
}
elsif ($type eq 'frameset') {
return q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">|;
return
q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">|;
}
elsif ($type eq '5') {
return '<!DOCTYPE html>';
}
elsif ($type eq '1.1') {
return q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">|;
return
q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">|;
}
elsif ($type eq 'basic') {
return q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">|;
return
q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">|;
}
elsif ($type eq 'mobile') {
return q|<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">|;
return
q|<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">|;
}
else {
return q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">|;
return
q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">|;
}
}
elsif ($self->format eq 'html4') {
if ($type eq 'strict') {
return q|<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">|;
return
q|<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">|;
}
elsif ($type eq 'frameset') {
return q|<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">|;
return
q|<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">|;
}
else {
return q|<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">|;
return
q|<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">|;
}
}
elsif ($self->format eq 'html5') {
Expand Down
17 changes: 10 additions & 7 deletions t/perl.t
Expand Up @@ -59,18 +59,21 @@ EOF

# Perl Blocks
$output = $haml->render(<<'EOF');
%ul
- for my $i (42..47) {
%p= $i
%li= $i
- }
%p See, I can count!
EOF
is($output, <<'EOF');
<p>42</p>
<p>43</p>
<p>44</p>
<p>45</p>
<p>46</p>
<p>47</p>
<ul>
<li>42</li>
<li>43</li>
<li>44</li>
<li>45</li>
<li>46</li>
<li>47</li>
</ul>
<p>See, I can count!</p>
EOF

Expand Down

0 comments on commit 24ad159

Please sign in to comment.