haml 4.0.6 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +19 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +72 -0
  5. data/.yardopts +2 -3
  6. data/CHANGELOG.md +138 -4
  7. data/FAQ.md +4 -14
  8. data/Gemfile +16 -0
  9. data/MIT-LICENSE +2 -2
  10. data/README.md +79 -42
  11. data/REFERENCE.md +142 -67
  12. data/Rakefile +44 -63
  13. data/TODO +24 -0
  14. data/benchmark.rb +70 -0
  15. data/haml.gemspec +45 -0
  16. data/lib/haml.rb +2 -0
  17. data/lib/haml/.gitattributes +1 -0
  18. data/lib/haml/attribute_builder.rb +164 -0
  19. data/lib/haml/attribute_compiler.rb +235 -0
  20. data/lib/haml/attribute_parser.rb +150 -0
  21. data/lib/haml/buffer.rb +29 -136
  22. data/lib/haml/compiler.rb +110 -320
  23. data/lib/haml/engine.rb +34 -41
  24. data/lib/haml/error.rb +28 -24
  25. data/lib/haml/escapable.rb +77 -0
  26. data/lib/haml/exec.rb +38 -20
  27. data/lib/haml/filters.rb +22 -27
  28. data/lib/haml/generator.rb +42 -0
  29. data/lib/haml/helpers.rb +134 -89
  30. data/lib/haml/helpers/action_view_extensions.rb +4 -2
  31. data/lib/haml/helpers/action_view_mods.rb +45 -60
  32. data/lib/haml/helpers/action_view_xss_mods.rb +2 -0
  33. data/lib/haml/helpers/safe_erubi_template.rb +20 -0
  34. data/lib/haml/helpers/safe_erubis_template.rb +5 -1
  35. data/lib/haml/helpers/xss_mods.rb +23 -13
  36. data/lib/haml/options.rb +63 -69
  37. data/lib/haml/parser.rb +292 -228
  38. data/lib/haml/plugin.rb +37 -0
  39. data/lib/haml/railtie.rb +38 -12
  40. data/lib/haml/sass_rails_filter.rb +18 -4
  41. data/lib/haml/template.rb +13 -6
  42. data/lib/haml/template/options.rb +13 -2
  43. data/lib/haml/temple_engine.rb +123 -0
  44. data/lib/haml/temple_line_counter.rb +30 -0
  45. data/lib/haml/util.rb +83 -202
  46. data/lib/haml/version.rb +3 -1
  47. data/yard/default/.gitignore +1 -0
  48. data/yard/default/fulldoc/html/css/common.sass +15 -0
  49. data/yard/default/layout/html/footer.erb +12 -0
  50. metadata +73 -108
  51. data/lib/haml/template/plugin.rb +0 -41
  52. data/test/engine_test.rb +0 -2013
  53. data/test/erb/_av_partial_1.erb +0 -12
  54. data/test/erb/_av_partial_2.erb +0 -8
  55. data/test/erb/action_view.erb +0 -62
  56. data/test/erb/standard.erb +0 -55
  57. data/test/filters_test.rb +0 -254
  58. data/test/gemfiles/Gemfile.rails-3.0.x +0 -5
  59. data/test/gemfiles/Gemfile.rails-3.1.x +0 -6
  60. data/test/gemfiles/Gemfile.rails-3.2.x +0 -5
  61. data/test/gemfiles/Gemfile.rails-4.0.x +0 -5
  62. data/test/helper_test.rb +0 -583
  63. data/test/markaby/standard.mab +0 -52
  64. data/test/mocks/article.rb +0 -6
  65. data/test/parser_test.rb +0 -105
  66. data/test/results/content_for_layout.xhtml +0 -12
  67. data/test/results/eval_suppressed.xhtml +0 -9
  68. data/test/results/helpers.xhtml +0 -70
  69. data/test/results/helpful.xhtml +0 -10
  70. data/test/results/just_stuff.xhtml +0 -70
  71. data/test/results/list.xhtml +0 -12
  72. data/test/results/nuke_inner_whitespace.xhtml +0 -40
  73. data/test/results/nuke_outer_whitespace.xhtml +0 -148
  74. data/test/results/original_engine.xhtml +0 -20
  75. data/test/results/partial_layout.xhtml +0 -5
  76. data/test/results/partial_layout_erb.xhtml +0 -5
  77. data/test/results/partials.xhtml +0 -21
  78. data/test/results/render_layout.xhtml +0 -3
  79. data/test/results/silent_script.xhtml +0 -74
  80. data/test/results/standard.xhtml +0 -162
  81. data/test/results/tag_parsing.xhtml +0 -23
  82. data/test/results/very_basic.xhtml +0 -5
  83. data/test/results/whitespace_handling.xhtml +0 -90
  84. data/test/template_test.rb +0 -354
  85. data/test/templates/_av_partial_1.haml +0 -9
  86. data/test/templates/_av_partial_1_ugly.haml +0 -9
  87. data/test/templates/_av_partial_2.haml +0 -5
  88. data/test/templates/_av_partial_2_ugly.haml +0 -5
  89. data/test/templates/_layout.erb +0 -3
  90. data/test/templates/_layout_for_partial.haml +0 -3
  91. data/test/templates/_partial.haml +0 -8
  92. data/test/templates/_text_area.haml +0 -3
  93. data/test/templates/_text_area_helper.html.haml +0 -4
  94. data/test/templates/action_view.haml +0 -47
  95. data/test/templates/action_view_ugly.haml +0 -47
  96. data/test/templates/breakage.haml +0 -8
  97. data/test/templates/content_for_layout.haml +0 -8
  98. data/test/templates/eval_suppressed.haml +0 -11
  99. data/test/templates/helpers.haml +0 -55
  100. data/test/templates/helpful.haml +0 -11
  101. data/test/templates/just_stuff.haml +0 -85
  102. data/test/templates/list.haml +0 -12
  103. data/test/templates/nuke_inner_whitespace.haml +0 -32
  104. data/test/templates/nuke_outer_whitespace.haml +0 -144
  105. data/test/templates/original_engine.haml +0 -17
  106. data/test/templates/partial_layout.haml +0 -3
  107. data/test/templates/partial_layout_erb.erb +0 -4
  108. data/test/templates/partialize.haml +0 -1
  109. data/test/templates/partials.haml +0 -12
  110. data/test/templates/render_layout.haml +0 -2
  111. data/test/templates/silent_script.haml +0 -45
  112. data/test/templates/standard.haml +0 -43
  113. data/test/templates/standard_ugly.haml +0 -43
  114. data/test/templates/tag_parsing.haml +0 -21
  115. data/test/templates/very_basic.haml +0 -4
  116. data/test/templates/whitespace_handling.haml +0 -87
  117. data/test/test_helper.rb +0 -81
  118. data/test/util_test.rb +0 -63
@@ -1,12 +0,0 @@
1
- <h2>This is a pretty complicated partial</h2>
2
- <div class="partial">
3
- <p>It has several nested partials,</p>
4
- <ul>
5
- <% 5.times do %>
6
- <li>
7
- <strong>Partial:</strong>
8
- <% @nesting = 5 %>
9
- <%= render :partial => 'erb/av_partial_2' %>
10
- <% end %>
11
- </ul>
12
- </div>
@@ -1,8 +0,0 @@
1
- <% @nesting -= 1 %>
2
- <div class="partial" level="<%= @nesting %>">
3
- <h3>This is a crazy deep-nested partial.</h3>
4
- <p>Nesting level <%= @nesting %></p>
5
- <% if @nesting > 0 %>
6
- <%= render :partial => 'erb/av_partial_2' %>
7
- <% end %>
8
- </div>
@@ -1,62 +0,0 @@
1
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
- <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en-US'>
3
- <head>
4
- <title>Hampton Catlin Is Totally Awesome</title>
5
- <meta content='text/html; charset=utf-8' http-equiv='Content-Type' />
6
- </head>
7
- <body>
8
- <h1>
9
- This is very much like the standard template,
10
- except that it has some ActionView-specific stuff.
11
- It's only used for benchmarking.
12
- </h1>
13
- <div class="crazy_partials">
14
- <%= render :partial => 'erb/av_partial_1' %>
15
- </div>
16
- <!-- You're In my house now! -->
17
- <div class='header'>
18
- Yes, ladies and gentileman. He is just that egotistical.
19
- Fantastic! This should be multi-line output
20
- The question is if this would translate! Ahah!
21
- <%= 1 + 9 + 8 + 2 %>
22
- <%# numbers should work and this should be ignored %>
23
- </div>
24
- <% 120.times do |number| -%>
25
- <%= number %>
26
- <% end -%>
27
- <div id='body'><%= " Quotes should be loved! Just like people!" %></div>
28
- Wow.
29
- <p>
30
- <%= "Holy cow " +
31
- "multiline " +
32
- "tags! " +
33
- "A pipe (|) even!" %>
34
- <%= [1, 2, 3].collect { |n| "PipesIgnored|" } %>
35
- <%= [1, 2, 3].collect { |n|
36
- n.to_s
37
- }.join("|") %>
38
- </p>
39
- <div class='silent'>
40
- <% foo = String.new
41
- foo << "this"
42
- foo << " shouldn't"
43
- foo << " evaluate" %>
44
- <%= foo + "but now it should!" %>
45
- <%# Woah crap a comment! %>
46
- </div>
47
- <ul class='really cool'>
48
- <% ('a'..'f').each do |a|%>
49
- <li><%= a %>
50
- <% end %>
51
- <div class='of_divs_with_underscore' id='combo'><%= @should_eval = "with this text" %></div>
52
- <%= [ 104, 101, 108, 108, 111 ].map do |byte|
53
- byte.chr
54
- end %>
55
- <div class='footer'>
56
- <strong class='shout'>
57
- <%= "This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid.\n" +
58
- " So, I'm just making it *really* long. God, I hope this works" %>
59
- </strong>
60
- </div>
61
- </body>
62
- </html>
@@ -1,55 +0,0 @@
1
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
- <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en-US' lang='en-US'>
3
- <head>
4
- <title>Hampton Catlin Is Totally Awesome</title>
5
- <meta content='text/html; charset=utf-8' http-equiv='Content-Type' />
6
- </head>
7
- <body>
8
- <!-- You're In my house now! -->
9
- <div class='header'>
10
- Yes, ladies and gentileman. He is just that egotistical.
11
- Fantastic! This should be multi-line output
12
- The question is if this would translate! Ahah!
13
- <%= 1 + 9 + 8 + 2 %>
14
- <%# numbers should work and this should be ignored %>
15
- </div>
16
- <% 120.times do |number| -%>
17
- <%= number %>
18
- <% end -%>
19
- <div id='body'><%= " Quotes should be loved! Just like people!" %></div>
20
- Wow.
21
- <p code="<%= 1 + 2 %>">
22
- <%= "Holy cow " +
23
- "multiline " +
24
- "tags! " +
25
- "A pipe (|) even!" %>
26
- <%= [1, 2, 3].collect { |n| "PipesIgnored|" }.join %>
27
- <%= [1, 2, 3].collect { |n|
28
- n.to_s
29
- }.join("|") %>
30
- </p>
31
- <% bar = 17 %>
32
- <div class='silent' foo="<%= bar %>">
33
- <% foo = String.new
34
- foo << "this"
35
- foo << " shouldn't"
36
- foo << " evaluate" %>
37
- <%= foo + "but now it should!" %>
38
- <%# Woah crap a comment! %>
39
- </div>
40
- <ul class='really cool'>
41
- <% ('a'..'f').each do |a|%>
42
- <li><%= a %></li>
43
- <% end %>
44
- <div class='of_divs_with_underscore' id='combo'><%= @should_eval = "with this text" %></div>
45
- <%= "foo".each_line do |line|
46
- nil
47
- end %>
48
- <div class='footer'>
49
- <strong class='shout'>
50
- <%= "This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid.\n" +
51
- " So, I'm just making it *really* long. God, I hope this works" %>
52
- </strong>
53
- </div>
54
- </body>
55
- </html>
@@ -1,254 +0,0 @@
1
- require 'test_helper'
2
-
3
- class FiltersTest < MiniTest::Unit::TestCase
4
- test "should be registered as filters when including Haml::Filters::Base" do
5
- begin
6
- refute Haml::Filters.defined.has_key? "bar"
7
- Module.new {def self.name; "Foo::Bar"; end; include Haml::Filters::Base}
8
- assert Haml::Filters.defined.has_key? "bar"
9
- ensure
10
- Haml::Filters.remove_filter "Bar"
11
- end
12
- end
13
-
14
- test "should raise error when attempting to register a defined Tilt filter" do
15
- begin
16
- assert_raises RuntimeError do
17
- 2.times do
18
- Haml::Filters.register_tilt_filter "Foo"
19
- end
20
- end
21
- ensure
22
- Haml::Filters.remove_filter "Foo"
23
- end
24
- end
25
-
26
- test "should raise error when a Tilt filters dependencies are unavailable for extension" do
27
- begin
28
- assert_raises Haml::Error do
29
- Haml::Filters.register_tilt_filter "Textile"
30
- Haml::Filters.defined["textile"].template_class
31
- end
32
- ensure
33
- Haml::Filters.remove_filter "Textile"
34
- end
35
- end
36
-
37
- test "should raise error when a Tilt filters dependencies are unavailable for filter without extension" do
38
- begin
39
- assert_raises Haml::Error do
40
- Haml::Filters.register_tilt_filter "Maruku"
41
- Haml::Filters.defined["maruku"].template_class
42
- end
43
- ensure
44
- Haml::Filters.remove_filter "Maruku"
45
- end
46
- end
47
-
48
- test "should raise informative error about Maruku being moved to haml-contrib" do
49
- begin
50
- render(":maruku\n # foo")
51
- flunk("Should have raised error with message about the haml-contrib gem.")
52
- rescue Haml::Error => e
53
- assert_equal e.message, Haml::Error.message(:install_haml_contrib, "maruku")
54
- end
55
- end
56
-
57
- test "should raise informative error about Textile being moved to haml-contrib" do
58
- begin
59
- render(":textile\n h1. foo")
60
- flunk("Should have raised error with message about the haml-contrib gem.")
61
- rescue Haml::Error => e
62
- assert_equal e.message, Haml::Error.message(:install_haml_contrib, "textile")
63
- end
64
- end
65
-
66
- test "should respect escaped newlines and interpolation" do
67
- html = "\\n\n"
68
- haml = ":plain\n \\n\#{""}"
69
- assert_equal(html, render(haml))
70
- end
71
-
72
- test "should process an filter with no content" do
73
- assert_equal("\n", render(':plain'))
74
- end
75
-
76
- test "should be compatible with ugly mode" do
77
- expectation = "foo\n"
78
- assert_equal(expectation, render(":plain\n foo", :ugly => true))
79
- end
80
-
81
- test "should pass options to Tilt filters that precompile" do
82
- haml = ":erb\n <%= 'foo' %>"
83
- refute_match('TEST_VAR', Haml::Engine.new(haml).compiler.precompiled)
84
- Haml::Filters::Erb.options = {:outvar => 'TEST_VAR'}
85
- assert_match('TEST_VAR', Haml::Engine.new(haml).compiler.precompiled)
86
- end
87
-
88
- test "should pass options to Tilt filters that don't precompile" do
89
- begin
90
- filter = Class.new(Tilt::Template) do
91
- def self.name
92
- "Foo"
93
- end
94
-
95
- def prepare
96
- @engine = {:data => data, :options => options}
97
- end
98
-
99
- def evaluate(scope, locals, &block)
100
- @output = @engine[:options].to_a.join
101
- end
102
- end
103
- Haml::Filters.register_tilt_filter "Foo", :template_class => filter
104
- Haml::Filters::Foo.options[:foo] = "bar"
105
- haml = ":foo"
106
- assert_equal "foobar\n", render(haml)
107
- ensure
108
- Haml::Filters.remove_filter "Foo"
109
- end
110
- end
111
-
112
- end
113
-
114
- class ErbFilterTest < MiniTest::Unit::TestCase
115
- test "multiline expressions should work" do
116
- html = "foobarbaz\n"
117
- haml = %Q{:erb\n <%= "foo" +\n "bar" +\n "baz" %>}
118
- assert_equal(html, render(haml))
119
- end
120
-
121
- test "should evaluate in the same context as Haml" do
122
- haml = ":erb\n <%= foo %>"
123
- html = "bar\n"
124
- scope = Object.new.instance_eval {foo = "bar"; nil if foo; binding}
125
- assert_equal(html, render(haml, :scope => scope))
126
- end
127
-
128
- test "should use Rails's XSS safety features" do
129
- assert_equal("&lt;img&gt;\n", render(":erb\n <%= '<img>' %>"))
130
- assert_equal("<img>\n", render(":erb\n <%= '<img>'.html_safe %>"))
131
- end
132
-
133
- end
134
-
135
- class JavascriptFilterTest < MiniTest::Unit::TestCase
136
- test "should interpolate" do
137
- scope = Object.new.instance_eval {foo = "bar"; nil if foo; binding}
138
- haml = ":javascript\n \#{foo}"
139
- html = render(haml, :scope => scope)
140
- assert_match(/bar/, html)
141
- end
142
-
143
- test "should never HTML-escape ampersands" do
144
- html = "<script>\n & < > &\n</script>\n"
145
- haml = %Q{:javascript\n & < > \#{"&"}}
146
- assert_equal(html, render(haml, :escape_html => true))
147
- end
148
-
149
- test "should not include type in HTML 5 output" do
150
- html = "<script>\n foo bar\n</script>\n"
151
- haml = ":javascript\n foo bar"
152
- assert_equal(html, render(haml, :format => :html5))
153
- end
154
-
155
- test "should always include CDATA when format is xhtml" do
156
- html = "<script type='text/javascript'>\n //<![CDATA[\n foo bar\n //]]>\n</script>\n"
157
- haml = ":javascript\n foo bar"
158
- assert_equal(html, render(haml, :format => :xhtml, :cdata => false))
159
- end
160
-
161
- test "should omit CDATA when cdata option is false" do
162
- html = "<script>\n foo bar\n</script>\n"
163
- haml = ":javascript\n foo bar"
164
- assert_equal(html, render(haml, :format => :html5, :cdata => false))
165
- end
166
-
167
- test "should include CDATA when cdata option is true" do
168
- html = "<script>\n //<![CDATA[\n foo bar\n //]]>\n</script>\n"
169
- haml = ":javascript\n foo bar"
170
- assert_equal(html, render(haml, :format => :html5, :cdata => true))
171
- end
172
-
173
- test "should default to no CDATA when format is html5" do
174
- haml = ":javascript\n foo bar"
175
- out = render(haml, :format => :html5)
176
- refute_match('//<![CDATA[', out)
177
- refute_match('//]]>', out)
178
- end
179
- end
180
-
181
- class CSSFilterTest < MiniTest::Unit::TestCase
182
- test "should wrap output in CDATA and a CSS tag when output is XHTML" do
183
- html = "<style type='text/css'>\n /*<![CDATA[*/\n foo\n /*]]>*/\n</style>\n"
184
- haml = ":css\n foo"
185
- assert_equal(html, render(haml, :format => :xhtml))
186
- end
187
-
188
- test "should not include type in HTML 5 output" do
189
- html = "<style>\n foo bar\n</style>\n"
190
- haml = ":css\n foo bar"
191
- assert_equal(html, render(haml, :format => :html5))
192
- end
193
-
194
- test "should always include CDATA when format is xhtml" do
195
- html = "<style type='text/css'>\n /*<![CDATA[*/\n foo bar\n /*]]>*/\n</style>\n"
196
- haml = ":css\n foo bar"
197
- assert_equal(html, render(haml, :format => :xhtml, :cdata => false))
198
- end
199
-
200
- test "should omit CDATA when cdata option is false" do
201
- html = "<style>\n foo bar\n</style>\n"
202
- haml = ":css\n foo bar"
203
- assert_equal(html, render(haml, :format => :html5, :cdata => false))
204
- end
205
-
206
- test "should include CDATA when cdata option is true" do
207
- html = "<style>\n /*<![CDATA[*/\n foo bar\n /*]]>*/\n</style>\n"
208
- haml = ":css\n foo bar"
209
- assert_equal(html, render(haml, :format => :html5, :cdata => true))
210
- end
211
-
212
- test "should default to no CDATA when format is html5" do
213
- haml = ":css\n foo bar"
214
- out = render(haml, :format => :html5)
215
- refute_match('<![CDATA[', out)
216
- refute_match(']]>', out)
217
- end
218
- end
219
-
220
- class CDATAFilterTest < MiniTest::Unit::TestCase
221
- test "should wrap output in CDATA tag" do
222
- html = "<![CDATA[\n foo\n]]>\n"
223
- haml = ":cdata\n foo"
224
- assert_equal(html, render(haml))
225
- end
226
- end
227
-
228
- class EscapedFilterTest < MiniTest::Unit::TestCase
229
- test "should escape ampersands" do
230
- html = "&amp;\n"
231
- haml = ":escaped\n &"
232
- assert_equal(html, render(haml))
233
- end
234
- end
235
-
236
- class RubyFilterTest < MiniTest::Unit::TestCase
237
- test "can write to haml_io" do
238
- haml = ":ruby\n haml_io.puts 'hello'\n"
239
- html = "hello\n"
240
- assert_equal(html, render(haml))
241
- end
242
-
243
- test "haml_io appends to output" do
244
- haml = "hello\n:ruby\n haml_io.puts 'hello'\n"
245
- html = "hello\nhello\n"
246
- assert_equal(html, render(haml))
247
- end
248
-
249
- test "can create local variables" do
250
- haml = ":ruby\n a = 7\n=a"
251
- html = "7\n"
252
- assert_equal(html, render(haml))
253
- end
254
- end
@@ -1,5 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem 'rails', '>= 3.0.0', '< 3.1.0'
4
- gemspec :path => "../.."
5
-
@@ -1,6 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem 'rails', '>= 3.1.0', '< 3.2.0'
4
- gemspec :path => "../.."
5
-
6
-
@@ -1,5 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem 'rails', '>= 3.2.0', '< 3.3.0'
4
- gemspec :path => "../.."
5
-
@@ -1,5 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem 'bundler', '~> 1.3.0'
4
- gem 'rails', '~> 4.0.0.rc1'
5
- gemspec :path => '../..'
@@ -1,583 +0,0 @@
1
- require 'test_helper'
2
-
3
- class ActionView::Base
4
- def nested_tag
5
- content_tag(:span) {content_tag(:div) {"something"}}
6
- end
7
-
8
- def wacky_form
9
- form_tag("/foo") {"bar"}
10
- end
11
- end
12
-
13
- module Haml::Helpers
14
- def something_that_uses_haml_concat
15
- haml_concat('foo').to_s
16
- end
17
-
18
- def render_something_with_haml_concat
19
- haml_concat "<p>"
20
- end
21
-
22
- def render_something_with_haml_tag_and_concat
23
- haml_tag 'p' do
24
- haml_concat '<foo>'
25
- end
26
- end
27
- end
28
-
29
- class HelperTest < MiniTest::Unit::TestCase
30
- Post = Struct.new('Post', :body, :error_field, :errors)
31
- class PostErrors
32
- def on(name)
33
- return unless name == 'error_field'
34
- ["Really bad error"]
35
- end
36
- alias_method :full_messages, :on
37
-
38
- def [](name)
39
- on(name) || []
40
- end
41
- end
42
-
43
- def setup
44
- @base = ActionView::Base.new
45
- @base.controller = ActionController::Base.new
46
- @base.view_paths << File.expand_path("../templates", __FILE__)
47
-
48
- if defined?(ActionController::Response)
49
- # This is needed for >=3.0.0
50
- @base.controller.response = ActionController::Response.new
51
- end
52
-
53
- @base.instance_variable_set('@post', Post.new("Foo bar\nbaz", nil, PostErrors.new))
54
- end
55
-
56
- def render(text, options = {})
57
- return @base.render :inline => text, :type => :haml if options == :action_view
58
- super
59
- end
60
-
61
- def test_rendering_with_escapes
62
- output = render(<<-HAML, :action_view)
63
- - render_something_with_haml_concat
64
- - render_something_with_haml_tag_and_concat
65
- - render_something_with_haml_concat
66
- HAML
67
- assert_equal("&lt;p&gt;\n<p>\n <foo>\n</p>\n&lt;p&gt;\n", output)
68
- end
69
-
70
- def test_flatten
71
- assert_equal("FooBar", Haml::Helpers.flatten("FooBar"))
72
-
73
- assert_equal("FooBar", Haml::Helpers.flatten("Foo\rBar"))
74
-
75
- assert_equal("Foo&#x000A;Bar", Haml::Helpers.flatten("Foo\nBar"))
76
-
77
- assert_equal("Hello&#x000A;World!&#x000A;YOU ARE FLAT?&#x000A;OMGZ!",
78
- Haml::Helpers.flatten("Hello\nWorld!\nYOU ARE \rFLAT?\n\rOMGZ!"))
79
- end
80
-
81
- def test_list_of_should_render_correctly
82
- assert_equal("<li>1</li>\n<li>2</li>\n", render("= list_of([1, 2]) do |i|\n = i"))
83
- assert_equal("<li>[1]</li>\n", 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>\n",
85
- render("= list_of(['Fee', 'Fi', 'Fo', 'Fum']) do |title|\n %h1= title\n %p A word!"))
86
- assert_equal("<li c='3'>1</li>\n<li c='3'>2</li>\n", render("= list_of([1, 2], {:c => 3}) do |i|\n = i"))
87
- assert_equal("<li c='3'>[1]</li>\n", 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>\n",
89
- render("= list_of(['Fee', 'Fi', 'Fo', 'Fum'], {:c => 3}) do |title|\n %h1= title\n %p A word!"))
90
- end
91
-
92
- def test_buffer_access
93
- assert(render("= buffer") =~ /#<Haml::Buffer:0x[a-z0-9]+>/)
94
- assert_equal(render("= (buffer == _hamlout)"), "true\n")
95
- end
96
-
97
- def test_tabs
98
- assert_equal("foo\n bar\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"))
100
- end
101
-
102
- def test_with_tabs
103
- assert_equal(<<HTML, render(<<HAML))
104
- Foo
105
- Bar
106
- Baz
107
- Baz
108
- HTML
109
- Foo
110
- - with_tabs 2 do
111
- = "Bar\\nBaz"
112
- Baz
113
- HAML
114
- end
115
-
116
- def test_helpers_dont_leak
117
- # Haml helpers shouldn't be accessible from ERB
118
- render("foo")
119
- proper_behavior = false
120
-
121
- begin
122
- ActionView::Base.new.render(:inline => "<%= flatten('Foo\\nBar') %>")
123
- rescue NoMethodError, Haml::Util.av_template_class(:Error)
124
- proper_behavior = true
125
- end
126
- assert(proper_behavior)
127
-
128
- begin
129
- ActionView::Base.new.render(:inline => "<%= concat('foo') %>")
130
- rescue ArgumentError, NameError
131
- proper_behavior = true
132
- end
133
- assert(proper_behavior)
134
- end
135
-
136
- def test_action_view_included
137
- assert(Haml::Helpers.action_view?)
138
- end
139
-
140
- def test_form_tag
141
- # This is usually provided by ActionController::Base.
142
- def @base.protect_against_forgery?; false; end
143
-
144
- rendered = render(<<HAML, :action_view)
145
- = form_tag 'foo' do
146
- %p bar
147
- %strong baz
148
- HAML
149
- fragment = Nokogiri::HTML.fragment(rendered)
150
- assert_equal 'foo', fragment.css('form').first.attributes['action'].to_s
151
- assert_equal 'bar', fragment.css('form p').first.text.strip
152
- assert_equal 'baz', fragment.css('form strong').first.text.strip
153
- end
154
-
155
- def test_pre
156
- assert_equal(%(<pre>Foo bar&#x000A; baz</pre>\n),
157
- render('= content_tag "pre", "Foo bar\n baz"', :action_view))
158
- end
159
-
160
- # Rails >= 3.2.3 adds a newline after opening textarea tags.
161
- def self.rails_text_area_helpers_emit_a_newline?
162
- major, minor, tiny = ActionPack::VERSION::MAJOR, ActionPack::VERSION::MINOR, ActionPack::VERSION::TINY
163
- major == 4 || ((major == 3) && (minor >= 2) && (tiny >= 3))
164
- end
165
-
166
- def text_area_content_regex
167
- @text_area_content_regex ||= if self.class.rails_text_area_helpers_emit_a_newline?
168
- /<(textarea)[^>]*>\n(.*?)<\/\1>/im
169
- else
170
- /<(textarea)[^>]*>(.*?)<\/\1>/im
171
- end
172
- end
173
-
174
- def test_text_area_tag
175
- output = render('= text_area_tag "body", "Foo\nBar\n Baz\n Boom"', :action_view)
176
- match_data = output.match(text_area_content_regex)
177
- assert_equal "Foo&#x000A;Bar&#x000A; Baz&#x000A; Boom", match_data[2]
178
- end
179
-
180
- def test_text_area
181
- output = render('= text_area :post, :body', :action_view)
182
- match_data = output.match(text_area_content_regex)
183
- assert_equal "Foo bar&#x000A;baz", match_data[2]
184
- end
185
-
186
- def test_partials_should_not_cause_textareas_to_be_indented
187
- # non-indentation of textareas rendered inside partials
188
- @base.instance_variable_set('@post', Post.new("Foo", nil, PostErrors.new))
189
- output = render(".foo\n .bar\n = render '/text_area_helper'", :action_view)
190
- match_data = output.match(text_area_content_regex)
191
- assert_equal 'Foo', match_data[2]
192
- end
193
-
194
- if rails_text_area_helpers_emit_a_newline?
195
- def test_textareas_should_prerve_leading_whitespace
196
- # leading whitespace preservation
197
- @base.instance_variable_set('@post', Post.new(" Foo", nil, PostErrors.new))
198
- output = render(".foo\n = text_area :post, :body", :action_view)
199
- match_data = output.match(text_area_content_regex)
200
- assert_equal '&#x0020; Foo', match_data[2]
201
- end
202
-
203
- def test_textareas_should_prerve_leading_whitespace_in_partials
204
- # leading whitespace in textareas rendered inside partials
205
- @base.instance_variable_set('@post', Post.new(" Foo", nil, PostErrors.new))
206
- output = render(".foo\n .bar\n = render '/text_area_helper'", :action_view)
207
- match_data = output.match(text_area_content_regex)
208
- assert_equal '&#x0020; Foo', match_data[2]
209
- end
210
- end
211
-
212
- def test_capture_haml
213
- assert_equal(<<HTML, render(<<HAML))
214
- "<p>13</p>\\n"
215
- HTML
216
- - (foo = capture_haml(13) do |a|
217
- %p= a
218
- - end)
219
- = foo.inspect
220
- HAML
221
- end
222
-
223
- def test_content_tag_block
224
- assert_equal(<<HTML.strip, render(<<HAML, :action_view).strip)
225
- <div><p>bar</p>
226
- <strong>bar</strong>
227
- </div>
228
- HTML
229
- = content_tag :div do
230
- %p bar
231
- %strong bar
232
- HAML
233
- end
234
-
235
- def test_content_tag_error_wrapping
236
- def @base.protect_against_forgery?; false; end
237
- output = render(<<HAML, :action_view)
238
- = form_for @post, :as => :post, :html => {:class => nil, :id => nil}, :url => '' do |f|
239
- = f.label 'error_field'
240
- HAML
241
- fragment = Nokogiri::HTML.fragment(output)
242
- refute_nil fragment.css('form div.field_with_errors label[for=post_error_field]').first
243
- end
244
-
245
- def test_form_tag_in_helper_with_string_block
246
- def @base.protect_against_forgery?; false; end
247
- rendered = render('= wacky_form', :action_view)
248
- fragment = Nokogiri::HTML.fragment(rendered)
249
- assert_equal 'bar', fragment.text.strip
250
- assert_equal '/foo', fragment.css('form').first.attributes['action'].to_s
251
- end
252
-
253
- def test_haml_tag_name_attribute_with_id
254
- assert_equal("<p id='some_id'></p>\n", render("- haml_tag 'p#some_id'"))
255
- end
256
-
257
- def test_haml_tag_name_attribute_with_colon_id
258
- assert_equal("<p id='some:id'></p>\n", render("- haml_tag 'p#some:id'"))
259
- end
260
-
261
- def test_haml_tag_without_name_but_with_id
262
- assert_equal("<div id='some_id'></div>\n", render("- haml_tag '#some_id'"))
263
- end
264
-
265
- def test_haml_tag_without_name_but_with_class
266
- assert_equal("<div class='foo'></div>\n", render("- haml_tag '.foo'"))
267
- end
268
-
269
- def test_haml_tag_without_name_but_with_colon_class
270
- assert_equal("<div class='foo:bar'></div>\n", render("- haml_tag '.foo:bar'"))
271
- end
272
-
273
- def test_haml_tag_name_with_id_and_class
274
- assert_equal("<p class='foo' id='some_id'></p>\n", render("- haml_tag 'p#some_id.foo'"))
275
- end
276
-
277
- def test_haml_tag_name_with_class
278
- assert_equal("<p class='foo'></p>\n", render("- haml_tag 'p.foo'"))
279
- end
280
-
281
- def test_haml_tag_name_with_class_and_id
282
- assert_equal("<p class='foo' id='some_id'></p>\n", render("- haml_tag 'p.foo#some_id'"))
283
- end
284
-
285
- def test_haml_tag_name_with_id_and_multiple_classes
286
- assert_equal("<p class='foo bar' id='some_id'></p>\n", render("- haml_tag 'p#some_id.foo.bar'"))
287
- end
288
-
289
- def test_haml_tag_name_with_multiple_classes_and_id
290
- assert_equal("<p class='foo bar' id='some_id'></p>\n", render("- haml_tag 'p.foo.bar#some_id'"))
291
- end
292
-
293
- def test_haml_tag_name_and_attribute_classes_merging_with_id
294
- assert_equal("<p class='bar foo' id='some_id'></p>\n", render("- haml_tag 'p#some_id.foo', :class => 'bar'"))
295
- end
296
-
297
- def test_haml_tag_name_and_attribute_classes_merging
298
- assert_equal("<p class='bar foo'></p>\n", render("- haml_tag 'p.foo', :class => 'bar'"))
299
- end
300
-
301
- def test_haml_tag_name_merges_id_and_attribute_id
302
- assert_equal("<p id='foo_bar'></p>\n", render("- haml_tag 'p#foo', :id => 'bar'"))
303
- end
304
-
305
- def test_haml_tag_attribute_html_escaping
306
- assert_equal("<p id='foo&amp;bar'>baz</p>\n", render("%p{:id => 'foo&bar'} baz", :escape_html => true))
307
- end
308
-
309
- def test_haml_tag_autoclosed_tags_are_closed
310
- assert_equal("<br class='foo' />\n", render("- haml_tag :br, :class => 'foo'"))
311
- end
312
-
313
- def test_haml_tag_with_class_array
314
- assert_equal("<p class='a b'>foo</p>\n", render("- haml_tag :p, 'foo', :class => %w[a b]"))
315
- assert_equal("<p class='a b c d'>foo</p>\n", render("- haml_tag 'p.c.d', 'foo', :class => %w[a b]"))
316
- end
317
-
318
- def test_haml_tag_with_id_array
319
- assert_equal("<p id='a_b'>foo</p>\n", render("- haml_tag :p, 'foo', :id => %w[a b]"))
320
- assert_equal("<p id='c_a_b'>foo</p>\n", render("- haml_tag 'p#c', 'foo', :id => %w[a b]"))
321
- end
322
-
323
- def test_haml_tag_with_data_hash
324
- assert_equal("<p data-baz data-foo='bar'>foo</p>\n",
325
- render("- haml_tag :p, 'foo', :data => {:foo => 'bar', :baz => true}"))
326
- end
327
-
328
- def test_haml_tag_non_autoclosed_tags_arent_closed
329
- assert_equal("<p></p>\n", render("- haml_tag :p"))
330
- end
331
-
332
- def test_haml_tag_renders_text_on_a_single_line
333
- assert_equal("<p>#{'a' * 100}</p>\n", render("- haml_tag :p, 'a' * 100"))
334
- end
335
-
336
- def test_haml_tag_raises_error_for_multiple_content
337
- assert_raises(Haml::Error) { render("- haml_tag :p, 'foo' do\n bar") }
338
- end
339
-
340
- def test_haml_tag_flags
341
- assert_equal("<p />\n", render("- haml_tag :p, :/"))
342
- assert_equal("<p>kumquat</p>\n", render("- haml_tag :p, :< do\n kumquat"))
343
-
344
- assert_raises(Haml::Error) { render("- haml_tag :p, 'foo', :/") }
345
- assert_raises(Haml::Error) { render("- haml_tag :p, :/ do\n foo") }
346
- end
347
-
348
- def test_haml_tag_error_return
349
- assert_raises(Haml::Error) { render("= haml_tag :p") }
350
- end
351
-
352
- def test_haml_tag_with_multiline_string
353
- assert_equal(<<HTML, render(<<HAML))
354
- <p>
355
- foo
356
- bar
357
- baz
358
- </p>
359
- HTML
360
- - haml_tag :p, "foo\\nbar\\nbaz"
361
- HAML
362
- end
363
-
364
- def test_haml_concat_with_multiline_string
365
- assert_equal(<<HTML, render(<<HAML))
366
- <p>
367
- foo
368
- bar
369
- baz
370
- </p>
371
- HTML
372
- %p
373
- - haml_concat "foo\\nbar\\nbaz"
374
- HAML
375
- end
376
-
377
- def test_haml_tag_with_ugly
378
- assert_equal(<<HTML, render(<<HAML, :ugly => true))
379
- <p>
380
- <strong>Hi!</strong>
381
- </p>
382
- HTML
383
- - haml_tag :p do
384
- - haml_tag :strong, "Hi!"
385
- HAML
386
- end
387
-
388
- def test_is_haml
389
- assert(!ActionView::Base.new.is_haml?)
390
- assert_equal("true\n", render("= is_haml?"))
391
- assert_equal("true\n", render("= is_haml?", :action_view))
392
- assert_equal("false", @base.render(:inline => '<%= is_haml? %>'))
393
- assert_equal("false\n", render("= render :inline => '<%= is_haml? %>'", :action_view))
394
- end
395
-
396
- def test_page_class
397
- controller = Struct.new(:controller_name, :action_name).new('troller', 'tion')
398
- scope = Struct.new(:controller).new(controller)
399
- result = render("%div{:class => page_class} MyDiv", :scope => scope)
400
- expected = "<div class='troller tion'>MyDiv</div>\n"
401
- assert_equal expected, result
402
- end
403
-
404
- def test_indented_capture
405
- assert_equal(" Foo\n ", @base.render(:inline => " <% res = capture do %>\n Foo\n <% end %><%= res %>"))
406
- end
407
-
408
- def test_capture_deals_properly_with_collections
409
- Haml::Helpers.module_eval do
410
- def trc(collection, &block)
411
- collection.each do |record|
412
- haml_concat capture_haml(record, &block)
413
- end
414
- end
415
- end
416
-
417
- assert_equal("1\n\n2\n\n3\n\n", render("- trc([1, 2, 3]) do |i|\n = i.inspect"))
418
- end
419
-
420
- def test_capture_with_string_block
421
- assert_equal("foo\n", render("= capture { 'foo' }", :action_view))
422
- end
423
-
424
- def test_capture_with_non_string_value_reurns_nil
425
- Haml::Helpers.module_eval do
426
- def check_capture_returns_nil(&block)
427
- contents = capture(&block)
428
-
429
- contents << "ERROR" if contents
430
- end
431
- end
432
-
433
- assert_equal("\n", render("= check_capture_returns_nil { 2 }", :action_view))
434
- end
435
-
436
- def test_find_and_preserve_with_block
437
- assert_equal("<pre>Foo&#x000A;Bar</pre>\nFoo\nBar\n",
438
- render("= find_and_preserve do\n %pre\n Foo\n Bar\n Foo\n Bar"))
439
- end
440
-
441
- def test_find_and_preserve_with_block_and_tags
442
- assert_equal("<pre>Foo\nBar</pre>\nFoo\nBar\n",
443
- render("= find_and_preserve([]) do\n %pre\n Foo\n Bar\n Foo\n Bar"))
444
- end
445
-
446
- def test_preserve_with_block
447
- assert_equal("<pre>Foo&#x000A;Bar</pre>&#x000A;Foo&#x000A;Bar\n",
448
- render("= preserve do\n %pre\n Foo\n Bar\n Foo\n Bar"))
449
- end
450
-
451
- def test_init_haml_helpers
452
- context = Object.new
453
- class << context
454
- include Haml::Helpers
455
- end
456
- context.init_haml_helpers
457
-
458
- result = context.capture_haml do
459
- context.haml_tag :p, :attr => "val" do
460
- context.haml_concat "Blah"
461
- end
462
- end
463
-
464
- assert_equal("<p attr='val'>\n Blah\n</p>\n", result)
465
- end
466
-
467
- def test_non_haml
468
- assert_equal("false\n", render("= non_haml { is_haml? }"))
469
- end
470
-
471
- def test_content_tag_nested
472
- assert_equal "<span><div>something</div></span>", render("= nested_tag", :action_view).strip
473
- end
474
-
475
- def test_error_return
476
- assert_raises(Haml::Error, <<MESSAGE) {render("= haml_concat 'foo'")}
477
- haml_concat outputs directly to the Haml template.
478
- Disregard its return value and use the - operator,
479
- or use capture_haml to get the value as a String.
480
- MESSAGE
481
- end
482
-
483
- def test_error_return_line
484
- render("%p foo\n= haml_concat 'foo'\n%p bar")
485
- assert false, "Expected Haml::Error"
486
- rescue Haml::Error => e
487
- assert_equal 2, e.backtrace[1].scan(/:(\d+)/).first.first.to_i
488
- end
489
-
490
- def test_error_return_line_in_helper
491
- render("- something_that_uses_haml_concat")
492
- assert false, "Expected Haml::Error"
493
- rescue Haml::Error => e
494
- assert_equal 15, e.backtrace[0].scan(/:(\d+)/).first.first.to_i
495
- end
496
-
497
- class ActsLikeTag
498
- # We want to be able to have people include monkeypatched ActionView helpers
499
- # without redefining is_haml?.
500
- # This is accomplished via Object#is_haml?, and this is a test for it.
501
- include ActionView::Helpers::TagHelper
502
- def to_s
503
- content_tag :p, 'some tag content'
504
- end
505
- end
506
-
507
- def test_random_class_includes_tag_helper
508
- assert_equal "<p>some tag content</p>", ActsLikeTag.new.to_s
509
- end
510
-
511
- def test_capture_with_nuke_outer
512
- assert_equal "<div></div>\n*<div>hi there!</div>\n", render(<<HAML)
513
- %div
514
- = precede("*") do
515
- %div> hi there!
516
- HAML
517
-
518
- assert_equal "<div></div>\n*<div>hi there!</div>\n", render(<<HAML)
519
- %div
520
- = precede("*") do
521
- = " "
522
- %div> hi there!
523
- HAML
524
- end
525
-
526
- def test_html_escape
527
- assert_equal "&quot;&gt;&lt;&amp;", Haml::Helpers.html_escape('"><&')
528
- end
529
-
530
- def test_html_escape_should_work_on_frozen_strings
531
- begin
532
- assert Haml::Helpers.html_escape('foo'.freeze)
533
- rescue => e
534
- flunk e.message
535
- end
536
- end
537
-
538
- def test_html_escape_encoding
539
- old_stderr, $stderr = $stderr, StringIO.new
540
- string = "\"><&\u00e9" # if you're curious, u00e9 is "LATIN SMALL LETTER E WITH ACUTE"
541
- assert_equal "&quot;&gt;&lt;&amp;\u00e9", Haml::Helpers.html_escape(string)
542
- assert $stderr.string == "", "html_escape shouldn't generate warnings with UTF-8 strings: #{$stderr.string}"
543
- ensure
544
- $stderr = old_stderr
545
- end
546
-
547
- def test_html_escape_non_string
548
- assert_equal('4.58', Haml::Helpers.html_escape(4.58))
549
- assert_equal('4.58', Haml::Helpers.html_escape_without_haml_xss(4.58))
550
- end
551
-
552
- def test_escape_once
553
- assert_equal "&quot;&gt;&lt;&amp;", Haml::Helpers.escape_once('"><&')
554
- end
555
-
556
- def test_escape_once_leaves_entity_references
557
- assert_equal "&quot;&gt;&lt;&amp; &nbsp;", Haml::Helpers.escape_once('"><& &nbsp;')
558
- end
559
-
560
- def test_escape_once_leaves_numeric_references
561
- assert_equal "&quot;&gt;&lt;&amp; &#160;", Haml::Helpers.escape_once('"><& &#160;') #decimal
562
- #assert_equal "&quot;&gt;&lt;&amp; &#x00a0;", Haml::Helpers.escape_once('"><& &#x00a0;') #hexadecimal
563
- end
564
-
565
- def test_escape_once_encoding
566
- old_stderr, $stderr = $stderr, StringIO.new
567
- string = "\"><&\u00e9 &nbsp;"
568
- assert_equal "&quot;&gt;&lt;&amp;\u00e9 &nbsp;", Haml::Helpers.escape_once(string)
569
- assert $stderr.string == "", "html_escape shouldn't generate warnings with UTF-8 strings: #{$stderr.string}"
570
- ensure
571
- $stderr = old_stderr
572
- end
573
-
574
- def test_escape_once_should_work_on_frozen_strings
575
- begin
576
- Haml::Helpers.escape_once('foo'.freeze)
577
- rescue => e
578
- flunk e.message
579
- end
580
- end
581
-
582
- end
583
-