slim 2.0.3 → 2.1.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +7 -8
- data/.yardopts +1 -1
- data/CHANGES +23 -0
- data/Gemfile +2 -1
- data/LICENSE +1 -1
- data/README.jp.md +497 -268
- data/README.md +505 -278
- data/Rakefile +14 -2
- data/benchmarks/view.haml +2 -2
- data/doc/include.md +20 -0
- data/doc/jp/include.md +20 -0
- data/doc/jp/logic_less.md +137 -0
- data/doc/jp/smart.md +102 -0
- data/doc/jp/translator.md +28 -0
- data/doc/smart.md +102 -0
- data/lib/slim/command.rb +8 -2
- data/lib/slim/controls.rb +4 -3
- data/lib/slim/do_inserter.rb +1 -1
- data/lib/slim/embedded.rb +26 -22
- data/lib/slim/end_inserter.rb +1 -1
- data/lib/slim/engine.rb +3 -2
- data/lib/slim/filter.rb +2 -2
- data/lib/slim/grammar.rb +3 -1
- data/lib/slim/include.rb +54 -0
- data/lib/slim/interpolation.rb +1 -1
- data/lib/slim/parser.rb +61 -46
- data/lib/slim/smart.rb +8 -0
- data/lib/slim/smart/escaper.rb +42 -0
- data/lib/slim/smart/filter.rb +96 -0
- data/lib/slim/smart/parser.rb +33 -0
- data/lib/slim/splat/builder.rb +3 -3
- data/lib/slim/splat/filter.rb +2 -2
- data/lib/slim/translator.rb +2 -2
- data/lib/slim/version.rb +1 -1
- data/slim.gemspec +1 -1
- data/test/core/helper.rb +5 -3
- data/test/core/test_code_blocks.rb +11 -0
- data/test/core/test_code_escaping.rb +14 -4
- data/test/core/test_embedded_engines.rb +26 -0
- data/test/core/test_html_structure.rb +39 -0
- data/test/core/test_parser_errors.rb +8 -25
- data/test/core/test_pretty.rb +15 -0
- data/test/core/test_ruby_errors.rb +0 -10
- data/test/include/files/recursive.slim +1 -0
- data/test/include/files/slimfile.slim +3 -0
- data/test/include/files/subdir/test.slim +1 -0
- data/test/include/files/textfile +1 -0
- data/test/include/test_include.rb +23 -0
- data/test/literate/TESTS.md +17 -2
- data/test/rails/test/test_slim.rb +1 -1
- data/test/smart/test_smart_text.rb +300 -0
- data/test/translator/test_translator.rb +7 -6
- metadata +22 -4
data/lib/slim/smart.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'slim'
|
2
|
+
require 'slim/smart/filter'
|
3
|
+
require 'slim/smart/escaper'
|
4
|
+
require 'slim/smart/parser'
|
5
|
+
|
6
|
+
Slim::Engine.replace(Slim::Parser, Slim::Smart::Parser, :file, :tabsize, :shortcut, :default_tag, :attr_delims, :attr_list_delims, :code_attr_delims, :implicit_text)
|
7
|
+
Slim::Engine.after(Slim::Smart::Parser, Slim::Smart::Filter, :smart_text, :smart_text_end_chars, :smart_text_begin_chars)
|
8
|
+
Slim::Engine.after(Slim::Interpolation, Slim::Smart::Escaper, :smart_text_escaping)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Slim
|
2
|
+
module Smart
|
3
|
+
# Perform smart entity escaping in the
|
4
|
+
# expressions `[:slim, :text, type, Expression]`.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
class Escaper < ::Slim::Filter
|
8
|
+
define_options :smart_text_escaping => true
|
9
|
+
|
10
|
+
def call(exp)
|
11
|
+
if options[:smart_text_escaping]
|
12
|
+
super
|
13
|
+
else
|
14
|
+
exp
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def on_slim_text(type, content)
|
19
|
+
[:escape, type != :verbatim, [:slim, :text, type, compile(content)]]
|
20
|
+
end
|
21
|
+
|
22
|
+
def on_static(string)
|
23
|
+
# Prevent obvious &foo; and Ӓ and ÿ entities from escaping.
|
24
|
+
block = [:multi]
|
25
|
+
until string.empty?
|
26
|
+
case string
|
27
|
+
when /\A&(\w+|#x[0-9a-f]+|#\d+);/i
|
28
|
+
# Entity.
|
29
|
+
block << [:escape, false, [:static, $&]]
|
30
|
+
string = $'
|
31
|
+
when /\A&?[^&]*/
|
32
|
+
# Other text.
|
33
|
+
block << [:static, $&]
|
34
|
+
string = $'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
block
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Slim
|
2
|
+
module Smart
|
3
|
+
# Perform newline processing in the
|
4
|
+
# expressions `[:slim, :text, type, Expression]`.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
class Filter < ::Slim::Filter
|
8
|
+
define_options :smart_text => true,
|
9
|
+
:smart_text_end_chars => '([{',
|
10
|
+
:smart_text_begin_chars => ',.;:!?)]}'
|
11
|
+
|
12
|
+
def initialize(opts = {})
|
13
|
+
super
|
14
|
+
@active = @prepend = @append = false
|
15
|
+
@prepend_re = /\A#{chars_re(options[:smart_text_begin_chars])}/
|
16
|
+
@append_re = /#{chars_re(options[:smart_text_end_chars])}\Z/
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(exp)
|
20
|
+
if options[:smart_text]
|
21
|
+
super
|
22
|
+
else
|
23
|
+
exp
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def on_multi(*exps)
|
28
|
+
# The [:multi] blocks serve two purposes.
|
29
|
+
# On outer level, they collect the building blocks like
|
30
|
+
# tags, verbatim text, and implicit/explicit text.
|
31
|
+
# Within a text block, they collect the individual
|
32
|
+
# lines in [:slim, :interpolate, string] blocks.
|
33
|
+
#
|
34
|
+
# Our goal here is to decide when we want to prepend and
|
35
|
+
# append newlines to those individual interpolated lines.
|
36
|
+
# We basically want the text to come out as it was originally entered,
|
37
|
+
# while removing newlines next to the enclosing tags.
|
38
|
+
#
|
39
|
+
# On outer level, we choose to prepend every time, except
|
40
|
+
# right after the opening tag or after other text block.
|
41
|
+
# We also use the append flag to recognize the last expression
|
42
|
+
# before the closing tag, as we don't want to append newline there.
|
43
|
+
#
|
44
|
+
# Within text block, we prepend only before the first line unless
|
45
|
+
# the outer level tells us not to, and we append only after the last line,
|
46
|
+
# unless the outer level tells us it is the last line before the closing tag.
|
47
|
+
# Of course, this is later subject to the special begin/end characters
|
48
|
+
# which may further suppress the newline at the corresponding line boundary.
|
49
|
+
# Also note that the lines themselves are already correctly separated by newlines,
|
50
|
+
# so we don't have to worry about that at all.
|
51
|
+
block = [:multi]
|
52
|
+
prev = nil
|
53
|
+
last_exp = exps.reject{ |exp| exp.first == :newline }.last unless @active && @append
|
54
|
+
exps.each do |exp|
|
55
|
+
@append = exp.equal?(last_exp)
|
56
|
+
if @active
|
57
|
+
@prepend = false if prev
|
58
|
+
else
|
59
|
+
@prepend = prev && ( prev.first != :slim || prev[1] != :text )
|
60
|
+
end
|
61
|
+
block << compile(exp)
|
62
|
+
prev = exp unless exp.first == :newline
|
63
|
+
end
|
64
|
+
block
|
65
|
+
end
|
66
|
+
|
67
|
+
def on_slim_text(type, content)
|
68
|
+
@active = type != :verbatim
|
69
|
+
[:slim, :text, type, compile(content)]
|
70
|
+
ensure
|
71
|
+
@active = false
|
72
|
+
end
|
73
|
+
|
74
|
+
def on_slim_text_inline(content)
|
75
|
+
# Inline text is not wrapped in multi block, so set it up as if it was.
|
76
|
+
@prepend = false
|
77
|
+
@append = true
|
78
|
+
on_slim_text(:inline, content)
|
79
|
+
end
|
80
|
+
|
81
|
+
def on_slim_interpolate(string)
|
82
|
+
if @active
|
83
|
+
string = "\n" + string if @prepend && string !~ @prepend_re
|
84
|
+
string += "\n" if @append && string !~ @append_re
|
85
|
+
end
|
86
|
+
[:slim, :interpolate, string]
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def chars_re(string)
|
92
|
+
Regexp.union(string.split(//))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Slim
|
2
|
+
module Smart
|
3
|
+
class Parser < ::Slim::Parser
|
4
|
+
define_options :implicit_text => true
|
5
|
+
|
6
|
+
def initialize(opts = {})
|
7
|
+
super
|
8
|
+
word_re = options[:implicit_text] ? LC_WORD_RE : WORD_RE
|
9
|
+
attr_keys = Regexp.union(@attr_shortcut.keys.sort_by {|k| -k.size } )
|
10
|
+
@attr_shortcut_re = /\A(#{attr_keys}+)((?:#{WORD_RE}|-)*)/
|
11
|
+
tag_keys = Regexp.union((@tag_shortcut.keys - @attr_shortcut.keys).sort_by {|k| -k.size } )
|
12
|
+
@tag_re = /\A(?:#{attr_keys}(?=-*#{WORD_RE})|#{tag_keys}|\*(?=[^\s]+)|(#{word_re}(?:#{word_re}|:|-)*#{word_re}|#{word_re}+))/
|
13
|
+
end
|
14
|
+
|
15
|
+
def unknown_line_indicator
|
16
|
+
if @line =~ /\A>( ?)/
|
17
|
+
# Found explicit text block.
|
18
|
+
@stacks.last << [:slim, :text, :explicit, parse_text_block($', @indents.last + $1.size + 1)]
|
19
|
+
else
|
20
|
+
unless options[:implicit_text]
|
21
|
+
syntax_error! 'Illegal shortcut' if @line =~ @attr_shortcut_re
|
22
|
+
super
|
23
|
+
end
|
24
|
+
# Found implicit smart text block.
|
25
|
+
if line = @lines.first
|
26
|
+
indent = ( line =~ /\A\s*\Z/ ? @indents.last + 1 : get_indent(line) )
|
27
|
+
end
|
28
|
+
@stacks.last << [:slim, :text, :implicit, parse_text_block(@line, indent)]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/slim/splat/builder.rb
CHANGED
@@ -10,11 +10,11 @@ module Slim
|
|
10
10
|
def code_attr(name, escape, value)
|
11
11
|
if delim = @options[:merge_attrs][name]
|
12
12
|
value = Array === value ? value.join(delim) : value.to_s
|
13
|
-
attr(name, escape ? Temple::Utils.
|
13
|
+
attr(name, escape ? Temple::Utils.escape_html_safe(value, @options[:use_html_safe]) : value) unless value.empty?
|
14
14
|
elsif @options[:hyphen_attrs].include?(name) && Hash === value
|
15
15
|
hyphen_attr(name, escape, value)
|
16
16
|
elsif value != false && value != nil
|
17
|
-
attr(name, value != true && escape ? Temple::Utils.
|
17
|
+
attr(name, value != true && escape ? Temple::Utils.escape_html_safe(value, @options[:use_html_safe]) : value)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -69,7 +69,7 @@ module Slim
|
|
69
69
|
hyphen_attr("#{name}-#{n.to_s.gsub('_', '-')}", escape, v)
|
70
70
|
end
|
71
71
|
else
|
72
|
-
attr(name, value != true && escape ? Temple::Utils.
|
72
|
+
attr(name, value != true && escape ? Temple::Utils.escape_html_safe(value, @options[:use_html_safe]) : value)
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
data/lib/slim/splat/filter.rb
CHANGED
@@ -2,9 +2,9 @@ module Slim
|
|
2
2
|
module Splat
|
3
3
|
# @api private
|
4
4
|
class Filter < ::Slim::Filter
|
5
|
-
OPTIONS = [:merge_attrs, :attr_quote, :sort_attrs, :default_tag, :hyphen_attrs, :format]
|
5
|
+
OPTIONS = [:merge_attrs, :attr_quote, :sort_attrs, :default_tag, :hyphen_attrs, :format, :use_html_safe]
|
6
6
|
define_options OPTIONS
|
7
|
-
|
7
|
+
set_default_options :hyphen_attrs => %w(data aria), :use_html_safe => ''.respond_to?(:html_safe?)
|
8
8
|
|
9
9
|
def call(exp)
|
10
10
|
@splat_options = nil
|
data/lib/slim/translator.rb
CHANGED
data/lib/slim/version.rb
CHANGED
data/slim.gemspec
CHANGED
@@ -18,6 +18,6 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = %w(lib)
|
20
20
|
|
21
|
-
s.add_runtime_dependency('temple', ['~> 0.6.
|
21
|
+
s.add_runtime_dependency('temple', ['~> 0.6.9'])
|
22
22
|
s.add_runtime_dependency('tilt', ['>= 1.3.3', '< 2.1'])
|
23
23
|
end
|
data/test/core/helper.rb
CHANGED
@@ -46,6 +46,8 @@ class TestSlim < MiniTest::Unit::TestCase
|
|
46
46
|
raise 'Syntax error expected'
|
47
47
|
rescue Slim::Parser::SyntaxError => ex
|
48
48
|
assert_equal message, ex.message
|
49
|
+
message =~ /([^\s]+), Line (\d+)/
|
50
|
+
assert_backtrace ex, "#{$1}:#{$2}"
|
49
51
|
end
|
50
52
|
|
51
53
|
def assert_ruby_error(error, from, source, options = {})
|
@@ -58,12 +60,12 @@ class TestSlim < MiniTest::Unit::TestCase
|
|
58
60
|
def assert_backtrace(ex, from)
|
59
61
|
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
|
60
62
|
# HACK: Rubinius stack trace sometimes has one entry more
|
61
|
-
if ex.backtrace[0] !~ /^#{Regexp.escape from}
|
62
|
-
ex.backtrace[1] =~ /([^\s]+:\d+)
|
63
|
+
if ex.backtrace[0] !~ /^#{Regexp.escape from}/
|
64
|
+
ex.backtrace[1] =~ /([^\s]+:\d+)/
|
63
65
|
assert_equal from, $1
|
64
66
|
end
|
65
67
|
else
|
66
|
-
ex.backtrace[0] =~ /([^\s]+:\d+)
|
68
|
+
ex.backtrace[0] =~ /([^\s]+:\d+)/
|
67
69
|
assert_equal from, $1
|
68
70
|
end
|
69
71
|
end
|
@@ -21,6 +21,17 @@ p
|
|
21
21
|
assert_html '<p>Hello Ruby! Hello from within a block! Hello Ruby!</p>', source
|
22
22
|
end
|
23
23
|
|
24
|
+
def test_render_variable_ending_with_do
|
25
|
+
source = %q{
|
26
|
+
- appelido=10
|
27
|
+
p= appelido
|
28
|
+
- appelido
|
29
|
+
}
|
30
|
+
|
31
|
+
assert_html '<p>10</p>', source
|
32
|
+
end
|
33
|
+
|
34
|
+
|
24
35
|
def test_render_with_output_code_within_block
|
25
36
|
source = %q{
|
26
37
|
p
|
@@ -45,10 +45,9 @@ p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>.".html_safe
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
# splat ignores html_safe? for now
|
49
48
|
def test_render_splat_with_html_safe_true
|
50
49
|
source = %q{
|
51
|
-
p *{ :title => '&'.html_safe }
|
50
|
+
p *{ :title => '&'.html_safe }
|
52
51
|
}
|
53
52
|
|
54
53
|
with_html_safe do
|
@@ -56,13 +55,24 @@ p *{ :title => '&'.html_safe }
|
|
56
55
|
end
|
57
56
|
end
|
58
57
|
|
58
|
+
def test_render_splat_with_html_safe_false
|
59
|
+
source = %q{
|
60
|
+
p *{ :title => '&' }
|
61
|
+
}
|
62
|
+
|
63
|
+
with_html_safe do
|
64
|
+
assert_html "<p title=\"&\"></p>", source, :use_html_safe => true
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
59
69
|
def test_render_attribute_with_html_safe_true
|
60
70
|
source = %q{
|
61
|
-
p title=('&'.html_safe)
|
71
|
+
p title=('&'.html_safe)
|
62
72
|
}
|
63
73
|
|
64
74
|
with_html_safe do
|
65
|
-
assert_html "<p title=\"
|
75
|
+
assert_html "<p title=\"&\"></p>", source, :use_html_safe => true
|
66
76
|
end
|
67
77
|
end
|
68
78
|
|
@@ -69,6 +69,17 @@ creole:
|
|
69
69
|
assert_html "<h1>head1</h1><h2>head2</h2>", source
|
70
70
|
end
|
71
71
|
|
72
|
+
def test_render_with_creole_one_line
|
73
|
+
source = %q{
|
74
|
+
creole: Hello **world**,
|
75
|
+
we can write one-line embedded markup now!
|
76
|
+
= Headline
|
77
|
+
Text
|
78
|
+
.nested: creole: **Strong**
|
79
|
+
}
|
80
|
+
assert_html '<p>Hello <strong>world</strong>, we can write one-line embedded markup now!</p><h1>Headline</h1><p>Text</p><div class="nested"><p><strong>Strong</strong></p></div>', source
|
81
|
+
end
|
82
|
+
|
72
83
|
def test_render_with_org
|
73
84
|
# HACK: org-ruby registers itself in Tilt
|
74
85
|
require 'org-ruby'
|
@@ -113,6 +124,21 @@ p Hi
|
|
113
124
|
assert_html %{<script type="text/javascript">$(function() {});\n\n\nalert('hello')</script><p>Hi</p>}, source
|
114
125
|
end
|
115
126
|
|
127
|
+
def test_render_with_opal
|
128
|
+
begin
|
129
|
+
# HACK: org-ruby registers itself in Tilt
|
130
|
+
require 'opal'
|
131
|
+
rescue LoadError
|
132
|
+
return
|
133
|
+
end
|
134
|
+
|
135
|
+
source = %q{
|
136
|
+
opal:
|
137
|
+
puts 'hello from opal'
|
138
|
+
}
|
139
|
+
assert_match '$puts("hello from opal")', render(source)
|
140
|
+
end
|
141
|
+
|
116
142
|
def test_render_with_javascript_with_tabs
|
117
143
|
source = "javascript:\n\t$(function() {});\n\talert('hello')\np Hi"
|
118
144
|
assert_html "<script type=\"text/javascript\">$(function() {});\nalert('hello')</script><p>Hi</p>", source
|
@@ -14,6 +14,15 @@ html
|
|
14
14
|
assert_html '<html><head><title>Simple Test Title</title></head><body><p>Hello World, meet Slim.</p></body></html>', source
|
15
15
|
end
|
16
16
|
|
17
|
+
def test_relaxed_indentation_of_first_line
|
18
|
+
source = %q{
|
19
|
+
p
|
20
|
+
.content
|
21
|
+
}
|
22
|
+
|
23
|
+
assert_html "<p><div class=\"content\"></div></p>", source
|
24
|
+
end
|
25
|
+
|
17
26
|
def test_html_tag_with_text_and_empty_line
|
18
27
|
source = %q{
|
19
28
|
p Hello
|
@@ -209,6 +218,17 @@ p#test class="paragraph" This is line one.
|
|
209
218
|
assert_html "<p class=\"paragraph\" id=\"test\">This is line one.\nThis is line two.</p>", source
|
210
219
|
end
|
211
220
|
|
221
|
+
def test_relaxed_text_indentation
|
222
|
+
source = %q{
|
223
|
+
p
|
224
|
+
| text block
|
225
|
+
text
|
226
|
+
line3
|
227
|
+
}
|
228
|
+
|
229
|
+
assert_html "<p>text block\ntext\n line3</p>", source
|
230
|
+
end
|
231
|
+
|
212
232
|
def test_output_code_with_leading_spaces
|
213
233
|
source = %q{
|
214
234
|
p= hello_world
|
@@ -311,6 +331,25 @@ closed/
|
|
311
331
|
assert_html '<closed />', source, :format => :xhtml
|
312
332
|
end
|
313
333
|
|
334
|
+
def test_custom_attr_list_delims_option
|
335
|
+
source = %q{
|
336
|
+
p { foo="bar" x=(1+1) }
|
337
|
+
p < x=(1+1) > Hello
|
338
|
+
}
|
339
|
+
|
340
|
+
assert_html '<p foo="bar" x="2"></p><p>< x=(1+1) > Hello</p>', source
|
341
|
+
assert_html '<p foo="bar" x="2"></p><p>< x=(1+1) > Hello</p>', source, :attr_list_delims => {'{' => '}'}
|
342
|
+
assert_html '<p>{ foo="bar" x=(1+1) }</p><p x="2">Hello</p>', source, :attr_list_delims => {'<' => '>'}, :code_attr_delims => { '(' => ')' }
|
343
|
+
end
|
344
|
+
|
345
|
+
def test_closed_tag
|
346
|
+
source = %q{
|
347
|
+
closed/
|
348
|
+
}
|
349
|
+
|
350
|
+
assert_html '<closed />', source, :format => :xhtml
|
351
|
+
end
|
352
|
+
|
314
353
|
def test_attributs_with_parens_and_spaces
|
315
354
|
source = %q{label{ for='filter' }= hello_world}
|
316
355
|
assert_html '<label for="filter">Hello World from @env</label>', source
|
@@ -19,40 +19,23 @@ doctype 5
|
|
19
19
|
assert_syntax_error "Unexpected indentation\n (__TEMPLATE__), Line 3, Column 2\n div Invalid\n ^\n", source
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
22
|
+
def test_malformed_indentation
|
23
23
|
source = %q{
|
24
24
|
p
|
25
|
-
|
26
|
-
|
27
|
-
}
|
28
|
-
|
29
|
-
assert_syntax_error "Text line not indented deep enough.\nThe first text line defines the necessary text indentation.\n (__TEMPLATE__), Line 4, Column 3\n text\n ^\n", source
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_unexpected_text_indentation_in_tag
|
33
|
-
source = %q{
|
34
|
-
ul
|
35
|
-
li List1
|
36
|
-
ul
|
37
|
-
li a
|
38
|
-
li b
|
39
|
-
li List2
|
40
|
-
ul
|
41
|
-
li a
|
42
|
-
li b
|
25
|
+
div Valid
|
26
|
+
div Invalid
|
43
27
|
}
|
44
28
|
|
45
|
-
assert_syntax_error "
|
29
|
+
assert_syntax_error "Malformed indentation\n (__TEMPLATE__), Line 4, Column 1\n div Invalid\n ^\n", source
|
46
30
|
end
|
47
31
|
|
48
|
-
def
|
32
|
+
def test_malformed_indentation2
|
49
33
|
source = %q{
|
50
|
-
p
|
51
34
|
div Valid
|
52
35
|
div Invalid
|
53
36
|
}
|
54
37
|
|
55
|
-
assert_syntax_error "Malformed indentation\n (__TEMPLATE__), Line
|
38
|
+
assert_syntax_error "Malformed indentation\n (__TEMPLATE__), Line 3, Column 1\n div Invalid\n ^\n", source
|
56
39
|
end
|
57
40
|
|
58
41
|
def test_unknown_line_indicator
|
@@ -76,13 +59,13 @@ p
|
|
76
59
|
assert_syntax_error "Expected closing delimiter )\n (__TEMPLATE__), Line 3, Column 33\n img(src=\"img.jpg\" title={title}\n ^\n", source
|
77
60
|
end
|
78
61
|
|
79
|
-
def
|
62
|
+
def test_missing_quote_unexpected_end
|
80
63
|
source = %q{
|
81
64
|
p
|
82
65
|
img(src="img.jpg
|
83
66
|
}
|
84
67
|
|
85
|
-
|
68
|
+
assert_syntax_error "Unexpected end of file\n (__TEMPLATE__), Line 3, Column 0\n \n ^\n", source
|
86
69
|
end
|
87
70
|
|
88
71
|
def test_expected_closing_attribute_delimiter
|