haml 4.0.6 → 5.2.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.
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
-