drnic-haml 2.3.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 (190) hide show
  1. data/.yardopts +5 -0
  2. data/CONTRIBUTING +4 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +347 -0
  5. data/REVISION +1 -0
  6. data/Rakefile +371 -0
  7. data/VERSION +1 -0
  8. data/VERSION_NAME +1 -0
  9. data/bin/css2sass +7 -0
  10. data/bin/haml +9 -0
  11. data/bin/html2haml +7 -0
  12. data/bin/sass +8 -0
  13. data/extra/haml-mode.el +663 -0
  14. data/extra/sass-mode.el +205 -0
  15. data/extra/update_watch.rb +13 -0
  16. data/init.rb +8 -0
  17. data/lib/haml.rb +40 -0
  18. data/lib/haml/buffer.rb +307 -0
  19. data/lib/haml/engine.rb +301 -0
  20. data/lib/haml/error.rb +22 -0
  21. data/lib/haml/exec.rb +470 -0
  22. data/lib/haml/filters.rb +341 -0
  23. data/lib/haml/helpers.rb +560 -0
  24. data/lib/haml/helpers/action_view_extensions.rb +40 -0
  25. data/lib/haml/helpers/action_view_mods.rb +176 -0
  26. data/lib/haml/herb.rb +96 -0
  27. data/lib/haml/html.rb +308 -0
  28. data/lib/haml/precompiler.rb +997 -0
  29. data/lib/haml/shared.rb +78 -0
  30. data/lib/haml/template.rb +51 -0
  31. data/lib/haml/template/patch.rb +58 -0
  32. data/lib/haml/template/plugin.rb +71 -0
  33. data/lib/haml/util.rb +244 -0
  34. data/lib/haml/version.rb +64 -0
  35. data/lib/sass.rb +24 -0
  36. data/lib/sass/css.rb +423 -0
  37. data/lib/sass/engine.rb +491 -0
  38. data/lib/sass/environment.rb +79 -0
  39. data/lib/sass/error.rb +162 -0
  40. data/lib/sass/files.rb +133 -0
  41. data/lib/sass/plugin.rb +170 -0
  42. data/lib/sass/plugin/merb.rb +57 -0
  43. data/lib/sass/plugin/rails.rb +23 -0
  44. data/lib/sass/repl.rb +58 -0
  45. data/lib/sass/script.rb +55 -0
  46. data/lib/sass/script/bool.rb +17 -0
  47. data/lib/sass/script/color.rb +183 -0
  48. data/lib/sass/script/funcall.rb +50 -0
  49. data/lib/sass/script/functions.rb +199 -0
  50. data/lib/sass/script/lexer.rb +191 -0
  51. data/lib/sass/script/literal.rb +177 -0
  52. data/lib/sass/script/node.rb +14 -0
  53. data/lib/sass/script/number.rb +381 -0
  54. data/lib/sass/script/operation.rb +45 -0
  55. data/lib/sass/script/parser.rb +222 -0
  56. data/lib/sass/script/string.rb +12 -0
  57. data/lib/sass/script/unary_operation.rb +34 -0
  58. data/lib/sass/script/variable.rb +31 -0
  59. data/lib/sass/tree/comment_node.rb +84 -0
  60. data/lib/sass/tree/debug_node.rb +30 -0
  61. data/lib/sass/tree/directive_node.rb +70 -0
  62. data/lib/sass/tree/for_node.rb +48 -0
  63. data/lib/sass/tree/if_node.rb +54 -0
  64. data/lib/sass/tree/import_node.rb +69 -0
  65. data/lib/sass/tree/mixin_def_node.rb +29 -0
  66. data/lib/sass/tree/mixin_node.rb +48 -0
  67. data/lib/sass/tree/node.rb +252 -0
  68. data/lib/sass/tree/prop_node.rb +106 -0
  69. data/lib/sass/tree/root_node.rb +56 -0
  70. data/lib/sass/tree/rule_node.rb +220 -0
  71. data/lib/sass/tree/variable_node.rb +34 -0
  72. data/lib/sass/tree/while_node.rb +31 -0
  73. data/rails/init.rb +1 -0
  74. data/test/benchmark.rb +99 -0
  75. data/test/haml/engine_test.rb +1129 -0
  76. data/test/haml/helper_test.rb +282 -0
  77. data/test/haml/html2haml_test.rb +258 -0
  78. data/test/haml/markaby/standard.mab +52 -0
  79. data/test/haml/mocks/article.rb +6 -0
  80. data/test/haml/results/content_for_layout.xhtml +12 -0
  81. data/test/haml/results/eval_suppressed.xhtml +9 -0
  82. data/test/haml/results/filters.xhtml +62 -0
  83. data/test/haml/results/helpers.xhtml +93 -0
  84. data/test/haml/results/helpful.xhtml +10 -0
  85. data/test/haml/results/just_stuff.xhtml +68 -0
  86. data/test/haml/results/list.xhtml +12 -0
  87. data/test/haml/results/nuke_inner_whitespace.xhtml +40 -0
  88. data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
  89. data/test/haml/results/original_engine.xhtml +20 -0
  90. data/test/haml/results/partial_layout.xhtml +5 -0
  91. data/test/haml/results/partials.xhtml +21 -0
  92. data/test/haml/results/render_layout.xhtml +3 -0
  93. data/test/haml/results/silent_script.xhtml +74 -0
  94. data/test/haml/results/standard.xhtml +162 -0
  95. data/test/haml/results/tag_parsing.xhtml +23 -0
  96. data/test/haml/results/very_basic.xhtml +5 -0
  97. data/test/haml/results/whitespace_handling.xhtml +89 -0
  98. data/test/haml/rhtml/_av_partial_1.rhtml +12 -0
  99. data/test/haml/rhtml/_av_partial_2.rhtml +8 -0
  100. data/test/haml/rhtml/action_view.rhtml +62 -0
  101. data/test/haml/rhtml/standard.rhtml +54 -0
  102. data/test/haml/spec_test.rb +44 -0
  103. data/test/haml/template_test.rb +217 -0
  104. data/test/haml/templates/_av_partial_1.haml +9 -0
  105. data/test/haml/templates/_av_partial_1_ugly.haml +9 -0
  106. data/test/haml/templates/_av_partial_2.haml +5 -0
  107. data/test/haml/templates/_av_partial_2_ugly.haml +5 -0
  108. data/test/haml/templates/_layout.erb +3 -0
  109. data/test/haml/templates/_layout_for_partial.haml +3 -0
  110. data/test/haml/templates/_partial.haml +8 -0
  111. data/test/haml/templates/_text_area.haml +3 -0
  112. data/test/haml/templates/action_view.haml +47 -0
  113. data/test/haml/templates/action_view_ugly.haml +47 -0
  114. data/test/haml/templates/breakage.haml +8 -0
  115. data/test/haml/templates/content_for_layout.haml +8 -0
  116. data/test/haml/templates/eval_suppressed.haml +11 -0
  117. data/test/haml/templates/filters.haml +66 -0
  118. data/test/haml/templates/helpers.haml +95 -0
  119. data/test/haml/templates/helpful.haml +11 -0
  120. data/test/haml/templates/just_stuff.haml +83 -0
  121. data/test/haml/templates/list.haml +12 -0
  122. data/test/haml/templates/nuke_inner_whitespace.haml +32 -0
  123. data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
  124. data/test/haml/templates/original_engine.haml +17 -0
  125. data/test/haml/templates/partial_layout.haml +3 -0
  126. data/test/haml/templates/partialize.haml +1 -0
  127. data/test/haml/templates/partials.haml +12 -0
  128. data/test/haml/templates/render_layout.haml +2 -0
  129. data/test/haml/templates/silent_script.haml +40 -0
  130. data/test/haml/templates/standard.haml +42 -0
  131. data/test/haml/templates/standard_ugly.haml +42 -0
  132. data/test/haml/templates/tag_parsing.haml +21 -0
  133. data/test/haml/templates/very_basic.haml +4 -0
  134. data/test/haml/templates/whitespace_handling.haml +87 -0
  135. data/test/haml/util_test.rb +92 -0
  136. data/test/linked_rails.rb +12 -0
  137. data/test/sass/css2sass_test.rb +294 -0
  138. data/test/sass/engine_test.rb +956 -0
  139. data/test/sass/functions_test.rb +126 -0
  140. data/test/sass/more_results/more1.css +9 -0
  141. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  142. data/test/sass/more_results/more_import.css +29 -0
  143. data/test/sass/more_templates/_more_partial.sass +2 -0
  144. data/test/sass/more_templates/more1.sass +23 -0
  145. data/test/sass/more_templates/more_import.sass +11 -0
  146. data/test/sass/plugin_test.rb +229 -0
  147. data/test/sass/results/alt.css +4 -0
  148. data/test/sass/results/basic.css +9 -0
  149. data/test/sass/results/compact.css +5 -0
  150. data/test/sass/results/complex.css +87 -0
  151. data/test/sass/results/compressed.css +1 -0
  152. data/test/sass/results/expanded.css +19 -0
  153. data/test/sass/results/import.css +29 -0
  154. data/test/sass/results/line_numbers.css +49 -0
  155. data/test/sass/results/mixins.css +95 -0
  156. data/test/sass/results/multiline.css +24 -0
  157. data/test/sass/results/nested.css +22 -0
  158. data/test/sass/results/parent_ref.css +13 -0
  159. data/test/sass/results/script.css +16 -0
  160. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  161. data/test/sass/results/subdir/subdir.css +3 -0
  162. data/test/sass/results/units.css +11 -0
  163. data/test/sass/script_test.rb +261 -0
  164. data/test/sass/templates/_partial.sass +2 -0
  165. data/test/sass/templates/alt.sass +16 -0
  166. data/test/sass/templates/basic.sass +23 -0
  167. data/test/sass/templates/bork1.sass +2 -0
  168. data/test/sass/templates/bork2.sass +2 -0
  169. data/test/sass/templates/bork3.sass +2 -0
  170. data/test/sass/templates/compact.sass +17 -0
  171. data/test/sass/templates/complex.sass +307 -0
  172. data/test/sass/templates/compressed.sass +15 -0
  173. data/test/sass/templates/expanded.sass +17 -0
  174. data/test/sass/templates/import.sass +11 -0
  175. data/test/sass/templates/importee.sass +19 -0
  176. data/test/sass/templates/line_numbers.sass +13 -0
  177. data/test/sass/templates/mixins.sass +76 -0
  178. data/test/sass/templates/multiline.sass +20 -0
  179. data/test/sass/templates/nested.sass +25 -0
  180. data/test/sass/templates/nested_bork1.sass +2 -0
  181. data/test/sass/templates/nested_bork2.sass +2 -0
  182. data/test/sass/templates/nested_bork3.sass +2 -0
  183. data/test/sass/templates/parent_ref.sass +25 -0
  184. data/test/sass/templates/script.sass +101 -0
  185. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  186. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  187. data/test/sass/templates/subdir/subdir.sass +6 -0
  188. data/test/sass/templates/units.sass +11 -0
  189. data/test/test_helper.rb +44 -0
  190. metadata +298 -0
@@ -0,0 +1,282 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../test_helper'
3
+ require 'haml/template'
4
+
5
+ class ActionView::Base
6
+ def nested_tag
7
+ content_tag(:span) {content_tag(:div) {"something"}}
8
+ end
9
+ end
10
+
11
+ module Haml::Helpers
12
+ def something_that_uses_haml_concat
13
+ haml_concat('foo').to_s
14
+ end
15
+ end
16
+
17
+ class HelperTest < Test::Unit::TestCase
18
+ Post = Struct.new('Post', :body)
19
+
20
+ def setup
21
+ @base = ActionView::Base.new
22
+ @base.controller = ActionController::Base.new
23
+
24
+ if defined?(ActionController::Response)
25
+ # This is needed for >=3.0.0
26
+ @base.controller.response = ActionController::Response.new
27
+ end
28
+
29
+ @base.instance_variable_set('@post', Post.new("Foo bar\nbaz"))
30
+ end
31
+
32
+ def render(text, options = {})
33
+ if options == :action_view
34
+ @base.render :inline => text, :type => :haml
35
+ else
36
+ scope = options.delete :scope_object
37
+ Haml::Engine.new(text, options).to_html(scope ? scope : Object.new)
38
+ end
39
+ end
40
+
41
+ def test_flatten
42
+ assert_equal("FooBar", Haml::Helpers.flatten("FooBar"))
43
+
44
+ assert_equal("FooBar", Haml::Helpers.flatten("Foo\rBar"))
45
+
46
+ assert_equal("Foo&#x000A;Bar", Haml::Helpers.flatten("Foo\nBar"))
47
+
48
+ assert_equal("Hello&#x000A;World!&#x000A;YOU ARE FLAT?&#x000A;OMGZ!",
49
+ Haml::Helpers.flatten("Hello\nWorld!\nYOU ARE \rFLAT?\n\rOMGZ!"))
50
+ end
51
+
52
+ def test_list_of_should_render_correctly
53
+ assert_equal("<li>1</li>\n<li>2</li>\n", render("= list_of([1, 2]) do |i|\n = i"))
54
+ assert_equal("<li>[1]</li>\n", render("= list_of([[1]]) do |i|\n = i.inspect"))
55
+ 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",
56
+ render("= list_of(['Fee', 'Fi', 'Fo', 'Fum']) do |title|\n %h1= title\n %p A word!"))
57
+ end
58
+
59
+ def test_buffer_access
60
+ assert(render("= buffer") =~ /#<Haml::Buffer:0x[a-z0-9]+>/)
61
+ assert_equal(render("= (buffer == _hamlout)"), "true\n")
62
+ end
63
+
64
+ def test_tabs
65
+ assert_equal("foo\n bar\nbaz\n", render("foo\n- tab_up\nbar\n- tab_down\nbaz"))
66
+ assert_equal(" <p>tabbed</p>\n", render("- buffer.tabulation=5\n%p tabbed"))
67
+ end
68
+
69
+ def test_helpers_dont_leak
70
+ # Haml helpers shouldn't be accessible from ERB
71
+ render("foo")
72
+ proper_behavior = false
73
+
74
+ begin
75
+ ActionView::Base.new.render(:inline => "<%= flatten('Foo\\nBar') %>")
76
+ rescue NoMethodError, ActionView::TemplateError
77
+ proper_behavior = true
78
+ end
79
+ assert(proper_behavior)
80
+
81
+ begin
82
+ ActionView::Base.new.render(:inline => "<%= concat('foo') %>")
83
+ rescue ArgumentError, NameError
84
+ proper_behavior = true
85
+ end
86
+ assert(proper_behavior)
87
+ end
88
+
89
+ def test_action_view_included
90
+ assert(Haml::Helpers.action_view?)
91
+ end
92
+
93
+ def test_form_tag
94
+ # This is usually provided by ActionController::Base.
95
+ def @base.protect_against_forgery?; false; end
96
+ result = render("- form_tag 'foo' do\n %p bar\n %strong baz", :action_view)
97
+ should_be = "<form action=\"foo\" method=\"post\">\n <p>bar</p>\n <strong>baz</strong>\n</form>\n"
98
+ assert_equal(should_be, result)
99
+ end
100
+
101
+ def test_text_area
102
+ assert_equal(%(<textarea id="body" name="body">Foo&#x000A;Bar&#x000A; Baz&#x000A; Boom</textarea>\n),
103
+ render('= text_area_tag "body", "Foo\nBar\n Baz\n Boom"', :action_view))
104
+
105
+ assert_equal(%(<textarea cols="40" id="post_body" name="post[body]" rows="20">Foo bar&#x000A;baz</textarea>\n),
106
+ render('= text_area :post, :body', :action_view))
107
+
108
+ assert_equal(%(<pre>Foo bar&#x000A; baz</pre>\n),
109
+ render('= content_tag "pre", "Foo bar\n baz"', :action_view))
110
+ end
111
+
112
+ def test_capture_haml
113
+ assert_equal("\"<p>13</p>\\n\"\n", render("- foo = capture_haml(13) do |a|\n %p= a\n= foo.dump"))
114
+ end
115
+
116
+ def test_content_tag_block
117
+ assert_equal(<<HTML.strip, render(<<HAML, :action_view))
118
+ <div><p>bar</p>
119
+ <strong>bar</strong>
120
+ </div>
121
+ HTML
122
+ - content_tag :div do
123
+ %p bar
124
+ %strong bar
125
+ HAML
126
+ end
127
+
128
+ def test_haml_tag_attribute_html_escaping
129
+ assert_equal("<p id='foo&amp;bar'>baz</p>\n", render("%p{:id => 'foo&bar'} baz", :escape_html => true))
130
+ end
131
+
132
+ def test_haml_tag_autoclosed_tags_are_closed
133
+ assert_equal("<br class='foo' />\n", render("- haml_tag :br, :class => 'foo'"))
134
+ end
135
+
136
+ def test_haml_tag_non_autoclosed_tags_arent_closed
137
+ assert_equal("<p></p>\n", render("- haml_tag :p"))
138
+ end
139
+
140
+ def test_haml_tag_renders_text_on_a_single_line
141
+ assert_equal("<p>#{'a' * 100}</p>\n", render("- haml_tag :p, 'a' * 100"))
142
+ end
143
+
144
+ def test_haml_tag_raises_error_for_multiple_content
145
+ assert_raise(Haml::Error) { render("- haml_tag :p, 'foo' do\n bar") }
146
+ end
147
+
148
+ def test_haml_tag_flags
149
+ assert_equal("<p />\n", render("- haml_tag :p, :/"))
150
+ assert_equal("<p>kumquat</p>\n", render("- haml_tag :p, :< do\n kumquat"))
151
+
152
+ assert_raise(Haml::Error) { render("- haml_tag :p, 'foo', :/") }
153
+ assert_raise(Haml::Error) { render("- haml_tag :p, :/ do\n foo") }
154
+ end
155
+
156
+ def test_haml_tag_error_return
157
+ assert_raise(Haml::Error) { render("= haml_tag :p") }
158
+ end
159
+
160
+ def test_is_haml
161
+ assert(!ActionView::Base.new.is_haml?)
162
+ assert_equal("true\n", render("= is_haml?"))
163
+ assert_equal("true\n", render("= is_haml?", :action_view))
164
+ assert_equal("false", @base.render(:inline => '<%= is_haml? %>'))
165
+ assert_equal("false\n", render("= render :inline => '<%= is_haml? %>'", :action_view))
166
+ end
167
+
168
+ def test_page_class
169
+ controller = Struct.new(:controller_name, :action_name).new('troller', 'tion')
170
+ scope = Struct.new(:controller).new(controller)
171
+ result = render("%div{:class => page_class} MyDiv", :scope_object => scope)
172
+ expected = "<div class='troller tion'>MyDiv</div>\n"
173
+ assert_equal expected, result
174
+ end
175
+
176
+ def test_indented_capture
177
+ assert_equal(" \n Foo\n ", @base.render(:inline => " <% res = capture do %>\n Foo\n <% end %><%= res %>"))
178
+ end
179
+
180
+ def test_capture_deals_properly_with_collections
181
+ Haml::Helpers.module_eval do
182
+ def trc(collection, &block)
183
+ collection.each do |record|
184
+ haml_concat capture_haml(record, &block)
185
+ end
186
+ end
187
+ end
188
+
189
+ assert_equal("1\n\n2\n\n3\n\n", render("- trc([1, 2, 3]) do |i|\n = i.inspect"))
190
+ end
191
+
192
+ def test_find_and_preserve_with_block
193
+ assert_equal("<pre>Foo&#x000A;Bar</pre>\nFoo\nBar\n",
194
+ render("= find_and_preserve do\n %pre\n Foo\n Bar\n Foo\n Bar"))
195
+ end
196
+
197
+ def test_find_and_preserve_with_block_and_tags
198
+ assert_equal("<pre>Foo\nBar</pre>\nFoo\nBar\n",
199
+ render("= find_and_preserve([]) do\n %pre\n Foo\n Bar\n Foo\n Bar"))
200
+ end
201
+
202
+ def test_preserve_with_block
203
+ assert_equal("<pre>Foo&#x000A;Bar</pre>&#x000A;Foo&#x000A;Bar\n",
204
+ render("= preserve do\n %pre\n Foo\n Bar\n Foo\n Bar"))
205
+ end
206
+
207
+ def test_init_haml_helpers
208
+ context = Object.new
209
+ class << context
210
+ include Haml::Helpers
211
+ end
212
+ context.init_haml_helpers
213
+
214
+ result = context.capture_haml do
215
+ context.haml_tag :p, :attr => "val" do
216
+ context.haml_concat "Blah"
217
+ end
218
+ end
219
+
220
+ assert_equal("<p attr='val'>\n Blah\n</p>\n", result)
221
+ end
222
+
223
+ def test_non_haml
224
+ assert_equal("false\n", render("= non_haml { is_haml? }"))
225
+ end
226
+
227
+ def test_content_tag_nested
228
+ assert_equal "<span><div>something</div></span>", render("= nested_tag", :action_view).strip
229
+ end
230
+
231
+ def test_error_return
232
+ assert_raise(Haml::Error, <<MESSAGE) {render("= haml_concat 'foo'")}
233
+ haml_concat outputs directly to the Haml template.
234
+ Disregard its return value and use the - operator,
235
+ or use capture_haml to get the value as a String.
236
+ MESSAGE
237
+ end
238
+
239
+ def test_error_return_line
240
+ render("%p foo\n= haml_concat 'foo'\n%p bar")
241
+ assert false, "Expected Haml::Error"
242
+ rescue Haml::Error => e
243
+ assert_equal 2, e.backtrace[0].scan(/:(\d+)/).first.first.to_i
244
+ end
245
+
246
+ def test_error_return_line_in_helper
247
+ render("- something_that_uses_haml_concat")
248
+ assert false, "Expected Haml::Error"
249
+ rescue Haml::Error => e
250
+ assert_equal 13, e.backtrace[0].scan(/:(\d+)/).first.first.to_i
251
+ end
252
+
253
+ class ActsLikeTag
254
+ # We want to be able to have people include monkeypatched ActionView helpers
255
+ # without redefining is_haml?.
256
+ # This is accomplished via Object#is_haml?, and this is a test for it.
257
+ include ActionView::Helpers::TagHelper
258
+ def to_s
259
+ content_tag :p, 'some tag content'
260
+ end
261
+ end
262
+
263
+ def test_random_class_includes_tag_helper
264
+ assert_equal "<p>some tag content</p>", ActsLikeTag.new.to_s
265
+ end
266
+
267
+ def test_capture_with_nuke_outer
268
+ assert_equal "<div></div>\n*<div>hi there!</div>\n", render(<<HAML)
269
+ %div
270
+ = precede("*") do
271
+ %div> hi there!
272
+ HAML
273
+
274
+ assert_equal "<div></div>\n*<div>hi there!</div>\n", render(<<HAML)
275
+ %div
276
+ = precede("*") do
277
+ = " "
278
+ %div> hi there!
279
+ HAML
280
+ end
281
+ end
282
+
@@ -0,0 +1,258 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../test_helper'
3
+ require 'haml/html'
4
+
5
+ class Html2HamlTest < Test::Unit::TestCase
6
+
7
+ def test_empty_render_should_remain_empty
8
+ assert_equal '', render('')
9
+ end
10
+
11
+ def test_id_and_class_should_be_removed_from_hash
12
+ assert_equal '%span#foo.bar', render('<span id="foo" class="bar"> </span>')
13
+ end
14
+
15
+ def test_no_tag_name_for_div_if_class_or_id_is_present
16
+ assert_equal '#foo', render('<div id="foo"> </div>')
17
+ assert_equal '.foo', render('<div class="foo"> </div>')
18
+ end
19
+
20
+ def test_multiple_class_names
21
+ assert_equal '.foo.bar.baz', render('<div class=" foo bar baz "> </div>')
22
+ end
23
+
24
+ def test_should_have_pretty_attributes
25
+ assert_equal_attributes('%input{ :type => "text", :name => "login" }',
26
+ render('<input type="text" name="login" />'))
27
+ assert_equal_attributes('%meta{ "http-equiv" => "Content-Type", :content => "text/html" }',
28
+ render('<meta http-equiv="Content-Type" content="text/html" />'))
29
+ end
30
+
31
+ def test_sqml_comment
32
+ assert_equal "/\n IE sucks", render('<!-- IE sucks -->')
33
+ end
34
+
35
+ def test_rhtml
36
+ assert_equal '- foo = bar', render_rhtml('<% foo = bar %>')
37
+ assert_equal '- foo = bar', render_rhtml('<% foo = bar -%>')
38
+ assert_equal '= h @item.title', render_rhtml('<%=h @item.title %>')
39
+ assert_equal '= h @item.title', render_rhtml('<%=h @item.title -%>')
40
+ end
41
+
42
+ def test_rhtml_with_html_special_chars
43
+ assert_equal '= 3 < 5 ? "OK" : "Your computer is b0rken"',
44
+ render_rhtml(%Q{<%= 3 < 5 ? "OK" : "Your computer is b0rken" %>})
45
+ end
46
+
47
+ def test_rhtml_in_class_attribute
48
+ assert_equal "%div{ :class => dyna_class }\n I have a dynamic attribute",
49
+ render_rhtml(%Q{<div class="<%= dyna_class %>">I have a dynamic attribute</div>})
50
+ end
51
+
52
+ def test_rhtml_in_id_attribute
53
+ assert_equal "%div{ :id => dyna_id }\n I have a dynamic attribute",
54
+ render_rhtml(%Q{<div id="<%= dyna_id %>">I have a dynamic attribute</div>})
55
+ end
56
+
57
+ def test_rhtml_in_attribute_results_in_string_interpolation
58
+ assert_equal %(%div{ :id => "item_\#{i}" }\n Ruby string interpolation FTW),
59
+ render_rhtml(%Q{<div id="item_<%= i %>">Ruby string interpolation FTW</div>})
60
+ end
61
+
62
+ def test_rhtml_in_attribute_with_trailing_content
63
+ assert_equal %(%div{ :class => "\#{12}!" }\n Bang!),
64
+ render_rhtml(%Q{<div class="<%= 12 %>!">Bang!</div>})
65
+ end
66
+
67
+ def test_rhtml_in_attribute_to_multiple_interpolations
68
+ assert_equal %(%div{ :class => "\#{12} + \#{13}" }\n Math is super),
69
+ render_rhtml(%Q{<div class="<%= 12 %> + <%= 13 %>">Math is super</div>})
70
+ end
71
+
72
+ def test_whitespace_eating_erb_tags
73
+ assert_equal %(- form_for),
74
+ render_rhtml(%Q{<%- form_for -%>})
75
+ end
76
+
77
+ def test_blocks_and_consuming_end_tags
78
+ html = <<-HTML.gsub(/^ /, '')
79
+ <% if @post %>
80
+ <% @post.comments.each do |comment| -%>
81
+ <p><%= comment.name %></p>
82
+ <% end -%>
83
+ <% end %>
84
+ HTML
85
+ expected = <<-EOS.gsub(/^ /, '').strip
86
+ - if @post
87
+ - @post.comments.each do |comment|
88
+ %p
89
+ = comment.name
90
+ EOS
91
+ assert_equal expected, render_rhtml(html)
92
+ end
93
+
94
+ def test_advanced_template
95
+ html = <<-HTML.gsub(/^ /, '')
96
+ <%
97
+ date = Date.today
98
+ date = date.to_s
99
+ %>
100
+ <% if @post %>
101
+ <p><%= "only do for each comment" %></p>
102
+ <p>- Don't chomp minus -</p>
103
+ <p class="class_name" id="foo" other_attribute="value">
104
+ This
105
+ is
106
+ multiline
107
+ HTML text
108
+ </p>
109
+ <%= @post.comments.map do |comment|
110
+ comment.name
111
+ end.join("\\n") %>
112
+ <% @post.comments.each do |comment| -%>
113
+ <p><%= "for inside each comment do something" %></p>
114
+ <% end -%>
115
+ <% end %>
116
+ HTML
117
+
118
+ # The 'extra' space on the 'end.join("\\n")' is meant to
119
+ # be there since the escape makes it one character less
120
+ expected = <<-EOS.gsub(/^ /, '').strip
121
+ - date = Date.today
122
+ - date = date.to_s
123
+ - if @post
124
+ %p
125
+ = "only do for each comment"
126
+ %p
127
+ \\- Don't chomp minus -
128
+ %p#foo.class_name{ :other_attribute => "value" }
129
+ This
130
+ is
131
+ multiline
132
+ HTML text
133
+ = @post.comments.map do |comment| |
134
+ comment.name |
135
+ end.join("\\n") |
136
+ - @post.comments.each do |comment|
137
+ %p
138
+ = "for inside each comment do something"
139
+ EOS
140
+ assert_equal expected, render_rhtml(html)
141
+ end
142
+
143
+ def test_content_for_block
144
+ html = <<-HTML.gsub(/^ /, '')
145
+ <% content_for :header do %>
146
+ My Header
147
+ <% end %>
148
+ <% content_for :account do -%>
149
+ Logged as <a href="#" title="Admin">Admin</a> (<a href="#" title="Logout">logout</a>)
150
+ <% end -%>
151
+ <% content_for :footer do %>
152
+ My Footer
153
+ <% end %>
154
+ HTML
155
+ expected = <<-RUBY.gsub(/^ /, '').strip
156
+ - content_for :header do
157
+ My Header
158
+ - content_for :account do
159
+ Logged as
160
+ %a{ :href => "#", :title => "Admin" }
161
+ Admin
162
+ (
163
+ %a{ :href => "#", :title => "Logout" }
164
+ logout
165
+ )
166
+ - content_for :footer do
167
+ My Footer
168
+ RUBY
169
+ assert_equal expected, render_rhtml(html)
170
+ end
171
+
172
+ def test_intermediate_format_with_loud_and_silent_tags
173
+ html = <<-HTML.gsub(/^ /, '')
174
+ <p>Hi there</p>
175
+ <haml:silent>
176
+ if @post
177
+ <haml:block>
178
+ <haml:loud>@post.title</haml:loud>
179
+ </haml:block>
180
+ else
181
+ <haml:block>
182
+ <haml:loud>"Unknown"</haml:loud>
183
+ </haml:block>
184
+ </haml:silent>
185
+ <haml:silent> content_for :header do
186
+ <haml:block>My Header</haml:block>
187
+ </haml:silent>
188
+ <p>Goodbye</p>
189
+ HTML
190
+ expected = <<-HAML.gsub(/^ /, '').strip
191
+ %p
192
+ Hi there
193
+ - if @post
194
+ = @post.title
195
+ - else
196
+ = "Unknown"
197
+ - content_for :header do
198
+ My Header
199
+ %p
200
+ Goodbye
201
+ HAML
202
+ assert_equal expected, render_rhtml(html)
203
+ end
204
+
205
+ def test_cdata
206
+ assert_equal(<<HAML.strip, render(<<HTML))
207
+ %p
208
+ :cdata
209
+ <a foo="bar" baz="bang">
210
+ <div id="foo">flop</div>
211
+ </a>
212
+ HAML
213
+ <p><![CDATA[
214
+ <a foo="bar" baz="bang">
215
+ <div id="foo">flop</div>
216
+ </a>
217
+ ]]></p>
218
+ HTML
219
+ end
220
+
221
+ # Encodings
222
+
223
+ unless Haml::Util.ruby1_8?
224
+ def test_encoding_error
225
+ render("foo\nbar\nb\xFEaz".force_encoding("utf-8"))
226
+ assert(false, "Expected exception")
227
+ rescue Haml::Error => e
228
+ assert_equal(3, e.line)
229
+ assert_equal('Invalid UTF-8 character "\xFE"', e.message)
230
+ end
231
+
232
+ def test_ascii_incompatible_encoding_error
233
+ template = "foo\nbar\nb_z".encode("utf-16le")
234
+ template[9] = "\xFE".force_encoding("utf-16le")
235
+ render(template)
236
+ assert(false, "Expected exception")
237
+ rescue Haml::Error => e
238
+ assert_equal(3, e.line)
239
+ assert_equal('Invalid UTF-16LE character "\xFE"', e.message)
240
+ end
241
+ end
242
+
243
+ protected
244
+
245
+ def render(text, options = {})
246
+ Haml::HTML.new(text, options).render.rstrip
247
+ end
248
+
249
+ def render_rhtml(text)
250
+ render(text, :rhtml => true)
251
+ end
252
+
253
+ def assert_equal_attributes(expected, result)
254
+ expected_attr, result_attr = [expected, result].map { |s| s.gsub!(/\{ (.+) \}/, ''); $1.split(', ').sort }
255
+ assert_equal expected_attr, result_attr
256
+ assert_equal expected, result
257
+ end
258
+ end