haml 1.8.0 → 2.0.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.
- data/FAQ +138 -0
- data/MIT-LICENSE +1 -1
- data/{README → README.rdoc} +66 -3
- data/Rakefile +111 -147
- data/VERSION +1 -1
- data/bin/css2sass +0 -0
- data/bin/haml +0 -0
- data/bin/html2haml +0 -0
- data/bin/sass +0 -0
- data/init.rb +6 -1
- data/lib/haml/buffer.rb +121 -63
- data/lib/haml/engine.rb +67 -44
- data/lib/haml/error.rb +16 -6
- data/lib/haml/exec.rb +37 -7
- data/lib/haml/filters.rb +213 -68
- data/lib/haml/helpers/action_view_extensions.rb +1 -1
- data/lib/haml/helpers/action_view_mods.rb +57 -9
- data/lib/haml/helpers.rb +105 -61
- data/lib/haml/html.rb +6 -6
- data/lib/haml/precompiler.rb +268 -132
- data/lib/haml/template/patch.rb +9 -2
- data/lib/haml/template/plugin.rb +61 -10
- data/lib/haml/template.rb +3 -6
- data/lib/haml.rb +464 -201
- data/lib/sass/constant/color.rb +13 -13
- data/lib/sass/constant/literal.rb +7 -7
- data/lib/sass/constant/number.rb +9 -9
- data/lib/sass/constant/operation.rb +4 -4
- data/lib/sass/constant/string.rb +3 -3
- data/lib/sass/constant.rb +22 -22
- data/lib/sass/css.rb +104 -31
- data/lib/sass/engine.rb +120 -39
- data/lib/sass/error.rb +1 -1
- data/lib/sass/plugin/merb.rb +48 -12
- data/lib/sass/plugin/rails.rb +10 -4
- data/lib/sass/plugin.rb +22 -3
- data/lib/sass/tree/attr_node.rb +5 -5
- data/lib/sass/tree/directive_node.rb +2 -7
- data/lib/sass/tree/node.rb +1 -12
- data/lib/sass/tree/rule_node.rb +39 -31
- data/lib/sass/tree/value_node.rb +1 -1
- data/lib/sass.rb +157 -12
- data/test/benchmark.rb +67 -80
- data/test/haml/engine_test.rb +318 -81
- data/test/haml/helper_test.rb +52 -16
- data/test/haml/results/content_for_layout.xhtml +1 -2
- data/test/haml/results/eval_suppressed.xhtml +2 -4
- data/test/haml/results/filters.xhtml +44 -15
- data/test/haml/results/helpers.xhtml +2 -3
- data/test/haml/results/just_stuff.xhtml +2 -6
- data/test/haml/results/nuke_inner_whitespace.xhtml +34 -0
- data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
- data/test/haml/results/original_engine.xhtml +3 -7
- data/test/haml/results/partials.xhtml +1 -0
- data/test/haml/results/tag_parsing.xhtml +1 -6
- data/test/haml/results/very_basic.xhtml +2 -4
- data/test/haml/results/whitespace_handling.xhtml +13 -21
- data/test/haml/template_test.rb +8 -15
- data/test/haml/templates/_partial.haml +1 -0
- data/test/haml/templates/filters.haml +48 -7
- data/test/haml/templates/helpers.haml +9 -9
- data/test/haml/templates/just_stuff.haml +1 -2
- data/test/haml/templates/nuke_inner_whitespace.haml +26 -0
- data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
- data/test/haml/templates/tag_parsing.haml +0 -3
- data/test/haml/test_helper.rb +15 -0
- data/test/sass/engine_test.rb +84 -34
- data/test/sass/plugin_test.rb +1 -1
- data/test/sass/results/import.css +2 -2
- data/test/sass/results/mixins.css +95 -0
- data/test/sass/results/multiline.css +24 -0
- data/test/sass/templates/import.sass +4 -1
- data/test/sass/templates/importee.sass +4 -0
- data/test/sass/templates/mixins.sass +76 -0
- data/test/sass/templates/multiline.sass +20 -0
- metadata +65 -53
- data/lib/haml/helpers/action_view_mods.rb.rej +0 -30
- data/lib/haml/util.rb +0 -18
- data/lib/sass/constant.rb.rej +0 -42
- data/test/haml/runner.rb +0 -16
- data/test/profile.rb +0 -65
- data/test/sass/engine_test.rb.rej +0 -18
data/test/haml/engine_test.rb
CHANGED
|
@@ -1,15 +1,45 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
require 'rubygems'
|
|
4
|
-
require 'active_support'
|
|
5
|
-
require 'action_controller'
|
|
6
|
-
require 'action_view'
|
|
7
|
-
|
|
8
|
-
require 'test/unit'
|
|
9
|
-
require File.dirname(__FILE__) + '/../../lib/haml'
|
|
10
|
-
require 'haml/engine'
|
|
2
|
+
require File.dirname(__FILE__) + '/test_helper'
|
|
11
3
|
|
|
12
4
|
class EngineTest < Test::Unit::TestCase
|
|
5
|
+
# A map of erroneous Sass documents to the error messages they should produce.
|
|
6
|
+
# The error messages may be arrays;
|
|
7
|
+
# if so, the second element should be the line number that should be reported for the error.
|
|
8
|
+
# If this isn't provided, the tests will assume the line number should be the last line of the document.
|
|
9
|
+
EXCEPTION_MAP = {
|
|
10
|
+
"!!!\n a" => "Illegal nesting: nesting within a header command is illegal.",
|
|
11
|
+
"a\n b" => "Illegal nesting: nesting within plain text is illegal.",
|
|
12
|
+
"/ a\n b" => "Illegal nesting: nesting within a tag that already has content is illegal.",
|
|
13
|
+
"% a" => 'Invalid tag: "% a".',
|
|
14
|
+
"%p a\n b" => "Illegal nesting: content can't be both given on the same line as %p and nested within it.",
|
|
15
|
+
"%p=" => "There's no Ruby code for = to evaluate.",
|
|
16
|
+
"%p~" => "There's no Ruby code for ~ to evaluate.",
|
|
17
|
+
"~" => "There's no Ruby code for ~ to evaluate.",
|
|
18
|
+
"=" => "There's no Ruby code for = to evaluate.",
|
|
19
|
+
"%p/\n a" => "Illegal nesting: nesting within a self-closing tag is illegal.",
|
|
20
|
+
"%p\n\ta" => <<END.strip,
|
|
21
|
+
A tab character was used for indentation. Haml must be indented using two spaces.
|
|
22
|
+
Are you sure you have soft tabs enabled in your editor?
|
|
23
|
+
END
|
|
24
|
+
"%p\n a" => "1 space was used for indentation. Haml must be indented using two spaces.",
|
|
25
|
+
"%p\n a" => "3 spaces were used for indentation. Haml must be indented using two spaces.",
|
|
26
|
+
"%p\n a" => "4 spaces were used for indentation. Haml must be indented using two spaces.",
|
|
27
|
+
":a\n b" => ['Filter "a" is not defined.', 1],
|
|
28
|
+
":a= b" => 'Invalid filter name ":a= b".',
|
|
29
|
+
"." => "Illegal element: classes and ids must have values.",
|
|
30
|
+
".#" => "Illegal element: classes and ids must have values.",
|
|
31
|
+
".{} a" => "Illegal element: classes and ids must have values.",
|
|
32
|
+
".= a" => "Illegal element: classes and ids must have values.",
|
|
33
|
+
"%p..a" => "Illegal element: classes and ids must have values.",
|
|
34
|
+
"%a/ b" => "Self-closing tags can't have content.",
|
|
35
|
+
|
|
36
|
+
# Regression tests
|
|
37
|
+
"- raise 'foo'\n\n\n\nbar" => ["foo", 1],
|
|
38
|
+
"= 'foo'\n-raise 'foo'" => ["foo", 2],
|
|
39
|
+
"\n\n\n- raise 'foo'" => ["foo", 4],
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
User = Struct.new('User', :id)
|
|
13
43
|
|
|
14
44
|
def render(text, options = {}, &block)
|
|
15
45
|
scope = options.delete(:scope) || Object.new
|
|
@@ -22,7 +52,7 @@ class EngineTest < Test::Unit::TestCase
|
|
|
22
52
|
end
|
|
23
53
|
|
|
24
54
|
def test_attributes_should_render_correctly
|
|
25
|
-
assert_equal("<div class='atlantis' style='ugly'
|
|
55
|
+
assert_equal("<div class='atlantis' style='ugly'></div>", render(".atlantis{:style => 'ugly'}").chomp)
|
|
26
56
|
end
|
|
27
57
|
|
|
28
58
|
def test_ruby_code_should_work_inside_attributes
|
|
@@ -31,7 +61,7 @@ class EngineTest < Test::Unit::TestCase
|
|
|
31
61
|
end
|
|
32
62
|
|
|
33
63
|
def test_nil_should_render_empty_tag
|
|
34
|
-
assert_equal("<div class='no_attributes'
|
|
64
|
+
assert_equal("<div class='no_attributes'></div>",
|
|
35
65
|
render(".no_attributes{:nil => nil}").chomp)
|
|
36
66
|
end
|
|
37
67
|
|
|
@@ -44,20 +74,8 @@ class EngineTest < Test::Unit::TestCase
|
|
|
44
74
|
assert_equal("<p>Hello</p>", render('%p Hello').chomp)
|
|
45
75
|
end
|
|
46
76
|
|
|
47
|
-
def
|
|
48
|
-
assert_equal("<
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def test_non_prerendered_one_liner
|
|
52
|
-
assert_equal("<p class='awesome'>One line</p>\n", render("%p{:class => c} One line", :locals => {:c => 'awesome'}))
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def test_non_prerendered_script_one_liner
|
|
56
|
-
assert_equal("<p class='awesome'>One line</p>\n", render("%p{:class => c}= 'One line'", :locals => {:c => 'awesome'}))
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def test_non_prerendered_long_script_one_liner
|
|
60
|
-
assert_equal("<p class='awesome'>\n #{'x' * 60}\n</p>\n", render("%p{:class => c}= 'x' * 60", :locals => {:c => 'awesome'}))
|
|
77
|
+
def test_one_liner_with_newline_shouldnt_be_one_line
|
|
78
|
+
assert_equal("<p>\n foo\n bar\n</p>", render('%p= "foo\nbar"').chomp)
|
|
61
79
|
end
|
|
62
80
|
|
|
63
81
|
def test_multi_render
|
|
@@ -93,36 +111,190 @@ class EngineTest < Test::Unit::TestCase
|
|
|
93
111
|
assert_equal("<img alt='' src='/foo.png' />\n", render("%img{:width => nil, :src => '/foo.png', :alt => String.new}"))
|
|
94
112
|
end
|
|
95
113
|
|
|
114
|
+
def test_end_of_file_multiline
|
|
115
|
+
assert_equal("<p>0</p>\n<p>1</p>\n<p>2</p>\n", render("- for i in (0...3)\n %p= |\n i |"))
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def test_cr_newline
|
|
119
|
+
assert_equal("<p>foo</p>\n<p>bar</p>\n<p>baz</p>\n<p>boom</p>\n", render("%p foo\r%p bar\r\n%p baz\n\r%p boom"))
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def test_textareas
|
|
123
|
+
assert_equal("<textarea>Foo
 bar
 baz</textarea>\n",
|
|
124
|
+
render('%textarea= "Foo\n bar\n baz"'))
|
|
125
|
+
|
|
126
|
+
assert_equal("<pre>Foo
 bar
 baz</pre>\n",
|
|
127
|
+
render('%pre= "Foo\n bar\n baz"'))
|
|
128
|
+
|
|
129
|
+
assert_equal("<textarea>#{'a' * 100}</textarea>\n",
|
|
130
|
+
render("%textarea #{'a' * 100}"))
|
|
131
|
+
|
|
132
|
+
assert_equal("<p>\n <textarea>Foo\n Bar\n Baz</textarea>\n</p>\n", render(<<SOURCE))
|
|
133
|
+
%p
|
|
134
|
+
%textarea
|
|
135
|
+
Foo
|
|
136
|
+
Bar
|
|
137
|
+
Baz
|
|
138
|
+
SOURCE
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def test_boolean_attributes
|
|
142
|
+
assert_equal("<p bar baz='true' foo='bar'></p>\n",
|
|
143
|
+
render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :html4))
|
|
144
|
+
assert_equal("<p bar='bar' baz='true' foo='bar'></p>\n",
|
|
145
|
+
render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :xhtml))
|
|
146
|
+
|
|
147
|
+
assert_equal("<p baz='false' foo='bar'></p>\n",
|
|
148
|
+
render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :html4))
|
|
149
|
+
assert_equal("<p baz='false' foo='bar'></p>\n",
|
|
150
|
+
render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :xhtml))
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def test_both_whitespace_nukes_work_together
|
|
154
|
+
assert_equal(<<RESULT, render(<<SOURCE))
|
|
155
|
+
<p><q>Foo
|
|
156
|
+
Bar</q></p>
|
|
157
|
+
RESULT
|
|
158
|
+
%p
|
|
159
|
+
%q><= "Foo\\nBar"
|
|
160
|
+
SOURCE
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# HTML escaping tests
|
|
164
|
+
|
|
165
|
+
def test_ampersand_equals_should_escape
|
|
166
|
+
assert_equal("<p>\n foo & bar\n</p>\n", render("%p\n &= 'foo & bar'", :escape_html => false))
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def test_ampersand_equals_inline_should_escape
|
|
170
|
+
assert_equal("<p>foo & bar</p>\n", render("%p&= 'foo & bar'", :escape_html => false))
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def test_bang_equals_should_not_escape
|
|
174
|
+
assert_equal("<p>\n foo & bar\n</p>\n", render("%p\n != 'foo & bar'", :escape_html => true))
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def test_bang_equals_inline_should_not_escape
|
|
178
|
+
assert_equal("<p>foo & bar</p>\n", render("%p!= 'foo & bar'", :escape_html => true))
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def test_static_attributes_should_be_escaped
|
|
182
|
+
assert_equal("<img class='atlantis' style='ugly&stupid' />\n",
|
|
183
|
+
render("%img.atlantis{:style => 'ugly&stupid'}", :escape_html => true))
|
|
184
|
+
assert_equal("<div class='atlantis' style='ugly&stupid'>foo</div>\n",
|
|
185
|
+
render(".atlantis{:style => 'ugly&stupid'} foo", :escape_html => true))
|
|
186
|
+
assert_equal("<p class='atlantis' style='ugly&stupid'>foo</p>\n",
|
|
187
|
+
render("%p.atlantis{:style => 'ugly&stupid'}= 'foo'", :escape_html => true))
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def test_dynamic_attributes_should_be_escaped
|
|
191
|
+
assert_equal("<img alt='' src='/foo.png' />\n",
|
|
192
|
+
render("%img{:width => nil, :src => '/foo.png', :alt => String.new}", :escape_html => true))
|
|
193
|
+
assert_equal("<p alt='' src='/foo.png'>foo</p>\n",
|
|
194
|
+
render("%p{:width => nil, :src => '/foo.png', :alt => String.new} foo", :escape_html => true))
|
|
195
|
+
assert_equal("<div alt='' src='/foo.png'>foo</div>\n",
|
|
196
|
+
render("%div{:width => nil, :src => '/foo.png', :alt => String.new}= 'foo'", :escape_html => true))
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def test_string_interpolation_should_be_esaped
|
|
200
|
+
assert_equal("<p>4&3</p>\n", render("%p== #{2+2}&#{2+1}", :escape_html => true))
|
|
201
|
+
assert_equal("<p>4&3</p>\n", render("%p== #{2+2}&#{2+1}", :escape_html => false))
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def test_escaped_inline_string_interpolation
|
|
205
|
+
assert_equal("<p>4&3</p>\n", render("%p&== #{2+2}&#{2+1}", :escape_html => true))
|
|
206
|
+
assert_equal("<p>4&3</p>\n", render("%p&== #{2+2}&#{2+1}", :escape_html => false))
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def test_unescaped_inline_string_interpolation
|
|
210
|
+
assert_equal("<p>4&3</p>\n", render("%p!== #{2+2}&#{2+1}", :escape_html => true))
|
|
211
|
+
assert_equal("<p>4&3</p>\n", render("%p!== #{2+2}&#{2+1}", :escape_html => false))
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def test_escaped_string_interpolation
|
|
215
|
+
assert_equal("<p>\n 4&3\n</p>\n", render("%p\n &== #{2+2}&#{2+1}", :escape_html => true))
|
|
216
|
+
assert_equal("<p>\n 4&3\n</p>\n", render("%p\n &== #{2+2}&#{2+1}", :escape_html => false))
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def test_unescaped_string_interpolation
|
|
220
|
+
assert_equal("<p>\n 4&3\n</p>\n", render("%p\n !== #{2+2}&#{2+1}", :escape_html => true))
|
|
221
|
+
assert_equal("<p>\n 4&3\n</p>\n", render("%p\n !== #{2+2}&#{2+1}", :escape_html => false))
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def test_scripts_should_respect_escape_html_option
|
|
225
|
+
assert_equal("<p>\n foo & bar\n</p>\n", render("%p\n = 'foo & bar'", :escape_html => true))
|
|
226
|
+
assert_equal("<p>\n foo & bar\n</p>\n", render("%p\n = 'foo & bar'", :escape_html => false))
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def test_inline_scripts_should_respect_escape_html_option
|
|
230
|
+
assert_equal("<p>foo & bar</p>\n", render("%p= 'foo & bar'", :escape_html => true))
|
|
231
|
+
assert_equal("<p>foo & bar</p>\n", render("%p= 'foo & bar'", :escape_html => false))
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def test_script_ending_in_comment_should_render_when_html_is_escaped
|
|
235
|
+
assert_equal("foo&bar\n", render("= 'foo&bar' #comment", :escape_html => true))
|
|
236
|
+
end
|
|
237
|
+
|
|
96
238
|
# Options tests
|
|
97
239
|
|
|
240
|
+
def test_filename_and_line
|
|
241
|
+
begin
|
|
242
|
+
render("\n\n = abc", :filename => 'test', :line => 2)
|
|
243
|
+
rescue Exception => e
|
|
244
|
+
assert_kind_of Haml::SyntaxError, e
|
|
245
|
+
assert_match /test:4/, e.backtrace.first
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
begin
|
|
249
|
+
render("\n\n= 123\n\n= nil[]", :filename => 'test', :line => 2)
|
|
250
|
+
rescue Exception => e
|
|
251
|
+
assert_kind_of NoMethodError, e
|
|
252
|
+
assert_match /test:6/, e.backtrace.first
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
98
256
|
def test_stop_eval
|
|
99
257
|
assert_equal("", render("= 'Hello'", :suppress_eval => true))
|
|
100
258
|
assert_equal("", render("- puts 'foo'", :suppress_eval => true))
|
|
101
259
|
assert_equal("<div id='foo' yes='no' />\n", render("#foo{:yes => 'no'}/", :suppress_eval => true))
|
|
102
260
|
assert_equal("<div id='foo' />\n", render("#foo{:yes => 'no', :call => a_function() }/", :suppress_eval => true))
|
|
103
261
|
assert_equal("<div />\n", render("%div[1]/", :suppress_eval => true))
|
|
104
|
-
|
|
105
|
-
begin
|
|
106
|
-
assert_equal("", render(":ruby\n puts 'hello'", :suppress_eval => true))
|
|
107
|
-
rescue Haml::HamlError => err
|
|
108
|
-
caught = true
|
|
109
|
-
assert_equal('"ruby" filter is not defined!', err.message)
|
|
110
|
-
end
|
|
111
|
-
assert(caught, "Rendering a ruby filter without evaluating didn't throw an error!")
|
|
262
|
+
assert_equal("", render(":ruby\n puts 'hello'", :suppress_eval => true))
|
|
112
263
|
end
|
|
113
264
|
|
|
114
265
|
def test_attr_wrapper
|
|
115
|
-
assert_equal("<p strange=*attrs
|
|
116
|
-
assert_equal("<p escaped='quo\"te'
|
|
117
|
-
assert_equal("<p escaped=\"
|
|
266
|
+
assert_equal("<p strange=*attrs*></p>\n", render("%p{ :strange => 'attrs'}", :attr_wrapper => '*'))
|
|
267
|
+
assert_equal("<p escaped='quo\"te'></p>\n", render("%p{ :escaped => 'quo\"te'}", :attr_wrapper => '"'))
|
|
268
|
+
assert_equal("<p escaped=\"quo'te\"></p>\n", render("%p{ :escaped => 'quo\\'te'}", :attr_wrapper => '"'))
|
|
269
|
+
assert_equal("<p escaped=\"q'uo"te\"></p>\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"'))
|
|
118
270
|
assert_equal("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n", render("!!! XML", :attr_wrapper => '"'))
|
|
119
271
|
end
|
|
120
272
|
|
|
121
273
|
def test_attrs_parsed_correctly
|
|
122
|
-
assert_equal("<p boom=>biddly='bar
|
|
123
|
-
assert_equal("<p foo,bar='baz, qux'
|
|
124
|
-
assert_equal("<p escaped='quo\nte'
|
|
125
|
-
assert_equal("<p escaped='quo4te'
|
|
274
|
+
assert_equal("<p boom=>biddly='bar => baz'></p>\n", render("%p{'boom=>biddly' => 'bar => baz'}"))
|
|
275
|
+
assert_equal("<p foo,bar='baz, qux'></p>\n", render("%p{'foo,bar' => 'baz, qux'}"))
|
|
276
|
+
assert_equal("<p escaped='quo\nte'></p>\n", render("%p{ :escaped => \"quo\\nte\"}"))
|
|
277
|
+
assert_equal("<p escaped='quo4te'></p>\n", render("%p{ :escaped => \"quo\#{2 + 2}te\"}"))
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def test_correct_parsing_with_brackets
|
|
281
|
+
assert_equal("<p class='foo'>{tada} foo</p>\n", render("%p{:class => 'foo'} {tada} foo"))
|
|
282
|
+
assert_equal("<p class='foo'>deep {nested { things }}</p>\n", render("%p{:class => 'foo'} deep {nested { things }}"))
|
|
283
|
+
assert_equal("<p class='bar foo'>{a { d</p>\n", render("%p{{:class => 'foo'}, :class => 'bar'} {a { d"))
|
|
284
|
+
assert_equal("<p foo='bar'>a}</p>\n", render("%p{:foo => 'bar'} a}"))
|
|
285
|
+
|
|
286
|
+
foo = []
|
|
287
|
+
foo[0] = Struct.new('Foo', :id).new
|
|
288
|
+
assert_equal("<p class='struct_foo' id='struct_foo_new'>New User]</p>\n",
|
|
289
|
+
render("%p[foo[0]] New User]", :locals => {:foo => foo}))
|
|
290
|
+
assert_equal("<p class='prefix_struct_foo' id='prefix_struct_foo_new'>New User]</p>\n",
|
|
291
|
+
render("%p[foo[0], :prefix] New User]", :locals => {:foo => foo}))
|
|
292
|
+
|
|
293
|
+
foo[0].id = 1
|
|
294
|
+
assert_equal("<p class='struct_foo' id='struct_foo_1'>New User]</p>\n",
|
|
295
|
+
render("%p[foo[0]] New User]", :locals => {:foo => foo}))
|
|
296
|
+
assert_equal("<p class='prefix_struct_foo' id='prefix_struct_foo_1'>New User]</p>\n",
|
|
297
|
+
render("%p[foo[0], :prefix] New User]", :locals => {:foo => foo}))
|
|
126
298
|
end
|
|
127
299
|
|
|
128
300
|
def test_empty_attrs
|
|
@@ -135,61 +307,51 @@ class EngineTest < Test::Unit::TestCase
|
|
|
135
307
|
assert_equal("<p>nil</p>\n", render("%p{ :attr => x } nil", :locals => {:x => nil}))
|
|
136
308
|
end
|
|
137
309
|
|
|
138
|
-
def
|
|
139
|
-
assert_equal("<p>
|
|
310
|
+
def test_nil_id_with_syntactic_id
|
|
311
|
+
assert_equal("<p id='foo'>nil</p>\n", render("%p#foo{:id => nil} nil"))
|
|
312
|
+
assert_equal("<p id='foo_bar'>nil</p>\n", render("%p#foo{{:id => 'bar'}, :id => nil} nil"))
|
|
313
|
+
assert_equal("<p id='foo_bar'>nil</p>\n", render("%p#foo{{:id => nil}, :id => 'bar'} nil"))
|
|
140
314
|
end
|
|
141
315
|
|
|
142
|
-
def
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
assert_equal("<p>Paragraph!</p>\n", Haml::Engine.new("%p= text", :locals => { :text => "Paragraph!" }).render)
|
|
316
|
+
def test_nil_class_with_syntactic_class
|
|
317
|
+
assert_equal("<p class='foo'>nil</p>\n", render("%p.foo{:class => nil} nil"))
|
|
318
|
+
assert_equal("<p class='bar foo'>nil</p>\n", render("%p.bar.foo{:class => nil} nil"))
|
|
319
|
+
assert_equal("<p class='bar foo'>nil</p>\n", render("%p.foo{{:class => 'bar'}, :class => nil} nil"))
|
|
320
|
+
assert_equal("<p class='bar foo'>nil</p>\n", render("%p.foo{{:class => nil}, :class => 'bar'} nil"))
|
|
321
|
+
end
|
|
150
322
|
|
|
151
|
-
|
|
323
|
+
def test_locals
|
|
324
|
+
assert_equal("<p>Paragraph!</p>\n", render("%p= text", :locals => { :text => "Paragraph!" }))
|
|
152
325
|
end
|
|
153
326
|
|
|
154
327
|
def test_dynamic_attrs_shouldnt_register_as_literal_values
|
|
155
|
-
assert_equal("<p a='b2c'
|
|
156
|
-
assert_equal("<p a='b2c'
|
|
328
|
+
assert_equal("<p a='b2c'></p>\n", render('%p{:a => "b#{1 + 1}c"}'))
|
|
329
|
+
assert_equal("<p a='b2c'></p>\n", render("%p{:a => 'b' + (1 + 1).to_s + 'c'}"))
|
|
157
330
|
end
|
|
158
331
|
|
|
159
|
-
def
|
|
160
|
-
|
|
161
|
-
hash2 = {4=>5, 3=>{5=>2, 16=>12}}
|
|
162
|
-
hash3 = {1=>2, 4=>5, 3=>{5=>2, 8=>9, 16=>12}}
|
|
163
|
-
|
|
164
|
-
hash1.rec_merge!(hash2)
|
|
165
|
-
assert_equal(hash3, hash1)
|
|
332
|
+
def test_dynamic_attrs_with_self_closed_tag
|
|
333
|
+
assert_equal("<a b='2' />\nc\n", render("%a{'b' => 1 + 1}/\n= 'c'\n"))
|
|
166
334
|
end
|
|
167
335
|
|
|
168
|
-
def
|
|
169
|
-
|
|
170
|
-
"% a", "%p a\n b", "a\n%p=\nb", "%p=\n a",
|
|
171
|
-
"a\n%p~\nb", "a\n~\nb", "a\n~\n b", "%p~\n b", "%p/\n a",
|
|
172
|
-
"%p\n \t%a b", "%a\n b\nc", "%a\n b\nc",
|
|
173
|
-
":notafilter\n This isn't\n a filter!",
|
|
174
|
-
".{} a", "\#{} a", ".= 'foo'", "%a/ b", "%p..class", "%p..#." ]
|
|
175
|
-
errs.each do |err|
|
|
336
|
+
def test_exceptions
|
|
337
|
+
EXCEPTION_MAP.each do |key, value|
|
|
176
338
|
begin
|
|
177
|
-
render(
|
|
178
|
-
rescue Exception =>
|
|
179
|
-
|
|
339
|
+
render(key)
|
|
340
|
+
rescue Exception => err
|
|
341
|
+
value = [value] unless value.is_a?(Array)
|
|
342
|
+
|
|
343
|
+
assert_equal(value.first, err.message, "Line: #{key}")
|
|
344
|
+
assert_equal(value[1] || key.split("\n").length, err.backtrace[0].gsub('(haml):', '').to_i, "Line: #{key}")
|
|
180
345
|
else
|
|
181
|
-
assert(false, "#{
|
|
346
|
+
assert(false, "Exception not raised for\n#{key}")
|
|
182
347
|
end
|
|
183
348
|
end
|
|
184
349
|
end
|
|
185
350
|
|
|
186
|
-
def
|
|
351
|
+
def test_exception_line
|
|
187
352
|
render("a\nb\n!!!\n c\nd")
|
|
188
353
|
rescue Haml::SyntaxError => e
|
|
189
|
-
assert_equal(
|
|
190
|
-
assert_equal("(haml):3", e.backtrace[0])
|
|
191
|
-
rescue Exception => e
|
|
192
|
-
assert(false, '"a\nb\n!!!\n c\nd" doesn\'t produce a Haml::SyntaxError')
|
|
354
|
+
assert_equal("(haml):4", e.backtrace[0])
|
|
193
355
|
else
|
|
194
356
|
assert(false, '"a\nb\n!!!\n c\nd" doesn\'t produce an exception')
|
|
195
357
|
end
|
|
@@ -218,6 +380,11 @@ class EngineTest < Test::Unit::TestCase
|
|
|
218
380
|
assert_equal("Unbalanced brackets.", e.message)
|
|
219
381
|
end
|
|
220
382
|
|
|
383
|
+
def test_balanced_conditional_comments
|
|
384
|
+
assert_equal("<!--[if !(IE 6)|(IE 7)]> Bracket: ] <![endif]-->\n",
|
|
385
|
+
render("/[if !(IE 6)|(IE 7)] Bracket: ]"))
|
|
386
|
+
end
|
|
387
|
+
|
|
221
388
|
def test_no_bluecloth
|
|
222
389
|
Kernel.module_eval do
|
|
223
390
|
def gem_original_require_with_bluecloth(file)
|
|
@@ -231,7 +398,7 @@ class EngineTest < Test::Unit::TestCase
|
|
|
231
398
|
begin
|
|
232
399
|
assert_equal("<h1>Foo</h1>\t<p>- a\n- b</p>\n",
|
|
233
400
|
Haml::Engine.new(":markdown\n Foo\n ===\n - a\n - b").to_html)
|
|
234
|
-
rescue Haml::
|
|
401
|
+
rescue Haml::Error => e
|
|
235
402
|
if e.message == "Can't run Markdown filter; required 'bluecloth' or 'redcloth', but none were found"
|
|
236
403
|
puts "\nCouldn't require 'bluecloth' or 'redcloth'; skipping a test."
|
|
237
404
|
else
|
|
@@ -256,7 +423,7 @@ class EngineTest < Test::Unit::TestCase
|
|
|
256
423
|
|
|
257
424
|
begin
|
|
258
425
|
Haml::Engine.new(":redcloth\n _foo_").to_html
|
|
259
|
-
rescue Haml::
|
|
426
|
+
rescue Haml::Error
|
|
260
427
|
else
|
|
261
428
|
assert(false, "No exception raised!")
|
|
262
429
|
end
|
|
@@ -278,7 +445,7 @@ class EngineTest < Test::Unit::TestCase
|
|
|
278
445
|
|
|
279
446
|
begin
|
|
280
447
|
Haml::Engine.new(":markdown\n _foo_").to_html
|
|
281
|
-
rescue Haml::
|
|
448
|
+
rescue Haml::Error
|
|
282
449
|
else
|
|
283
450
|
assert(false, "No exception raised!")
|
|
284
451
|
end
|
|
@@ -288,17 +455,33 @@ class EngineTest < Test::Unit::TestCase
|
|
|
288
455
|
end
|
|
289
456
|
end
|
|
290
457
|
|
|
458
|
+
def test_empty_filter
|
|
459
|
+
assert_equal(<<END, render(':javascript'))
|
|
460
|
+
<script type='text/javascript'>
|
|
461
|
+
//<![CDATA[
|
|
462
|
+
|
|
463
|
+
//]]>
|
|
464
|
+
</script>
|
|
465
|
+
END
|
|
466
|
+
end
|
|
467
|
+
|
|
291
468
|
def test_local_assigns_dont_modify_class
|
|
292
469
|
assert_equal("bar\n", render("= foo", :locals => {:foo => 'bar'}))
|
|
293
470
|
assert_equal(nil, defined?(foo))
|
|
294
471
|
end
|
|
295
472
|
|
|
296
473
|
def test_object_ref_with_nil_id
|
|
297
|
-
user =
|
|
474
|
+
user = User.new
|
|
298
475
|
assert_equal("<p class='struct_user' id='struct_user_new'>New User</p>\n",
|
|
299
476
|
render("%p[user] New User", :locals => {:user => user}))
|
|
300
477
|
end
|
|
301
478
|
|
|
479
|
+
def test_object_ref_before_attrs
|
|
480
|
+
user = User.new 42
|
|
481
|
+
assert_equal("<p class='struct_user' id='struct_user_42' style='width: 100px;'>New User</p>\n",
|
|
482
|
+
render("%p[user]{:style => 'width: 100px;'} New User", :locals => {:user => user}))
|
|
483
|
+
end
|
|
484
|
+
|
|
302
485
|
def test_non_literal_attributes
|
|
303
486
|
assert_equal("<p a1='foo' a2='bar' a3='baz' />\n",
|
|
304
487
|
render("%p{a2, a1, :a3 => 'baz'}/",
|
|
@@ -346,4 +529,58 @@ class EngineTest < Test::Unit::TestCase
|
|
|
346
529
|
def test_render_proc_with_binding
|
|
347
530
|
assert_equal("FOO\n", Haml::Engine.new("= upcase").render_proc("foo".instance_eval{binding}).call)
|
|
348
531
|
end
|
|
532
|
+
|
|
533
|
+
def test_ugly_true
|
|
534
|
+
assert_equal("<div id='outer'>\n<div id='inner'>\n<p>hello world</p>\n</div>\n</div>\n",
|
|
535
|
+
render("#outer\n #inner\n %p hello world", :ugly => true))
|
|
536
|
+
|
|
537
|
+
assert_equal("<p>#{'s' * 75}</p>\n",
|
|
538
|
+
render("%p #{'s' * 75}", :ugly => true))
|
|
539
|
+
|
|
540
|
+
assert_equal("<p>#{'s' * 75}</p>\n",
|
|
541
|
+
render("%p= 's' * 75", :ugly => true))
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
def test_xhtml_output_option
|
|
545
|
+
assert_equal "<p>\n <br />\n</p>\n", render("%p\n %br", :format => :xhtml)
|
|
546
|
+
assert_equal "<a />\n", render("%a/", :format => :xhtml)
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
def test_arbitrary_output_option
|
|
550
|
+
assert_raise(Haml::Error, "Invalid output format :html1") { Haml::Engine.new("%br", :format => :html1) }
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
# HTML 4.0
|
|
554
|
+
|
|
555
|
+
def test_html_has_no_self_closing_tags
|
|
556
|
+
assert_equal "<p>\n <br>\n</p>\n", render("%p\n %br", :format => :html4)
|
|
557
|
+
assert_equal "<br>\n", render("%br/", :format => :html4)
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
def test_html_renders_empty_node_with_closing_tag
|
|
561
|
+
assert_equal "<div class='foo'></div>\n", render(".foo", :format => :html4)
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
def test_html_ignores_explicit_self_closing_declaration
|
|
565
|
+
assert_equal "<a></a>\n", render("%a/", :format => :html4)
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
def test_html_ignores_xml_prolog_declaration
|
|
569
|
+
assert_equal "", render('!!! XML', :format => :html4)
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
def test_html_has_different_doctype
|
|
573
|
+
assert_equal %{<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n},
|
|
574
|
+
render('!!!', :format => :html4)
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
# because anything before the doctype triggers quirks mode in IE
|
|
578
|
+
def test_xml_prolog_and_doctype_dont_result_in_a_leading_whitespace_in_html
|
|
579
|
+
assert_no_match /^\s+/, render("!!! xml\n!!!", :format => :html4)
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
# HTML5
|
|
583
|
+
def test_html5_doctype
|
|
584
|
+
assert_equal %{<!DOCTYPE html>\n}, render('!!!', :format => :html5)
|
|
585
|
+
end
|
|
349
586
|
end
|
data/test/haml/helper_test.rb
CHANGED
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
require 'rubygems'
|
|
4
|
-
require 'active_support'
|
|
5
|
-
require 'action_controller'
|
|
6
|
-
require 'action_view'
|
|
7
|
-
|
|
8
|
-
require 'test/unit'
|
|
9
|
-
require File.dirname(__FILE__) + '/../../lib/haml'
|
|
2
|
+
require File.dirname(__FILE__) + '/test_helper'
|
|
10
3
|
require 'haml/template'
|
|
11
4
|
|
|
12
5
|
class HelperTest < Test::Unit::TestCase
|
|
13
6
|
include Haml::Helpers
|
|
7
|
+
Post = Struct.new('Post', :body)
|
|
14
8
|
|
|
15
9
|
def setup
|
|
16
10
|
@base = ActionView::Base.new
|
|
17
11
|
@base.controller = ActionController::Base.new
|
|
12
|
+
@base.instance_variable_set('@post', Post.new("Foo bar\nbaz"))
|
|
18
13
|
end
|
|
19
14
|
|
|
20
15
|
def render(text, options = {})
|
|
@@ -27,14 +22,14 @@ class HelperTest < Test::Unit::TestCase
|
|
|
27
22
|
end
|
|
28
23
|
|
|
29
24
|
def test_flatten
|
|
30
|
-
assert_equal(
|
|
25
|
+
assert_equal("FooBar", flatten("FooBar"))
|
|
31
26
|
|
|
32
|
-
assert_equal(flatten("Foo\rBar")
|
|
27
|
+
assert_equal("FooBar", flatten("Foo\rBar"))
|
|
33
28
|
|
|
34
|
-
assert_equal(
|
|
29
|
+
assert_equal("Foo
Bar", flatten("Foo\nBar"))
|
|
35
30
|
|
|
36
|
-
assert_equal(
|
|
37
|
-
|
|
31
|
+
assert_equal("Hello
World!
YOU ARE FLAT?
OMGZ!",
|
|
32
|
+
flatten("Hello\nWorld!\nYOU ARE \rFLAT?\n\rOMGZ!"))
|
|
38
33
|
end
|
|
39
34
|
|
|
40
35
|
def test_list_of_should_render_correctly
|
|
@@ -85,10 +80,33 @@ class HelperTest < Test::Unit::TestCase
|
|
|
85
80
|
should_be = "<form action=\"foo\" method=\"post\">\n <p>bar</p>\n <strong>baz</strong>\n</form>\n"
|
|
86
81
|
assert_equal(should_be, result)
|
|
87
82
|
end
|
|
83
|
+
|
|
84
|
+
def test_text_area
|
|
85
|
+
assert_equal(%(<textarea id="body" name="body">Foo
Bar
 Baz
 Boom</textarea>\n),
|
|
86
|
+
render('= text_area_tag "body", "Foo\nBar\n Baz\n Boom"', :action_view))
|
|
87
|
+
|
|
88
|
+
assert_equal(%(<textarea cols="40" id="post_body" name="post[body]" rows="20">Foo bar
baz</textarea>\n),
|
|
89
|
+
render('= text_area :post, :body', :action_view))
|
|
90
|
+
|
|
91
|
+
assert_equal(%(<pre>Foo bar
 baz</pre>\n),
|
|
92
|
+
render('= content_tag "pre", "Foo bar\n baz"', :action_view))
|
|
93
|
+
end
|
|
88
94
|
|
|
89
95
|
def test_capture_haml
|
|
90
96
|
assert_equal("\"<p>13</p>\\n\"\n", render("- foo = capture_haml(13) do |a|\n %p= a\n= foo.dump"))
|
|
91
97
|
end
|
|
98
|
+
|
|
99
|
+
def test_haml_tag_attribute_html_escaping
|
|
100
|
+
assert_equal("<p id='foo&bar'>baz</p>\n", render("%p{:id => 'foo&bar'} baz", :escape_html => true))
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def test_haml_tag_autoclosed_tags_are_closed
|
|
104
|
+
assert_equal("<br class='foo' />\n", render("- haml_tag :br, :class => 'foo'"))
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def test_haml_tag_non_autoclosed_tags_arent_closed
|
|
108
|
+
assert_equal("<p>\n</p>\n", render("- haml_tag :p"))
|
|
109
|
+
end
|
|
92
110
|
|
|
93
111
|
def test_is_haml
|
|
94
112
|
assert(!ActionView::Base.new.is_haml?)
|
|
@@ -123,12 +141,12 @@ class HelperTest < Test::Unit::TestCase
|
|
|
123
141
|
end
|
|
124
142
|
|
|
125
143
|
def test_find_and_preserve_with_block
|
|
126
|
-
assert_equal("<pre
|
|
144
|
+
assert_equal("<pre>Foo
Bar</pre>\nFoo\nBar\n",
|
|
127
145
|
render("= find_and_preserve do\n %pre\n Foo\n Bar\n Foo\n Bar"))
|
|
128
146
|
end
|
|
129
147
|
|
|
130
148
|
def test_preserve_with_block
|
|
131
|
-
assert_equal("<pre
|
|
149
|
+
assert_equal("<pre>Foo
Bar</pre>
Foo
Bar\n",
|
|
132
150
|
render("= preserve do\n %pre\n Foo\n Bar\n Foo\n Bar"))
|
|
133
151
|
end
|
|
134
152
|
|
|
@@ -140,12 +158,30 @@ class HelperTest < Test::Unit::TestCase
|
|
|
140
158
|
context.init_haml_helpers
|
|
141
159
|
|
|
142
160
|
result = context.capture_haml do
|
|
143
|
-
context.
|
|
161
|
+
context.haml_tag :p, :attr => "val" do
|
|
144
162
|
context.puts "Blah"
|
|
145
163
|
end
|
|
146
164
|
end
|
|
147
165
|
|
|
148
166
|
assert_equal("<p attr='val'>\n Blah\n</p>\n", result)
|
|
149
167
|
end
|
|
168
|
+
|
|
169
|
+
def test_non_haml
|
|
170
|
+
assert_equal("false\n", render("= non_haml { is_haml? }"))
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
class ActsLikeTag
|
|
174
|
+
# We want to be able to have people include monkeypatched ActionView helpers
|
|
175
|
+
# without redefining is_haml?.
|
|
176
|
+
# This is accomplished via Object#is_haml?, and this is a test for it.
|
|
177
|
+
include ActionView::Helpers::TagHelper
|
|
178
|
+
def to_s
|
|
179
|
+
content_tag :p, 'some tag content'
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def test_random_class_includes_tag_helper
|
|
184
|
+
assert_equal "<p>some tag content</p>", ActsLikeTag.new.to_s
|
|
185
|
+
end
|
|
150
186
|
end
|
|
151
187
|
|