haml 4.0.0 → 5.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.
- checksums.yaml +7 -0
- data/.yardopts +1 -1
- data/CHANGELOG.md +117 -5
- data/FAQ.md +7 -17
- data/MIT-LICENSE +1 -1
- data/README.md +85 -42
- data/REFERENCE.md +181 -86
- data/Rakefile +47 -51
- data/lib/haml/attribute_builder.rb +163 -0
- data/lib/haml/attribute_compiler.rb +215 -0
- data/lib/haml/attribute_parser.rb +144 -0
- data/lib/haml/buffer.rb +38 -128
- data/lib/haml/compiler.rb +88 -295
- data/lib/haml/engine.rb +25 -41
- data/lib/haml/error.rb +3 -0
- data/lib/haml/escapable.rb +49 -0
- data/lib/haml/exec.rb +33 -19
- data/lib/haml/filters.rb +20 -24
- data/lib/haml/generator.rb +41 -0
- data/lib/haml/helpers/action_view_extensions.rb +3 -2
- data/lib/haml/helpers/action_view_mods.rb +44 -66
- data/lib/haml/helpers/action_view_xss_mods.rb +1 -0
- data/lib/haml/helpers/safe_erubi_template.rb +27 -0
- data/lib/haml/helpers/safe_erubis_template.rb +16 -4
- data/lib/haml/helpers/xss_mods.rb +18 -12
- data/lib/haml/helpers.rb +122 -58
- data/lib/haml/options.rb +39 -46
- data/lib/haml/parser.rb +278 -217
- data/lib/haml/{template/plugin.rb → plugin.rb} +8 -15
- data/lib/haml/railtie.rb +21 -11
- data/lib/haml/sass_rails_filter.rb +17 -4
- data/lib/haml/template/options.rb +12 -2
- data/lib/haml/template.rb +12 -6
- data/lib/haml/temple_engine.rb +120 -0
- data/lib/haml/temple_line_counter.rb +29 -0
- data/lib/haml/util.rb +80 -199
- data/lib/haml/version.rb +2 -1
- data/lib/haml.rb +2 -1
- data/test/attribute_parser_test.rb +101 -0
- data/test/engine_test.rb +306 -176
- data/test/filters_test.rb +32 -19
- data/test/gemfiles/Gemfile.rails-4.0.x +11 -0
- data/test/gemfiles/Gemfile.rails-4.0.x.lock +87 -0
- data/test/gemfiles/Gemfile.rails-4.1.x +5 -0
- data/test/gemfiles/Gemfile.rails-4.2.x +5 -0
- data/test/gemfiles/Gemfile.rails-5.0.x +4 -0
- data/test/helper_test.rb +282 -96
- data/test/options_test.rb +22 -0
- data/test/parser_test.rb +71 -4
- data/test/results/bemit.xhtml +4 -0
- data/test/results/eval_suppressed.xhtml +4 -4
- data/test/results/helpers.xhtml +43 -41
- data/test/results/helpful.xhtml +6 -3
- data/test/results/just_stuff.xhtml +21 -20
- data/test/results/list.xhtml +9 -9
- data/test/results/nuke_inner_whitespace.xhtml +22 -22
- data/test/results/nuke_outer_whitespace.xhtml +84 -92
- data/test/results/original_engine.xhtml +17 -17
- data/test/results/partial_layout.xhtml +4 -3
- data/test/results/partial_layout_erb.xhtml +4 -3
- data/test/results/partials.xhtml +11 -10
- data/test/results/silent_script.xhtml +63 -63
- data/test/results/standard.xhtml +156 -159
- data/test/results/tag_parsing.xhtml +19 -19
- data/test/results/very_basic.xhtml +2 -2
- data/test/results/whitespace_handling.xhtml +56 -50
- data/test/template_test.rb +44 -53
- data/test/template_test_helper.rb +38 -0
- data/test/templates/_text_area_helper.html.haml +4 -0
- data/test/templates/bemit.haml +3 -0
- data/test/templates/just_stuff.haml +1 -0
- data/test/templates/partial_layout_erb.erb +1 -1
- data/test/templates/standard_ugly.haml +1 -0
- data/test/templates/with_bom.haml +1 -0
- data/test/temple_line_counter_test.rb +40 -0
- data/test/test_helper.rb +26 -12
- data/test/util_test.rb +6 -47
- metadata +88 -106
- data/lib/haml/helpers/rails_323_textarea_fix.rb +0 -24
- data/test/gemfiles/Gemfile.rails-3.0.x +0 -5
- data/test/gemfiles/Gemfile.rails-3.1.x +0 -6
- data/test/gemfiles/Gemfile.rails-3.2.x +0 -5
- data/test/gemfiles/Gemfile.rails-master +0 -4
- data/test/templates/_av_partial_1_ugly.haml +0 -9
- data/test/templates/_av_partial_2_ugly.haml +0 -5
- data/test/templates/action_view_ugly.haml +0 -47
- data/test/templates/standard_ugly.haml +0 -43
data/test/helper_test.rb
CHANGED
@@ -1,22 +1,13 @@
|
|
1
1
|
require 'test_helper'
|
2
|
+
require "active_model/naming"
|
2
3
|
|
3
|
-
class
|
4
|
-
|
5
|
-
content_tag(:span) {content_tag(:div) {"something"}}
|
6
|
-
end
|
7
|
-
|
8
|
-
def wacky_form
|
9
|
-
form_tag("/foo") {"bar"}
|
10
|
-
end
|
4
|
+
class FormModel
|
5
|
+
extend ActiveModel::Naming
|
11
6
|
end
|
12
7
|
|
13
|
-
|
14
|
-
|
15
|
-
haml_concat('foo').to_s
|
16
|
-
end
|
17
|
-
end
|
8
|
+
class HelperTest < Haml::TestCase
|
9
|
+
TEXT_AREA_CONTENT_REGEX = /<(textarea)[^>]*>\n(.*?)<\/\1>/im
|
18
10
|
|
19
|
-
class HelperTest < MiniTest::Unit::TestCase
|
20
11
|
Post = Struct.new('Post', :body, :error_field, :errors)
|
21
12
|
class PostErrors
|
22
13
|
def on(name)
|
@@ -31,15 +22,18 @@ class HelperTest < MiniTest::Unit::TestCase
|
|
31
22
|
end
|
32
23
|
|
33
24
|
def setup
|
34
|
-
@base = ActionView::Base
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
# This is needed for >=3.0.0
|
39
|
-
@base.controller.response = ActionController::Response.new
|
40
|
-
end
|
25
|
+
@base = Class.new(ActionView::Base) {
|
26
|
+
def nested_tag
|
27
|
+
content_tag(:span) {content_tag(:div) {"something"}}
|
28
|
+
end
|
41
29
|
|
42
|
-
|
30
|
+
def wacky_form
|
31
|
+
form_tag("/foo") {"bar"}
|
32
|
+
end
|
33
|
+
}.new
|
34
|
+
@base.controller = ActionController::Base.new
|
35
|
+
@base.view_paths << File.expand_path("../templates", __FILE__)
|
36
|
+
@base.instance_variable_set(:@post, Post.new("Foo bar\nbaz", nil, PostErrors.new))
|
43
37
|
end
|
44
38
|
|
45
39
|
def render(text, options = {})
|
@@ -47,6 +41,32 @@ class HelperTest < MiniTest::Unit::TestCase
|
|
47
41
|
super
|
48
42
|
end
|
49
43
|
|
44
|
+
def test_rendering_with_escapes
|
45
|
+
def @base.render_something_with_haml_concat
|
46
|
+
haml_concat "<p>"
|
47
|
+
end
|
48
|
+
def @base.render_something_with_haml_tag_and_concat
|
49
|
+
haml_tag 'p' do
|
50
|
+
haml_concat '<foo>'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
output = render(<<-HAML, :action_view)
|
55
|
+
- render_something_with_haml_concat
|
56
|
+
- render_something_with_haml_tag_and_concat
|
57
|
+
- render_something_with_haml_concat
|
58
|
+
HAML
|
59
|
+
assert_equal("<p>\n<p>\n <foo>\n</p>\n<p>\n", output)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_with_raw_haml_concat
|
63
|
+
haml = <<HAML
|
64
|
+
- with_raw_haml_concat do
|
65
|
+
- haml_concat "<>&"
|
66
|
+
HAML
|
67
|
+
assert_equal("<>&\n", render(haml, :action_view))
|
68
|
+
end
|
69
|
+
|
50
70
|
def test_flatten
|
51
71
|
assert_equal("FooBar", Haml::Helpers.flatten("FooBar"))
|
52
72
|
|
@@ -59,13 +79,13 @@ class HelperTest < MiniTest::Unit::TestCase
|
|
59
79
|
end
|
60
80
|
|
61
81
|
def test_list_of_should_render_correctly
|
62
|
-
assert_equal("<li>1</li>\n<li>2</li
|
63
|
-
assert_equal("<li>[1]</li
|
64
|
-
assert_equal("<li>\n <h1>Fee</h1>\n <p>A word!</p>\n</li>\n<li>\n <h1>Fi</h1>\n <p>A word!</p>\n</li>\n<li>\n <h1>Fo</h1>\n <p>A word!</p>\n</li>\n<li>\n <h1>Fum</h1>\n <p>A word!</p>\n</li
|
82
|
+
assert_equal("<li>1</li>\n<li>2</li>", render("= list_of([1, 2]) do |i|\n = i"))
|
83
|
+
assert_equal("<li>[1]</li>", render("= list_of([[1]]) do |i|\n = i.inspect"))
|
84
|
+
assert_equal("<li>\n <h1>Fee</h1>\n <p>A word!</p>\n</li>\n<li>\n <h1>Fi</h1>\n <p>A word!</p>\n</li>\n<li>\n <h1>Fo</h1>\n <p>A word!</p>\n</li>\n<li>\n <h1>Fum</h1>\n <p>A word!</p>\n</li>",
|
65
85
|
render("= list_of(['Fee', 'Fi', 'Fo', 'Fum']) do |title|\n %h1= title\n %p A word!"))
|
66
|
-
assert_equal("<li c='3'>1</li>\n<li c='3'>2</li
|
67
|
-
assert_equal("<li c='3'>[1]</li
|
68
|
-
assert_equal("<li c='3'>\n <h1>Fee</h1>\n <p>A word!</p>\n</li>\n<li c='3'>\n <h1>Fi</h1>\n <p>A word!</p>\n</li>\n<li c='3'>\n <h1>Fo</h1>\n <p>A word!</p>\n</li>\n<li c='3'>\n <h1>Fum</h1>\n <p>A word!</p>\n</li
|
86
|
+
assert_equal("<li c='3'>1</li>\n<li c='3'>2</li>", render("= list_of([1, 2], {:c => 3}) do |i|\n = i"))
|
87
|
+
assert_equal("<li c='3'>[1]</li>", render("= list_of([[1]], {:c => 3}) do |i|\n = i.inspect"))
|
88
|
+
assert_equal("<li c='3'>\n <h1>Fee</h1>\n <p>A word!</p>\n</li>\n<li c='3'>\n <h1>Fi</h1>\n <p>A word!</p>\n</li>\n<li c='3'>\n <h1>Fo</h1>\n <p>A word!</p>\n</li>\n<li c='3'>\n <h1>Fum</h1>\n <p>A word!</p>\n</li>",
|
69
89
|
render("= list_of(['Fee', 'Fi', 'Fo', 'Fum'], {:c => 3}) do |title|\n %h1= title\n %p A word!"))
|
70
90
|
end
|
71
91
|
|
@@ -75,15 +95,15 @@ class HelperTest < MiniTest::Unit::TestCase
|
|
75
95
|
end
|
76
96
|
|
77
97
|
def test_tabs
|
78
|
-
assert_equal("foo\
|
79
|
-
assert_equal("
|
98
|
+
assert_equal("foo\nbar\nbaz\n", render("foo\n- tab_up\nbar\n- tab_down\nbaz"))
|
99
|
+
assert_equal("<p>tabbed</p>\n", render("- buffer.tabulation=5\n%p tabbed"))
|
80
100
|
end
|
81
101
|
|
82
102
|
def test_with_tabs
|
83
103
|
assert_equal(<<HTML, render(<<HAML))
|
84
104
|
Foo
|
85
|
-
|
86
|
-
|
105
|
+
Bar
|
106
|
+
Baz
|
87
107
|
Baz
|
88
108
|
HTML
|
89
109
|
Foo
|
@@ -100,7 +120,7 @@ HAML
|
|
100
120
|
|
101
121
|
begin
|
102
122
|
ActionView::Base.new.render(:inline => "<%= flatten('Foo\\nBar') %>")
|
103
|
-
rescue NoMethodError,
|
123
|
+
rescue NoMethodError, ActionView::Template::Error
|
104
124
|
proper_behavior = true
|
105
125
|
end
|
106
126
|
assert(proper_behavior)
|
@@ -118,53 +138,67 @@ HAML
|
|
118
138
|
end
|
119
139
|
|
120
140
|
def test_form_tag
|
121
|
-
# This is usually provided by ActionController::Base.
|
122
141
|
def @base.protect_against_forgery?; false; end
|
123
|
-
|
124
|
-
<form accept-charset="UTF-8" action="foo" method="post">#{rails_form_opener}
|
125
|
-
<p>bar</p>
|
126
|
-
<strong>baz</strong>
|
127
|
-
</form>
|
128
|
-
HTML
|
142
|
+
rendered = render(<<HAML, :action_view)
|
129
143
|
= form_tag 'foo' do
|
130
|
-
|
131
|
-
|
144
|
+
%p bar
|
145
|
+
%strong baz
|
132
146
|
HAML
|
147
|
+
fragment = Nokogiri::HTML.fragment(rendered)
|
148
|
+
assert_equal 'foo', fragment.css('form').first.attributes['action'].to_s
|
149
|
+
assert_equal 'bar', fragment.css('form p').first.text.strip
|
150
|
+
assert_equal 'baz', fragment.css('form strong').first.text.strip
|
133
151
|
end
|
134
152
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
153
|
+
def test_form_for
|
154
|
+
# FIXME: current HAML doesn't do proper indentation with form_for (it's the capture { output } in #form_for).
|
155
|
+
def @base.protect_against_forgery?; false; end
|
156
|
+
rendered = render(<<HAML, :action_view)
|
157
|
+
= form_for OpenStruct.new, url: 'foo', as: :post do |f|
|
158
|
+
= f.text_field :name
|
159
|
+
HAML
|
160
|
+
assert_match(/<(form|div)[^>]+><input/, rendered)
|
161
|
+
end
|
139
162
|
|
140
|
-
|
141
|
-
|
163
|
+
def test_pre
|
164
|
+
assert_equal(%(<pre>Foo bar
 baz</pre>\n),
|
165
|
+
render('= content_tag "pre", "Foo bar\n baz"', :action_view))
|
166
|
+
end
|
142
167
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
assert_equal(%(<textarea id="body" name="body">\nFoo
Bar
 Baz
 Boom</textarea>\n),
|
149
|
-
render('= text_area_tag "body", "Foo\nBar\n Baz\n Boom"', :action_view))
|
168
|
+
def test_text_area_tag
|
169
|
+
output = render('= text_area_tag "body", "Foo\nBar\n Baz\n Boom"', :action_view)
|
170
|
+
match_data = output.match(TEXT_AREA_CONTENT_REGEX)
|
171
|
+
assert_equal "Foo
Bar
 Baz
 Boom", match_data[2]
|
172
|
+
end
|
150
173
|
|
151
|
-
|
152
|
-
|
174
|
+
def test_text_area
|
175
|
+
output = render('= text_area :post, :body', :action_view)
|
176
|
+
match_data = output.match(TEXT_AREA_CONTENT_REGEX)
|
177
|
+
assert_equal "Foo bar
baz", match_data[2]
|
178
|
+
end
|
153
179
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
180
|
+
def test_partials_should_not_cause_textareas_to_be_indented
|
181
|
+
# non-indentation of textareas rendered inside partials
|
182
|
+
@base.instance_variable_set(:@post, Post.new("Foo", nil, PostErrors.new))
|
183
|
+
output = render(".foo\n .bar\n = render '/text_area_helper'", :action_view)
|
184
|
+
match_data = output.match(TEXT_AREA_CONTENT_REGEX)
|
185
|
+
assert_equal 'Foo', match_data[2]
|
186
|
+
end
|
161
187
|
|
162
|
-
|
163
|
-
|
188
|
+
def test_textareas_should_preserve_leading_whitespace
|
189
|
+
# leading whitespace preservation
|
190
|
+
@base.instance_variable_set(:@post, Post.new(" Foo", nil, PostErrors.new))
|
191
|
+
output = render(".foo\n = text_area :post, :body", :action_view)
|
192
|
+
match_data = output.match(TEXT_AREA_CONTENT_REGEX)
|
193
|
+
assert_equal '  Foo', match_data[2]
|
194
|
+
end
|
164
195
|
|
165
|
-
|
166
|
-
|
167
|
-
|
196
|
+
def test_textareas_should_preserve_leading_whitespace_in_partials
|
197
|
+
# leading whitespace in textareas rendered inside partials
|
198
|
+
@base.instance_variable_set(:@post, Post.new(" Foo", nil, PostErrors.new))
|
199
|
+
output = render(".foo\n .bar\n = render '/text_area_helper'", :action_view)
|
200
|
+
match_data = output.match(TEXT_AREA_CONTENT_REGEX)
|
201
|
+
assert_equal '  Foo', match_data[2]
|
168
202
|
end
|
169
203
|
|
170
204
|
def test_capture_haml
|
@@ -202,11 +236,10 @@ HAML
|
|
202
236
|
|
203
237
|
def test_form_tag_in_helper_with_string_block
|
204
238
|
def @base.protect_against_forgery?; false; end
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
HAML
|
239
|
+
rendered = render('= wacky_form', :action_view)
|
240
|
+
fragment = Nokogiri::HTML.fragment(rendered)
|
241
|
+
assert_equal 'bar', fragment.text.strip
|
242
|
+
assert_equal '/foo', fragment.css('form').first.attributes['action'].to_s
|
210
243
|
end
|
211
244
|
|
212
245
|
def test_haml_tag_name_attribute_with_id
|
@@ -265,8 +298,12 @@ HAML
|
|
265
298
|
assert_equal("<p id='foo&bar'>baz</p>\n", render("%p{:id => 'foo&bar'} baz", :escape_html => true))
|
266
299
|
end
|
267
300
|
|
268
|
-
def
|
269
|
-
assert_equal("<br class='foo' />\n", render("- haml_tag :br, :class => 'foo'"))
|
301
|
+
def test_haml_tag_autoclosed_tags_are_closed_xhtml
|
302
|
+
assert_equal("<br class='foo' />\n", render("- haml_tag :br, :class => 'foo'", :format => :xhtml))
|
303
|
+
end
|
304
|
+
|
305
|
+
def test_haml_tag_autoclosed_tags_are_closed_html
|
306
|
+
assert_equal("<br class='foo'>\n", render("- haml_tag :br, :class => 'foo'", :format => :html5))
|
270
307
|
end
|
271
308
|
|
272
309
|
def test_haml_tag_with_class_array
|
@@ -297,7 +334,8 @@ HAML
|
|
297
334
|
end
|
298
335
|
|
299
336
|
def test_haml_tag_flags
|
300
|
-
assert_equal("<p />\n", render("- haml_tag :p, :/"))
|
337
|
+
assert_equal("<p />\n", render("- haml_tag :p, :/", :format => :xhtml))
|
338
|
+
assert_equal("<p>\n", render("- haml_tag :p, :/", :format => :html5))
|
301
339
|
assert_equal("<p>kumquat</p>\n", render("- haml_tag :p, :< do\n kumquat"))
|
302
340
|
|
303
341
|
assert_raises(Haml::Error) { render("- haml_tag :p, 'foo', :/") }
|
@@ -320,12 +358,19 @@ HTML
|
|
320
358
|
HAML
|
321
359
|
end
|
322
360
|
|
361
|
+
def test_haml_concat_inside_haml_tag_escaped_with_xss
|
362
|
+
assert_equal("<p>\n <>&\n</p>\n", render(<<HAML, :action_view))
|
363
|
+
- haml_tag :p do
|
364
|
+
- haml_concat "<>&"
|
365
|
+
HAML
|
366
|
+
end
|
367
|
+
|
323
368
|
def test_haml_concat_with_multiline_string
|
324
369
|
assert_equal(<<HTML, render(<<HAML))
|
325
370
|
<p>
|
326
|
-
|
327
|
-
|
328
|
-
|
371
|
+
foo
|
372
|
+
bar
|
373
|
+
baz
|
329
374
|
</p>
|
330
375
|
HTML
|
331
376
|
%p
|
@@ -333,10 +378,10 @@ HTML
|
|
333
378
|
HAML
|
334
379
|
end
|
335
380
|
|
336
|
-
def
|
337
|
-
assert_equal(<<HTML, render(<<HAML
|
381
|
+
def test_haml_tag
|
382
|
+
assert_equal(<<HTML, render(<<HAML))
|
338
383
|
<p>
|
339
|
-
<strong>Hi!</strong>
|
384
|
+
<strong>Hi!</strong>
|
340
385
|
</p>
|
341
386
|
HTML
|
342
387
|
- haml_tag :p do
|
@@ -344,6 +389,41 @@ HTML
|
|
344
389
|
HAML
|
345
390
|
end
|
346
391
|
|
392
|
+
def test_haml_tag_if_positive
|
393
|
+
assert_equal(<<HTML, render(<<HAML))
|
394
|
+
<div class='conditional'>
|
395
|
+
<p>A para</p>
|
396
|
+
</div>
|
397
|
+
HTML
|
398
|
+
- haml_tag_if true, '.conditional' do
|
399
|
+
%p A para
|
400
|
+
HAML
|
401
|
+
end
|
402
|
+
|
403
|
+
def test_haml_tag_if_positive_with_attributes
|
404
|
+
assert_equal(<<HTML, render(<<HAML))
|
405
|
+
<div class='conditional' foo='bar'>
|
406
|
+
<p>A para</p>
|
407
|
+
</div>
|
408
|
+
HTML
|
409
|
+
- haml_tag_if true, '.conditional', {:foo => 'bar'} do
|
410
|
+
%p A para
|
411
|
+
HAML
|
412
|
+
end
|
413
|
+
|
414
|
+
def test_haml_tag_if_negative
|
415
|
+
assert_equal(<<HTML, render(<<HAML))
|
416
|
+
<p>A para</p>
|
417
|
+
HTML
|
418
|
+
- haml_tag_if false, '.conditional' do
|
419
|
+
%p A para
|
420
|
+
HAML
|
421
|
+
end
|
422
|
+
|
423
|
+
def test_haml_tag_if_error_return
|
424
|
+
assert_raises(Haml::Error) { render("= haml_tag_if false, '.conditional' do\n %p Hello") }
|
425
|
+
end
|
426
|
+
|
347
427
|
def test_is_haml
|
348
428
|
assert(!ActionView::Base.new.is_haml?)
|
349
429
|
assert_equal("true\n", render("= is_haml?"))
|
@@ -365,21 +445,72 @@ HAML
|
|
365
445
|
end
|
366
446
|
|
367
447
|
def test_capture_deals_properly_with_collections
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
end
|
448
|
+
obj = Object.new
|
449
|
+
def obj.trc(collection, &block)
|
450
|
+
collection.each do |record|
|
451
|
+
haml_concat capture_haml(record, &block)
|
373
452
|
end
|
374
453
|
end
|
375
454
|
|
376
|
-
assert_equal("1\n\n2\n\n3\n\n", render("- trc([1, 2, 3]) do |i|\n = i.inspect"))
|
455
|
+
assert_equal("1\n\n2\n\n3\n\n", render("- trc([1, 2, 3]) do |i|\n = i.inspect", scope: obj))
|
377
456
|
end
|
378
457
|
|
379
458
|
def test_capture_with_string_block
|
380
459
|
assert_equal("foo\n", render("= capture { 'foo' }", :action_view))
|
381
460
|
end
|
382
461
|
|
462
|
+
def test_capture_with_non_string_value_reurns_nil
|
463
|
+
def @base.check_capture_returns_nil(&block)
|
464
|
+
contents = capture(&block)
|
465
|
+
|
466
|
+
contents << "ERROR" if contents
|
467
|
+
end
|
468
|
+
|
469
|
+
assert_equal("\n", render("= check_capture_returns_nil { 2 }", :action_view))
|
470
|
+
end
|
471
|
+
|
472
|
+
|
473
|
+
class HomemadeViewContext
|
474
|
+
include ActionView::Context
|
475
|
+
include ActionView::Helpers::FormHelper
|
476
|
+
|
477
|
+
def initialize
|
478
|
+
_prepare_context
|
479
|
+
end
|
480
|
+
|
481
|
+
def url_for(*)
|
482
|
+
"/"
|
483
|
+
end
|
484
|
+
|
485
|
+
def dom_class(*)
|
486
|
+
end
|
487
|
+
|
488
|
+
def dom_id(*)
|
489
|
+
end
|
490
|
+
|
491
|
+
def m # I have to inject the model into the view using an instance method, using locals doesn't work.
|
492
|
+
FormModel.new
|
493
|
+
end
|
494
|
+
|
495
|
+
def protect_against_forgery?
|
496
|
+
end
|
497
|
+
|
498
|
+
# def capture(*args, &block)
|
499
|
+
# capture_haml(*args, &block)
|
500
|
+
# end
|
501
|
+
end
|
502
|
+
|
503
|
+
def test_form_for_with_homemade_view_context
|
504
|
+
handler = ActionView::Template.handler_for_extension("haml")
|
505
|
+
template = ActionView::Template.new(<<HAML, "inline template", handler, {})
|
506
|
+
= form_for(m, :url => "/") do
|
507
|
+
%b Bold!
|
508
|
+
HAML
|
509
|
+
|
510
|
+
# see if Bold is within form tags:
|
511
|
+
assert_match(/<form.*>.*<b>Bold!<\/b>.*<\/form>/m, template.render(HomemadeViewContext.new, {}))
|
512
|
+
end
|
513
|
+
|
383
514
|
def test_find_and_preserve_with_block
|
384
515
|
assert_equal("<pre>Foo
Bar</pre>\nFoo\nBar\n",
|
385
516
|
render("= find_and_preserve do\n %pre\n Foo\n Bar\n Foo\n Bar"))
|
@@ -391,7 +522,7 @@ HAML
|
|
391
522
|
end
|
392
523
|
|
393
524
|
def test_preserve_with_block
|
394
|
-
assert_equal("<pre>Foo
Bar</pre>
Foo
Bar
|
525
|
+
assert_equal("<pre>Foo
Bar</pre>
Foo
Bar",
|
395
526
|
render("= preserve do\n %pre\n Foo\n Bar\n Foo\n Bar"))
|
396
527
|
end
|
397
528
|
|
@@ -428,17 +559,22 @@ MESSAGE
|
|
428
559
|
end
|
429
560
|
|
430
561
|
def test_error_return_line
|
431
|
-
render("%p foo\n= haml_concat
|
562
|
+
render("%p foo\n= haml_concat('foo').to_s\n%p bar")
|
432
563
|
assert false, "Expected Haml::Error"
|
433
564
|
rescue Haml::Error => e
|
434
|
-
assert_equal 2, e.backtrace[
|
565
|
+
assert_equal 2, e.backtrace[0].scan(/:(\d+)/).first.first.to_i
|
435
566
|
end
|
436
567
|
|
437
568
|
def test_error_return_line_in_helper
|
438
|
-
|
569
|
+
obj = Object.new
|
570
|
+
def obj.something_that_uses_haml_concat
|
571
|
+
haml_concat('foo').to_s
|
572
|
+
end
|
573
|
+
|
574
|
+
render("- something_that_uses_haml_concat", scope: obj)
|
439
575
|
assert false, "Expected Haml::Error"
|
440
576
|
rescue Haml::Error => e
|
441
|
-
assert_equal
|
577
|
+
assert_equal __LINE__ - 6, e.backtrace[0].scan(/:(\d+)/).first.first.to_i
|
442
578
|
end
|
443
579
|
|
444
580
|
class ActsLikeTag
|
@@ -474,6 +610,14 @@ HAML
|
|
474
610
|
assert_equal ""><&", Haml::Helpers.html_escape('"><&')
|
475
611
|
end
|
476
612
|
|
613
|
+
def test_html_escape_should_work_on_frozen_strings
|
614
|
+
begin
|
615
|
+
assert Haml::Helpers.html_escape('foo'.freeze)
|
616
|
+
rescue => e
|
617
|
+
flunk e.message
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
477
621
|
def test_html_escape_encoding
|
478
622
|
old_stderr, $stderr = $stderr, StringIO.new
|
479
623
|
string = "\"><&\u00e9" # if you're curious, u00e9 is "LATIN SMALL LETTER E WITH ACUTE"
|
@@ -483,6 +627,11 @@ HAML
|
|
483
627
|
$stderr = old_stderr
|
484
628
|
end
|
485
629
|
|
630
|
+
def test_html_escape_non_string
|
631
|
+
assert_equal('4.58', Haml::Helpers.html_escape(4.58))
|
632
|
+
assert_equal('4.58', Haml::Helpers.html_escape_without_haml_xss(4.58))
|
633
|
+
end
|
634
|
+
|
486
635
|
def test_escape_once
|
487
636
|
assert_equal ""><&", Haml::Helpers.escape_once('"><&')
|
488
637
|
end
|
@@ -493,7 +642,7 @@ HAML
|
|
493
642
|
|
494
643
|
def test_escape_once_leaves_numeric_references
|
495
644
|
assert_equal ""><&  ", Haml::Helpers.escape_once('"><&  ') #decimal
|
496
|
-
|
645
|
+
assert_equal ""><&  ", Haml::Helpers.escape_once('"><&  ') #hexadecimal
|
497
646
|
end
|
498
647
|
|
499
648
|
def test_escape_once_encoding
|
@@ -505,5 +654,42 @@ HAML
|
|
505
654
|
$stderr = old_stderr
|
506
655
|
end
|
507
656
|
|
508
|
-
|
657
|
+
def test_html_attrs_xhtml
|
658
|
+
assert_equal("<html lang='en-US' xml:lang='en-US' xmlns='http://www.w3.org/1999/xhtml'></html>\n",
|
659
|
+
render("%html{html_attrs}", :format => :xhtml))
|
660
|
+
end
|
509
661
|
|
662
|
+
def test_html_attrs_html4
|
663
|
+
assert_equal("<html lang='en-US'></html>\n",
|
664
|
+
render("%html{html_attrs}", :format => :html4))
|
665
|
+
end
|
666
|
+
|
667
|
+
def test_html_attrs_html5
|
668
|
+
assert_equal("<html lang='en-US'></html>\n",
|
669
|
+
render("%html{html_attrs}", :format => :html5))
|
670
|
+
end
|
671
|
+
|
672
|
+
def test_html_attrs_xhtml_other_lang
|
673
|
+
assert_equal("<html lang='es-AR' xml:lang='es-AR' xmlns='http://www.w3.org/1999/xhtml'></html>\n",
|
674
|
+
render("%html{html_attrs('es-AR')}", :format => :xhtml))
|
675
|
+
end
|
676
|
+
|
677
|
+
def test_html_attrs_html4_other_lang
|
678
|
+
assert_equal("<html lang='es-AR'></html>\n",
|
679
|
+
render("%html{html_attrs('es-AR')}", :format => :html4))
|
680
|
+
end
|
681
|
+
|
682
|
+
def test_html_attrs_html5_other_lang
|
683
|
+
assert_equal("<html lang='es-AR'></html>\n",
|
684
|
+
render("%html{html_attrs('es-AR')}", :format => :html5))
|
685
|
+
end
|
686
|
+
|
687
|
+
def test_escape_once_should_work_on_frozen_strings
|
688
|
+
begin
|
689
|
+
Haml::Helpers.escape_once('foo'.freeze)
|
690
|
+
rescue => e
|
691
|
+
flunk e.message
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Haml
|
4
|
+
class OptionsTest < Haml::TestCase
|
5
|
+
def test_buffer_defaults_have_only_buffer_option_keys
|
6
|
+
assert_equal(
|
7
|
+
Haml::Options.buffer_option_keys.sort,
|
8
|
+
Haml::Options.buffer_defaults.keys.sort,
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_buffer_defaults_values_are_the_same_as_rails_defaults
|
13
|
+
rails_defaults = Haml::Options.defaults.merge(Haml::Template.options)
|
14
|
+
Haml::Options.buffer_option_keys.each do |key|
|
15
|
+
assert_equal(
|
16
|
+
rails_defaults[key],
|
17
|
+
Haml::Options.buffer_defaults[key], "key: #{key}"
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/test/parser_test.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
module Haml
|
4
|
-
class ParserTest <
|
4
|
+
class ParserTest < Haml::TestCase
|
5
5
|
|
6
6
|
test "should raise error for 'else' at wrong indent level" do
|
7
7
|
begin
|
@@ -94,12 +94,79 @@ module Haml
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
+
test "revealed conditional comments are detected" do
|
98
|
+
text = "some revealed text"
|
99
|
+
cond = "[cond]"
|
100
|
+
|
101
|
+
node = parse("/!#{cond} #{text}").children[0]
|
102
|
+
|
103
|
+
assert_equal text, node.value[:text]
|
104
|
+
assert_equal cond, node.value[:conditional]
|
105
|
+
assert node.value[:revealed]
|
106
|
+
end
|
107
|
+
|
108
|
+
test "hidden conditional comments are detected" do
|
109
|
+
text = "some revealed text"
|
110
|
+
cond = "[cond]"
|
111
|
+
|
112
|
+
node = parse("/#{cond} #{text}").children[0]
|
113
|
+
|
114
|
+
assert_equal text, node.value[:text]
|
115
|
+
assert_equal cond, node.value[:conditional]
|
116
|
+
refute node.value[:revealed]
|
117
|
+
end
|
118
|
+
|
119
|
+
test "only script lines are checked for continuation keywords" do
|
120
|
+
haml = "- if true\n setup\n- else\n else\n"
|
121
|
+
node = parse(haml).children[0]
|
122
|
+
assert_equal(3, node.children.size)
|
123
|
+
end
|
124
|
+
|
125
|
+
# see #830. Strictly speaking the pipe here is not necessary, but there
|
126
|
+
# shouldn't be an error if it is there.
|
127
|
+
test "multiline Ruby with extra trailing pipe doesn't raise error" do
|
128
|
+
haml = "%p= foo bar, |\n baz"
|
129
|
+
begin
|
130
|
+
parse haml
|
131
|
+
rescue Haml::SyntaxError
|
132
|
+
flunk "Should not have raised SyntaxError"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
test "empty filter doesn't hide following lines" do
|
137
|
+
root = parse "%p\n :plain\n %p\n"
|
138
|
+
p_element = root.children[0]
|
139
|
+
assert_equal 2, p_element.children.size
|
140
|
+
assert_equal :filter, p_element.children[0].type
|
141
|
+
assert_equal :tag, p_element.children[1].type
|
142
|
+
end
|
143
|
+
|
144
|
+
# Previously blocks under a haml_comment would be rejected if any line was
|
145
|
+
# indented by a value that wasn't a multiple of the document indentation.
|
146
|
+
test "haml_comment accepts any indentation in content" do
|
147
|
+
begin
|
148
|
+
parse "-\#\n Indented two spaces\n Indented three spaces"
|
149
|
+
rescue Haml::SyntaxError
|
150
|
+
flunk "haml_comment should accept any combination of indentation"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
test "block haml_comment includes text" do
|
155
|
+
root = parse "-#\n Hello\n Hello\n"
|
156
|
+
assert_equal "Hello\n Hello\n", root.children[0].value[:text]
|
157
|
+
end
|
158
|
+
|
159
|
+
test "block haml_comment includes first line if present" do
|
160
|
+
root = parse "-# First line\n Hello\n Hello\n"
|
161
|
+
assert_equal " First line\nHello\n Hello\n", root.children[0].value[:text]
|
162
|
+
end
|
163
|
+
|
97
164
|
private
|
98
165
|
|
99
166
|
def parse(haml, options = nil)
|
100
167
|
options ||= Options.new
|
101
|
-
parser = Parser.new(
|
102
|
-
parser.
|
168
|
+
parser = Parser.new(options)
|
169
|
+
parser.call(haml)
|
103
170
|
end
|
104
171
|
end
|
105
|
-
end
|
172
|
+
end
|