haml_ejs 0.0.1

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 (358) hide show
  1. data/.yardopts +11 -0
  2. data/CONTRIBUTING +3 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +68 -0
  5. data/Rakefile +419 -0
  6. data/VERSION +1 -0
  7. data/VERSION_NAME +1 -0
  8. data/bin/haml +9 -0
  9. data/bin/html2haml +7 -0
  10. data/extra/update_watch.rb +13 -0
  11. data/init.rb +18 -0
  12. data/lib/haml.rb +49 -0
  13. data/lib/haml/buffer.rb +297 -0
  14. data/lib/haml/compiler.rb +486 -0
  15. data/lib/haml/engine.rb +312 -0
  16. data/lib/haml/error.rb +22 -0
  17. data/lib/haml/exec.rb +362 -0
  18. data/lib/haml/filters.rb +388 -0
  19. data/lib/haml/haml_ejs.rb +57 -0
  20. data/lib/haml/helpers.rb +608 -0
  21. data/lib/haml/helpers/action_view_extensions.rb +57 -0
  22. data/lib/haml/helpers/action_view_mods.rb +257 -0
  23. data/lib/haml/helpers/xss_mods.rb +165 -0
  24. data/lib/haml/html.rb +412 -0
  25. data/lib/haml/html/erb.rb +141 -0
  26. data/lib/haml/parser.rb +760 -0
  27. data/lib/haml/railtie.rb +19 -0
  28. data/lib/haml/root.rb +7 -0
  29. data/lib/haml/shared.rb +78 -0
  30. data/lib/haml/template.rb +99 -0
  31. data/lib/haml/template/options.rb +16 -0
  32. data/lib/haml/template/patch.rb +58 -0
  33. data/lib/haml/template/plugin.rb +123 -0
  34. data/lib/haml/util.rb +842 -0
  35. data/lib/haml/version.rb +109 -0
  36. data/lib/sass.rb +8 -0
  37. data/lib/sass/plugin.rb +10 -0
  38. data/lib/sass/rails2_shim.rb +9 -0
  39. data/lib/sass/rails3_shim.rb +16 -0
  40. data/rails/init.rb +1 -0
  41. data/test/benchmark.rb +91 -0
  42. data/test/gemfiles/Gemfile.rails-2.0.x +8 -0
  43. data/test/gemfiles/Gemfile.rails-2.0.x.lock +38 -0
  44. data/test/gemfiles/Gemfile.rails-2.1.x +8 -0
  45. data/test/gemfiles/Gemfile.rails-2.1.x.lock +38 -0
  46. data/test/gemfiles/Gemfile.rails-2.2.x +8 -0
  47. data/test/gemfiles/Gemfile.rails-2.2.x.lock +38 -0
  48. data/test/gemfiles/Gemfile.rails-2.3.x +8 -0
  49. data/test/gemfiles/Gemfile.rails-2.3.x.lock +40 -0
  50. data/test/gemfiles/Gemfile.rails-3.0.x +8 -0
  51. data/test/gemfiles/Gemfile.rails-3.0.x.lock +85 -0
  52. data/test/gemfiles/Gemfile.rails-3.1.x +8 -0
  53. data/test/gemfiles/Gemfile.rails-3.1.x.lock +98 -0
  54. data/test/gemfiles/Gemfile.rails-xss-2.3.x +9 -0
  55. data/test/gemfiles/Gemfile.rails-xss-2.3.x.lock +42 -0
  56. data/test/haml-ejs/haml-ejs_test.rb +22 -0
  57. data/test/haml-ejs/templates/conditional.input +3 -0
  58. data/test/haml-ejs/templates/conditional.output +3 -0
  59. data/test/haml-ejs/templates/conditional_and_interpolation.input +2 -0
  60. data/test/haml-ejs/templates/conditional_and_interpolation.output +3 -0
  61. data/test/haml-ejs/templates/conditional_else.input +5 -0
  62. data/test/haml-ejs/templates/conditional_else.output +5 -0
  63. data/test/haml-ejs/templates/conditional_else_elsif.input +7 -0
  64. data/test/haml-ejs/templates/conditional_else_elsif.output +7 -0
  65. data/test/haml-ejs/templates/conditional_elsif.input +5 -0
  66. data/test/haml-ejs/templates/conditional_elsif.output +5 -0
  67. data/test/haml-ejs/templates/conditional_unless.input +3 -0
  68. data/test/haml-ejs/templates/conditional_unless.output +3 -0
  69. data/test/haml-ejs/templates/conditional_unless_else.input +5 -0
  70. data/test/haml-ejs/templates/conditional_unless_else.output +5 -0
  71. data/test/haml-ejs/templates/conditional_unless_elsif_else.input +5 -0
  72. data/test/haml-ejs/templates/conditional_unless_elsif_else.output +5 -0
  73. data/test/haml-ejs/templates/interpolation.input +2 -0
  74. data/test/haml-ejs/templates/interpolation.output +1 -0
  75. data/test/haml-ejs/templates/iteration.input +2 -0
  76. data/test/haml-ejs/templates/iteration.output +3 -0
  77. data/test/haml-ejs/templates/suite.input +26 -0
  78. data/test/haml-ejs/templates/suite.output +27 -0
  79. data/test/haml/engine_test.rb +1925 -0
  80. data/test/haml/erb/_av_partial_1.erb +12 -0
  81. data/test/haml/erb/_av_partial_2.erb +8 -0
  82. data/test/haml/erb/action_view.erb +62 -0
  83. data/test/haml/erb/standard.erb +55 -0
  84. data/test/haml/helper_test.rb +454 -0
  85. data/test/haml/html2haml/erb_tests.rb +440 -0
  86. data/test/haml/html2haml_test.rb +336 -0
  87. data/test/haml/markaby/standard.mab +52 -0
  88. data/test/haml/mocks/article.rb +6 -0
  89. data/test/haml/results/content_for_layout.xhtml +12 -0
  90. data/test/haml/results/eval_suppressed.xhtml +9 -0
  91. data/test/haml/results/filters.xhtml +62 -0
  92. data/test/haml/results/helpers.xhtml +70 -0
  93. data/test/haml/results/helpful.xhtml +10 -0
  94. data/test/haml/results/just_stuff.xhtml +70 -0
  95. data/test/haml/results/list.xhtml +12 -0
  96. data/test/haml/results/nuke_inner_whitespace.xhtml +40 -0
  97. data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
  98. data/test/haml/results/original_engine.xhtml +20 -0
  99. data/test/haml/results/partial_layout.xhtml +5 -0
  100. data/test/haml/results/partials.xhtml +21 -0
  101. data/test/haml/results/render_layout.xhtml +3 -0
  102. data/test/haml/results/silent_script.xhtml +74 -0
  103. data/test/haml/results/standard.xhtml +162 -0
  104. data/test/haml/results/tag_parsing.xhtml +23 -0
  105. data/test/haml/results/very_basic.xhtml +5 -0
  106. data/test/haml/results/whitespace_handling.xhtml +89 -0
  107. data/test/haml/spec/README.md +97 -0
  108. data/test/haml/spec/lua_haml_spec.lua +30 -0
  109. data/test/haml/spec/ruby_haml_test.rb +19 -0
  110. data/test/haml/spec/tests.json +534 -0
  111. data/test/haml/spec_test.rb +44 -0
  112. data/test/haml/template_test.rb +419 -0
  113. data/test/haml/templates/_av_partial_1.haml +9 -0
  114. data/test/haml/templates/_av_partial_1_ugly.haml +9 -0
  115. data/test/haml/templates/_av_partial_2.haml +5 -0
  116. data/test/haml/templates/_av_partial_2_ugly.haml +5 -0
  117. data/test/haml/templates/_layout.erb +3 -0
  118. data/test/haml/templates/_layout_for_partial.haml +3 -0
  119. data/test/haml/templates/_partial.haml +8 -0
  120. data/test/haml/templates/_text_area.haml +3 -0
  121. data/test/haml/templates/action_view.haml +47 -0
  122. data/test/haml/templates/action_view_ugly.haml +47 -0
  123. data/test/haml/templates/breakage.haml +8 -0
  124. data/test/haml/templates/content_for_layout.haml +8 -0
  125. data/test/haml/templates/eval_suppressed.haml +11 -0
  126. data/test/haml/templates/filters.haml +66 -0
  127. data/test/haml/templates/helpers.haml +55 -0
  128. data/test/haml/templates/helpful.haml +11 -0
  129. data/test/haml/templates/just_stuff.haml +85 -0
  130. data/test/haml/templates/list.haml +12 -0
  131. data/test/haml/templates/nuke_inner_whitespace.haml +32 -0
  132. data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
  133. data/test/haml/templates/original_engine.haml +17 -0
  134. data/test/haml/templates/partial_layout.haml +10 -0
  135. data/test/haml/templates/partialize.haml +1 -0
  136. data/test/haml/templates/partials.haml +12 -0
  137. data/test/haml/templates/render_layout.haml +2 -0
  138. data/test/haml/templates/silent_script.haml +40 -0
  139. data/test/haml/templates/standard.haml +43 -0
  140. data/test/haml/templates/standard_ugly.haml +43 -0
  141. data/test/haml/templates/tag_parsing.haml +21 -0
  142. data/test/haml/templates/very_basic.haml +4 -0
  143. data/test/haml/templates/whitespace_handling.haml +87 -0
  144. data/test/haml/util_test.rb +300 -0
  145. data/test/linked_rails.rb +42 -0
  146. data/test/test_helper.rb +75 -0
  147. data/vendor/sass/CONTRIBUTING +3 -0
  148. data/vendor/sass/MIT-LICENSE +20 -0
  149. data/vendor/sass/README.md +201 -0
  150. data/vendor/sass/Rakefile +339 -0
  151. data/vendor/sass/TODO +39 -0
  152. data/vendor/sass/VERSION +1 -0
  153. data/vendor/sass/VERSION_NAME +1 -0
  154. data/vendor/sass/bin/sass +8 -0
  155. data/vendor/sass/bin/sass-convert +7 -0
  156. data/vendor/sass/bin/scss +8 -0
  157. data/vendor/sass/doc-src/FAQ.md +35 -0
  158. data/vendor/sass/doc-src/INDENTED_SYNTAX.md +210 -0
  159. data/vendor/sass/doc-src/SASS_CHANGELOG.md +2214 -0
  160. data/vendor/sass/doc-src/SASS_REFERENCE.md +1957 -0
  161. data/vendor/sass/doc-src/SCSS_FOR_SASS_USERS.md +155 -0
  162. data/vendor/sass/ext/extconf.rb +10 -0
  163. data/vendor/sass/extra/update_watch.rb +13 -0
  164. data/vendor/sass/init.rb +18 -0
  165. data/vendor/sass/lib/sass.rb +72 -0
  166. data/vendor/sass/lib/sass/cache_stores.rb +15 -0
  167. data/vendor/sass/lib/sass/cache_stores/base.rb +84 -0
  168. data/vendor/sass/lib/sass/cache_stores/chain.rb +33 -0
  169. data/vendor/sass/lib/sass/cache_stores/filesystem.rb +58 -0
  170. data/vendor/sass/lib/sass/cache_stores/memory.rb +47 -0
  171. data/vendor/sass/lib/sass/cache_stores/null.rb +25 -0
  172. data/vendor/sass/lib/sass/callbacks.rb +66 -0
  173. data/vendor/sass/lib/sass/css.rb +294 -0
  174. data/vendor/sass/lib/sass/engine.rb +862 -0
  175. data/vendor/sass/lib/sass/environment.rb +155 -0
  176. data/vendor/sass/lib/sass/error.rb +201 -0
  177. data/vendor/sass/lib/sass/exec.rb +659 -0
  178. data/vendor/sass/lib/sass/importers.rb +22 -0
  179. data/vendor/sass/lib/sass/importers/base.rb +138 -0
  180. data/vendor/sass/lib/sass/importers/filesystem.rb +144 -0
  181. data/vendor/sass/lib/sass/less.rb +382 -0
  182. data/vendor/sass/lib/sass/plugin.rb +136 -0
  183. data/vendor/sass/lib/sass/plugin/compiler.rb +358 -0
  184. data/vendor/sass/lib/sass/plugin/configuration.rb +125 -0
  185. data/vendor/sass/lib/sass/plugin/generic.rb +15 -0
  186. data/vendor/sass/lib/sass/plugin/merb.rb +48 -0
  187. data/vendor/sass/lib/sass/plugin/rack.rb +60 -0
  188. data/vendor/sass/lib/sass/plugin/rails.rb +47 -0
  189. data/vendor/sass/lib/sass/plugin/staleness_checker.rb +173 -0
  190. data/vendor/sass/lib/sass/railtie.rb +9 -0
  191. data/vendor/sass/lib/sass/repl.rb +58 -0
  192. data/vendor/sass/lib/sass/root.rb +7 -0
  193. data/vendor/sass/lib/sass/script.rb +40 -0
  194. data/vendor/sass/lib/sass/script/bool.rb +18 -0
  195. data/vendor/sass/lib/sass/script/color.rb +480 -0
  196. data/vendor/sass/lib/sass/script/css_lexer.rb +29 -0
  197. data/vendor/sass/lib/sass/script/css_parser.rb +31 -0
  198. data/vendor/sass/lib/sass/script/funcall.rb +162 -0
  199. data/vendor/sass/lib/sass/script/functions.rb +1343 -0
  200. data/vendor/sass/lib/sass/script/interpolation.rb +70 -0
  201. data/vendor/sass/lib/sass/script/lexer.rb +334 -0
  202. data/vendor/sass/lib/sass/script/list.rb +76 -0
  203. data/vendor/sass/lib/sass/script/literal.rb +245 -0
  204. data/vendor/sass/lib/sass/script/node.rb +91 -0
  205. data/vendor/sass/lib/sass/script/number.rb +429 -0
  206. data/vendor/sass/lib/sass/script/operation.rb +91 -0
  207. data/vendor/sass/lib/sass/script/parser.rb +467 -0
  208. data/vendor/sass/lib/sass/script/string.rb +51 -0
  209. data/vendor/sass/lib/sass/script/string_interpolation.rb +94 -0
  210. data/vendor/sass/lib/sass/script/unary_operation.rb +57 -0
  211. data/vendor/sass/lib/sass/script/variable.rb +54 -0
  212. data/vendor/sass/lib/sass/scss.rb +17 -0
  213. data/vendor/sass/lib/sass/scss/css_parser.rb +46 -0
  214. data/vendor/sass/lib/sass/scss/parser.rb +920 -0
  215. data/vendor/sass/lib/sass/scss/rx.rb +127 -0
  216. data/vendor/sass/lib/sass/scss/sass_parser.rb +11 -0
  217. data/vendor/sass/lib/sass/scss/script_lexer.rb +15 -0
  218. data/vendor/sass/lib/sass/scss/script_parser.rb +25 -0
  219. data/vendor/sass/lib/sass/scss/static_parser.rb +40 -0
  220. data/vendor/sass/lib/sass/selector.rb +361 -0
  221. data/vendor/sass/lib/sass/selector/abstract_sequence.rb +62 -0
  222. data/vendor/sass/lib/sass/selector/comma_sequence.rb +81 -0
  223. data/vendor/sass/lib/sass/selector/sequence.rb +233 -0
  224. data/vendor/sass/lib/sass/selector/simple.rb +113 -0
  225. data/vendor/sass/lib/sass/selector/simple_sequence.rb +134 -0
  226. data/vendor/sass/lib/sass/shared.rb +78 -0
  227. data/vendor/sass/lib/sass/tree/charset_node.rb +22 -0
  228. data/vendor/sass/lib/sass/tree/comment_node.rb +77 -0
  229. data/vendor/sass/lib/sass/tree/debug_node.rb +18 -0
  230. data/vendor/sass/lib/sass/tree/directive_node.rb +23 -0
  231. data/vendor/sass/lib/sass/tree/each_node.rb +24 -0
  232. data/vendor/sass/lib/sass/tree/extend_node.rb +29 -0
  233. data/vendor/sass/lib/sass/tree/for_node.rb +36 -0
  234. data/vendor/sass/lib/sass/tree/function_node.rb +27 -0
  235. data/vendor/sass/lib/sass/tree/if_node.rb +65 -0
  236. data/vendor/sass/lib/sass/tree/import_node.rb +68 -0
  237. data/vendor/sass/lib/sass/tree/media_node.rb +32 -0
  238. data/vendor/sass/lib/sass/tree/mixin_def_node.rb +27 -0
  239. data/vendor/sass/lib/sass/tree/mixin_node.rb +32 -0
  240. data/vendor/sass/lib/sass/tree/node.rb +204 -0
  241. data/vendor/sass/lib/sass/tree/prop_node.rb +155 -0
  242. data/vendor/sass/lib/sass/tree/return_node.rb +18 -0
  243. data/vendor/sass/lib/sass/tree/root_node.rb +28 -0
  244. data/vendor/sass/lib/sass/tree/rule_node.rb +129 -0
  245. data/vendor/sass/lib/sass/tree/variable_node.rb +30 -0
  246. data/vendor/sass/lib/sass/tree/visitors/base.rb +75 -0
  247. data/vendor/sass/lib/sass/tree/visitors/check_nesting.rb +134 -0
  248. data/vendor/sass/lib/sass/tree/visitors/convert.rb +255 -0
  249. data/vendor/sass/lib/sass/tree/visitors/cssize.rb +175 -0
  250. data/vendor/sass/lib/sass/tree/visitors/perform.rb +301 -0
  251. data/vendor/sass/lib/sass/tree/visitors/to_css.rb +216 -0
  252. data/vendor/sass/lib/sass/tree/warn_node.rb +18 -0
  253. data/vendor/sass/lib/sass/tree/while_node.rb +18 -0
  254. data/vendor/sass/lib/sass/util.rb +669 -0
  255. data/vendor/sass/lib/sass/util/subset_map.rb +101 -0
  256. data/vendor/sass/lib/sass/version.rb +112 -0
  257. data/vendor/sass/rails/init.rb +1 -0
  258. data/vendor/sass/sass.gemspec +32 -0
  259. data/vendor/sass/test/sass/cache_test.rb +74 -0
  260. data/vendor/sass/test/sass/callbacks_test.rb +61 -0
  261. data/vendor/sass/test/sass/conversion_test.rb +1203 -0
  262. data/vendor/sass/test/sass/css2sass_test.rb +364 -0
  263. data/vendor/sass/test/sass/data/hsl-rgb.txt +319 -0
  264. data/vendor/sass/test/sass/engine_test.rb +2469 -0
  265. data/vendor/sass/test/sass/extend_test.rb +1348 -0
  266. data/vendor/sass/test/sass/functions_test.rb +1025 -0
  267. data/vendor/sass/test/sass/importer_test.rb +82 -0
  268. data/vendor/sass/test/sass/less_conversion_test.rb +653 -0
  269. data/vendor/sass/test/sass/mock_importer.rb +49 -0
  270. data/vendor/sass/test/sass/more_results/more1.css +9 -0
  271. data/vendor/sass/test/sass/more_results/more1_with_line_comments.css +26 -0
  272. data/vendor/sass/test/sass/more_results/more_import.css +29 -0
  273. data/vendor/sass/test/sass/more_templates/_more_partial.sass +2 -0
  274. data/vendor/sass/test/sass/more_templates/more1.sass +23 -0
  275. data/vendor/sass/test/sass/more_templates/more_import.sass +11 -0
  276. data/vendor/sass/test/sass/plugin_test.rb +469 -0
  277. data/vendor/sass/test/sass/results/alt.css +4 -0
  278. data/vendor/sass/test/sass/results/basic.css +9 -0
  279. data/vendor/sass/test/sass/results/compact.css +5 -0
  280. data/vendor/sass/test/sass/results/complex.css +86 -0
  281. data/vendor/sass/test/sass/results/compressed.css +1 -0
  282. data/vendor/sass/test/sass/results/expanded.css +19 -0
  283. data/vendor/sass/test/sass/results/if.css +3 -0
  284. data/vendor/sass/test/sass/results/import.css +31 -0
  285. data/vendor/sass/test/sass/results/import_charset.css +4 -0
  286. data/vendor/sass/test/sass/results/import_charset_1_8.css +4 -0
  287. data/vendor/sass/test/sass/results/import_charset_ibm866.css +4 -0
  288. data/vendor/sass/test/sass/results/line_numbers.css +49 -0
  289. data/vendor/sass/test/sass/results/mixins.css +95 -0
  290. data/vendor/sass/test/sass/results/multiline.css +24 -0
  291. data/vendor/sass/test/sass/results/nested.css +22 -0
  292. data/vendor/sass/test/sass/results/options.css +1 -0
  293. data/vendor/sass/test/sass/results/parent_ref.css +13 -0
  294. data/vendor/sass/test/sass/results/script.css +16 -0
  295. data/vendor/sass/test/sass/results/scss_import.css +31 -0
  296. data/vendor/sass/test/sass/results/scss_importee.css +2 -0
  297. data/vendor/sass/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  298. data/vendor/sass/test/sass/results/subdir/subdir.css +3 -0
  299. data/vendor/sass/test/sass/results/units.css +11 -0
  300. data/vendor/sass/test/sass/results/warn.css +0 -0
  301. data/vendor/sass/test/sass/results/warn_imported.css +0 -0
  302. data/vendor/sass/test/sass/script_conversion_test.rb +283 -0
  303. data/vendor/sass/test/sass/script_test.rb +496 -0
  304. data/vendor/sass/test/sass/scss/css_test.rb +916 -0
  305. data/vendor/sass/test/sass/scss/rx_test.rb +156 -0
  306. data/vendor/sass/test/sass/scss/scss_test.rb +1249 -0
  307. data/vendor/sass/test/sass/scss/test_helper.rb +37 -0
  308. data/vendor/sass/test/sass/templates/_imported_charset_ibm866.sass +4 -0
  309. data/vendor/sass/test/sass/templates/_imported_charset_utf8.sass +4 -0
  310. data/vendor/sass/test/sass/templates/_partial.sass +2 -0
  311. data/vendor/sass/test/sass/templates/alt.sass +16 -0
  312. data/vendor/sass/test/sass/templates/basic.sass +23 -0
  313. data/vendor/sass/test/sass/templates/bork1.sass +2 -0
  314. data/vendor/sass/test/sass/templates/bork2.sass +2 -0
  315. data/vendor/sass/test/sass/templates/bork3.sass +2 -0
  316. data/vendor/sass/test/sass/templates/bork4.sass +2 -0
  317. data/vendor/sass/test/sass/templates/compact.sass +17 -0
  318. data/vendor/sass/test/sass/templates/complex.sass +305 -0
  319. data/vendor/sass/test/sass/templates/compressed.sass +15 -0
  320. data/vendor/sass/test/sass/templates/expanded.sass +17 -0
  321. data/vendor/sass/test/sass/templates/if.sass +11 -0
  322. data/vendor/sass/test/sass/templates/import.sass +12 -0
  323. data/vendor/sass/test/sass/templates/import_charset.sass +7 -0
  324. data/vendor/sass/test/sass/templates/import_charset_1_8.sass +4 -0
  325. data/vendor/sass/test/sass/templates/import_charset_ibm866.sass +9 -0
  326. data/vendor/sass/test/sass/templates/importee.less +2 -0
  327. data/vendor/sass/test/sass/templates/importee.sass +19 -0
  328. data/vendor/sass/test/sass/templates/line_numbers.sass +13 -0
  329. data/vendor/sass/test/sass/templates/mixin_bork.sass +5 -0
  330. data/vendor/sass/test/sass/templates/mixins.sass +76 -0
  331. data/vendor/sass/test/sass/templates/multiline.sass +20 -0
  332. data/vendor/sass/test/sass/templates/nested.sass +25 -0
  333. data/vendor/sass/test/sass/templates/nested_bork1.sass +2 -0
  334. data/vendor/sass/test/sass/templates/nested_bork2.sass +2 -0
  335. data/vendor/sass/test/sass/templates/nested_bork3.sass +2 -0
  336. data/vendor/sass/test/sass/templates/nested_bork4.sass +2 -0
  337. data/vendor/sass/test/sass/templates/nested_import.sass +2 -0
  338. data/vendor/sass/test/sass/templates/nested_mixin_bork.sass +6 -0
  339. data/vendor/sass/test/sass/templates/options.sass +2 -0
  340. data/vendor/sass/test/sass/templates/parent_ref.sass +25 -0
  341. data/vendor/sass/test/sass/templates/script.sass +101 -0
  342. data/vendor/sass/test/sass/templates/scss_import.scss +11 -0
  343. data/vendor/sass/test/sass/templates/scss_importee.scss +1 -0
  344. data/vendor/sass/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  345. data/vendor/sass/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  346. data/vendor/sass/test/sass/templates/subdir/subdir.sass +6 -0
  347. data/vendor/sass/test/sass/templates/units.sass +11 -0
  348. data/vendor/sass/test/sass/templates/warn.sass +3 -0
  349. data/vendor/sass/test/sass/templates/warn_imported.sass +4 -0
  350. data/vendor/sass/test/sass/test_helper.rb +8 -0
  351. data/vendor/sass/test/sass/util/subset_map_test.rb +91 -0
  352. data/vendor/sass/test/sass/util_test.rb +254 -0
  353. data/vendor/sass/test/test_helper.rb +69 -0
  354. data/vendor/sass/yard/callbacks.rb +29 -0
  355. data/vendor/sass/yard/default/fulldoc/html/css/common.sass +26 -0
  356. data/vendor/sass/yard/default/layout/html/footer.erb +12 -0
  357. data/vendor/sass/yard/inherited_hash.rb +41 -0
  358. metadata +458 -0
@@ -0,0 +1,1925 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require File.dirname(__FILE__) + '/../test_helper'
4
+
5
+ class EngineTest < Test::Unit::TestCase
6
+ # A map of erroneous Haml documents to the error messages they should produce.
7
+ # The error messages may be arrays;
8
+ # if so, the second element should be the line number that should be reported for the error.
9
+ # If this isn't provided, the tests will assume the line number should be the last line of the document.
10
+ EXCEPTION_MAP = {
11
+ "!!!\n a" => "Illegal nesting: nesting within a header command is illegal.",
12
+ "a\n b" => "Illegal nesting: nesting within plain text is illegal.",
13
+ "/ a\n b" => "Illegal nesting: nesting within a tag that already has content is illegal.",
14
+ "% a" => 'Invalid tag: "% a".',
15
+ "%p a\n b" => "Illegal nesting: content can't be both given on the same line as %p and nested within it.",
16
+ "%p=" => "There's no Ruby code for = to evaluate.",
17
+ "%p~" => "There's no Ruby code for ~ to evaluate.",
18
+ "~" => "There's no Ruby code for ~ to evaluate.",
19
+ "=" => "There's no Ruby code for = to evaluate.",
20
+ "%p/\n a" => "Illegal nesting: nesting within a self-closing tag is illegal.",
21
+ ":a\n b" => ['Filter "a" is not defined.', 1],
22
+ ":a= b" => 'Invalid filter name ":a= b".',
23
+ "." => "Illegal element: classes and ids must have values.",
24
+ ".#" => "Illegal element: classes and ids must have values.",
25
+ ".{} a" => "Illegal element: classes and ids must have values.",
26
+ ".() a" => "Illegal element: classes and ids must have values.",
27
+ ".= a" => "Illegal element: classes and ids must have values.",
28
+ "%p..a" => "Illegal element: classes and ids must have values.",
29
+ "%a/ b" => "Self-closing tags can't have content.",
30
+ "%p{:a => 'b',\n:c => 'd'}/ e" => ["Self-closing tags can't have content.", 2],
31
+ "%p{:a => 'b',\n:c => 'd'}=" => ["There's no Ruby code for = to evaluate.", 2],
32
+ "%p.{:a => 'b',\n:c => 'd'} e" => ["Illegal element: classes and ids must have values.", 1],
33
+ "%p{:a => 'b',\n:c => 'd',\n:e => 'f'}\n%p/ a" => ["Self-closing tags can't have content.", 4],
34
+ "%p{:a => 'b',\n:c => 'd',\n:e => 'f'}\n- raise 'foo'" => ["foo", 4],
35
+ "%p{:a => 'b',\n:c => raise('foo'),\n:e => 'f'}" => ["foo", 2],
36
+ "%p{:a => 'b',\n:c => 'd',\n:e => raise('foo')}" => ["foo", 3],
37
+ " %p foo" => "Indenting at the beginning of the document is illegal.",
38
+ " %p foo" => "Indenting at the beginning of the document is illegal.",
39
+ "- end" => <<MESSAGE.rstrip,
40
+ You don't need to use "- end" in Haml. Un-indent to close a block:
41
+ - if foo?
42
+ %strong Foo!
43
+ - else
44
+ Not foo.
45
+ %p This line is un-indented, so it isn't part of the "if" block
46
+ MESSAGE
47
+ " \n\t\n %p foo" => ["Indenting at the beginning of the document is illegal.", 3],
48
+ "\n\n %p foo" => ["Indenting at the beginning of the document is illegal.", 3],
49
+ "%p\n foo\n foo" => ["Inconsistent indentation: 1 space was used for indentation, but the rest of the document was indented using 2 spaces.", 3],
50
+ "%p\n foo\n%p\n foo" => ["Inconsistent indentation: 1 space was used for indentation, but the rest of the document was indented using 2 spaces.", 4],
51
+ "%p\n\t\tfoo\n\tfoo" => ["Inconsistent indentation: 1 tab was used for indentation, but the rest of the document was indented using 2 tabs.", 3],
52
+ "%p\n foo\n foo" => ["Inconsistent indentation: 3 spaces were used for indentation, but the rest of the document was indented using 2 spaces.", 3],
53
+ "%p\n foo\n %p\n bar" => ["Inconsistent indentation: 3 spaces were used for indentation, but the rest of the document was indented using 2 spaces.", 4],
54
+ "%p\n :plain\n bar\n \t baz" => ['Inconsistent indentation: " \t " was used for indentation, but the rest of the document was indented using 2 spaces.', 4],
55
+ "%p\n foo\n%p\n bar" => ["The line was indented 2 levels deeper than the previous line.", 4],
56
+ "%p\n foo\n %p\n bar" => ["The line was indented 3 levels deeper than the previous line.", 4],
57
+ "%p\n \tfoo" => ["Indentation can't use both tabs and spaces.", 2],
58
+ "%p(" => "Invalid attribute list: \"(\".",
59
+ "%p(foo=\nbar)" => ["Invalid attribute list: \"(foo=\".", 1],
60
+ "%p(foo=)" => "Invalid attribute list: \"(foo=)\".",
61
+ "%p(foo 'bar')" => "Invalid attribute list: \"(foo 'bar')\".",
62
+ "%p(foo 'bar'\nbaz='bang')" => ["Invalid attribute list: \"(foo 'bar'\".", 1],
63
+ "%p(foo='bar'\nbaz 'bang'\nbip='bop')" => ["Invalid attribute list: \"(foo='bar' baz 'bang'\".", 2],
64
+ "%p{:foo => 'bar' :bar => 'baz'}" => :compile,
65
+ "%p{:foo => }" => :compile,
66
+ "%p{=> 'bar'}" => :compile,
67
+ "%p{:foo => 'bar}" => :compile,
68
+ "%p{'foo => 'bar'}" => :compile,
69
+ "%p{:foo => 'bar\"}" => :compile,
70
+
71
+ # Regression tests
72
+ "- raise 'foo'\n\n\n\nbar" => ["foo", 1],
73
+ "= 'foo'\n-raise 'foo'" => ["foo", 2],
74
+ "\n\n\n- raise 'foo'" => ["foo", 4],
75
+ "%p foo |\n bar |\n baz |\nbop\n- raise 'foo'" => ["foo", 5],
76
+ "foo\n\n\n bar" => ["Illegal nesting: nesting within plain text is illegal.", 4],
77
+ "%p/\n\n bar" => ["Illegal nesting: nesting within a self-closing tag is illegal.", 3],
78
+ "%p foo\n\n bar" => ["Illegal nesting: content can't be both given on the same line as %p and nested within it.", 3],
79
+ "/ foo\n\n bar" => ["Illegal nesting: nesting within a tag that already has content is illegal.", 3],
80
+ "!!!\n\n bar" => ["Illegal nesting: nesting within a header command is illegal.", 3],
81
+ "foo\n:ruby\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6],
82
+ "foo\n:erb\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6],
83
+ "foo\n:plain\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6],
84
+ "foo\n:plain\n 1\n 2\n 3\n4\n- raise 'foo'" => ["foo", 7],
85
+ "foo\n:plain\n 1\n 2\n 3\#{''}\n- raise 'foo'" => ["foo", 6],
86
+ "foo\n:plain\n 1\n 2\n 3\#{''}\n4\n- raise 'foo'" => ["foo", 7],
87
+ "foo\n:plain\n 1\n 2\n \#{raise 'foo'}" => ["foo", 5],
88
+ "= raise 'foo'\nfoo\nbar\nbaz\nbang" => ["foo", 1],
89
+ "- case 1\n\n- when 1\n - raise 'foo'" => ["foo", 4],
90
+ }
91
+
92
+ User = Struct.new('User', :id)
93
+ class CustomHamlClass < Struct.new(:id)
94
+ def haml_object_ref
95
+ "my_thing"
96
+ end
97
+ end
98
+
99
+ def render(text, options = {}, &block)
100
+ scope = options.delete(:scope) || Object.new
101
+ locals = options.delete(:locals) || {}
102
+ engine(text, options).to_html(scope, locals, &block)
103
+ end
104
+
105
+ def engine(text, options = {})
106
+ unless options[:filename]
107
+ # use caller method name as fake filename. useful for debugging
108
+ i = -1
109
+ caller[i+=1] =~ /`(.+?)'/ until $1 and $1.index('test_') == 0
110
+ options[:filename] = "(#{$1})"
111
+ end
112
+ Haml::Engine.new(text, options)
113
+ end
114
+
115
+ def setup
116
+ return if Haml::Util.ruby1_8?
117
+ @old_default_internal = Encoding.default_internal
118
+ Encoding.default_internal = nil
119
+ end
120
+
121
+ def teardown
122
+ return if Haml::Util.ruby1_8?
123
+ Encoding.default_internal = @old_default_internal
124
+ end
125
+
126
+ def test_empty_render
127
+ assert_equal "", render("")
128
+ end
129
+
130
+ def test_flexible_tabulation
131
+ assert_equal("<p>\n foo\n</p>\n<q>\n bar\n <a>\n baz\n </a>\n</q>\n",
132
+ render("%p\n foo\n%q\n bar\n %a\n baz"))
133
+ assert_equal("<p>\n foo\n</p>\n<q>\n bar\n <a>\n baz\n </a>\n</q>\n",
134
+ render("%p\n\tfoo\n%q\n\tbar\n\t%a\n\t\tbaz"))
135
+ assert_equal("<p>\n \t \t bar\n baz\n</p>\n",
136
+ render("%p\n :plain\n \t \t bar\n baz"))
137
+ end
138
+
139
+ def test_empty_render_should_remain_empty
140
+ assert_equal('', render(''))
141
+ end
142
+
143
+ def test_attributes_should_render_correctly
144
+ assert_equal("<div class='atlantis' style='ugly'></div>", render(".atlantis{:style => 'ugly'}").chomp)
145
+ end
146
+
147
+ def test_css_id_as_attribute_should_be_appended_with_underscore
148
+ assert_equal("<div id='my_id_1'></div>", render("#my_id{:id => '1'}").chomp)
149
+ assert_equal("<div id='my_id_1'></div>", render("#my_id{:id => 1}").chomp)
150
+ end
151
+
152
+ def test_ruby_code_should_work_inside_attributes
153
+ author = 'hcatlin'
154
+ assert_equal("<p class='3'>foo</p>", render("%p{:class => 1+2} foo").chomp)
155
+ end
156
+
157
+ def test_class_attr_with_array
158
+ assert_equal("<p class='a b'>foo</p>\n", render("%p{:class => %w[a b]} foo")) # basic
159
+ assert_equal("<p class='a b css'>foo</p>\n", render("%p.css{:class => %w[a b]} foo")) # merge with css
160
+ assert_equal("<p class='b css'>foo</p>\n", render("%p.css{:class => %w[css b]} foo")) # merge uniquely
161
+ assert_equal("<p class='a b c d'>foo</p>\n", render("%p{:class => [%w[a b], %w[c d]]} foo")) # flatten
162
+ assert_equal("<p class='a b'>foo</p>\n", render("%p{:class => [:a, :b] } foo")) # stringify
163
+ assert_equal("<p>foo</p>\n", render("%p{:class => [nil, false] } foo")) # strip falsey
164
+ assert_equal("<p class='a'>foo</p>\n", render("%p{:class => :a} foo")) # single stringify
165
+ assert_equal("<p>foo</p>\n", render("%p{:class => false} foo")) # single falsey
166
+ assert_equal("<p class='a b html'>foo</p>\n", render("%p(class='html'){:class => %w[a b]} foo")) # html attrs
167
+ end
168
+
169
+ def test_id_attr_with_array
170
+ assert_equal("<p id='a_b'>foo</p>\n", render("%p{:id => %w[a b]} foo")) # basic
171
+ assert_equal("<p id='css_a_b'>foo</p>\n", render("%p#css{:id => %w[a b]} foo")) # merge with css
172
+ assert_equal("<p id='a_b_c_d'>foo</p>\n", render("%p{:id => [%w[a b], %w[c d]]} foo")) # flatten
173
+ assert_equal("<p id='a_b'>foo</p>\n", render("%p{:id => [:a, :b] } foo")) # stringify
174
+ assert_equal("<p>foo</p>\n", render("%p{:id => [nil, false] } foo")) # strip falsey
175
+ assert_equal("<p id='a'>foo</p>\n", render("%p{:id => :a} foo")) # single stringify
176
+ assert_equal("<p>foo</p>\n", render("%p{:id => false} foo")) # single falsey
177
+ assert_equal("<p id='html_a_b'>foo</p>\n", render("%p(id='html'){:id => %w[a b]} foo")) # html attrs
178
+ end
179
+
180
+ def test_colon_in_class_attr
181
+ assert_equal("<p class='foo:bar' />\n", render("%p.foo:bar/"))
182
+ end
183
+
184
+ def test_colon_in_id_attr
185
+ assert_equal("<p id='foo:bar' />\n", render("%p#foo:bar/"))
186
+ end
187
+
188
+ def test_dynamic_attributes_with_no_content
189
+ assert_equal(<<HTML, render(<<HAML))
190
+ <p>
191
+ <a href='http://haml-lang.com'></a>
192
+ </p>
193
+ HTML
194
+ %p
195
+ %a{:href => "http://" + "haml-lang.com"}
196
+ HAML
197
+ end
198
+
199
+ def test_attributes_with_to_s
200
+ assert_equal(<<HTML, render(<<HAML))
201
+ <p id='foo_2'></p>
202
+ <p class='2 foo'></p>
203
+ <p blaz='2'></p>
204
+ <p 2='2'></p>
205
+ HTML
206
+ %p#foo{:id => 1+1}
207
+ %p.foo{:class => 1+1}
208
+ %p{:blaz => 1+1}
209
+ %p{(1+1) => 1+1}
210
+ HAML
211
+ end
212
+
213
+ def test_nil_should_render_empty_tag
214
+ assert_equal("<div class='no_attributes'></div>",
215
+ render(".no_attributes{:nil => nil}").chomp)
216
+ end
217
+
218
+ def test_strings_should_get_stripped_inside_tags
219
+ assert_equal("<div class='stripped'>This should have no spaces in front of it</div>",
220
+ render(".stripped This should have no spaces in front of it").chomp)
221
+ end
222
+
223
+ def test_one_liner_should_be_one_line
224
+ assert_equal("<p>Hello</p>", render('%p Hello').chomp)
225
+ end
226
+
227
+ def test_one_liner_with_newline_shouldnt_be_one_line
228
+ assert_equal("<p>\n foo\n bar\n</p>", render('%p= "foo\nbar"').chomp)
229
+ end
230
+
231
+ def test_multi_render
232
+ engine = engine("%strong Hi there!")
233
+ assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
234
+ assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
235
+ assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
236
+ end
237
+
238
+ def test_interpolation
239
+ assert_equal("<p>Hello World</p>\n", render('%p Hello #{who}', :locals => {:who => 'World'}))
240
+ assert_equal("<p>\n Hello World\n</p>\n", render("%p\n Hello \#{who}", :locals => {:who => 'World'}))
241
+ end
242
+
243
+ def test_interpolation_in_the_middle_of_a_string
244
+ assert_equal("\"title 'Title'. \"\n",
245
+ render("\"title '\#{\"Title\"}'. \""))
246
+ end
247
+
248
+ def test_interpolation_at_the_beginning_of_a_line
249
+ assert_equal("<p>2</p>\n", render('%p #{1 + 1}'))
250
+ assert_equal("<p>\n 2\n</p>\n", render("%p\n \#{1 + 1}"))
251
+ end
252
+
253
+ def test_escaped_interpolation
254
+ assert_equal("<p>Foo &amp; Bar & Baz</p>\n", render('%p& Foo #{"&"} Bar & Baz'))
255
+ end
256
+
257
+ def test_nil_tag_value_should_render_as_empty
258
+ assert_equal("<p></p>\n", render("%p= nil"))
259
+ end
260
+
261
+ def test_tag_with_failed_if_should_render_as_empty
262
+ assert_equal("<p></p>\n", render("%p= 'Hello' if false"))
263
+ end
264
+
265
+ def test_static_attributes_with_empty_attr
266
+ assert_equal("<img alt='' src='/foo.png' />\n", render("%img{:src => '/foo.png', :alt => ''}"))
267
+ end
268
+
269
+ def test_dynamic_attributes_with_empty_attr
270
+ assert_equal("<img alt='' src='/foo.png' />\n", render("%img{:width => nil, :src => '/foo.png', :alt => String.new}"))
271
+ end
272
+
273
+ def test_attribute_hash_with_newlines
274
+ assert_equal("<p a='b' c='d'>foop</p>\n", render("%p{:a => 'b',\n :c => 'd'} foop"))
275
+ assert_equal("<p a='b' c='d'>\n foop\n</p>\n", render("%p{:a => 'b',\n :c => 'd'}\n foop"))
276
+ assert_equal("<p a='b' c='d' />\n", render("%p{:a => 'b',\n :c => 'd'}/"))
277
+ assert_equal("<p a='b' c='d' e='f'></p>\n", render("%p{:a => 'b',\n :c => 'd',\n :e => 'f'}"))
278
+ end
279
+
280
+ def test_attr_hashes_not_modified
281
+ hash = {:color => 'red'}
282
+ assert_equal(<<HTML, render(<<HAML, :locals => {:hash => hash}))
283
+ <div color='red'></div>
284
+ <div class='special' color='red'></div>
285
+ <div color='red'></div>
286
+ HTML
287
+ %div{hash}
288
+ .special{hash}
289
+ %div{hash}
290
+ HAML
291
+ assert_equal(hash, {:color => 'red'})
292
+ end
293
+
294
+ def test_ugly_semi_prerendered_tags
295
+ assert_equal(<<HTML, render(<<HAML, :ugly => true))
296
+ <p a='2'></p>
297
+ <p a='2'>foo</p>
298
+ <p a='2' />
299
+ <p a='2'>foo</p>
300
+ <p a='2'>foo
301
+ bar</p>
302
+ <p a='2'>foo
303
+ bar</p>
304
+ <p a='2'>
305
+ foo
306
+ </p>
307
+ HTML
308
+ %p{:a => 1 + 1}
309
+ %p{:a => 1 + 1} foo
310
+ %p{:a => 1 + 1}/
311
+ %p{:a => 1 + 1}= "foo"
312
+ %p{:a => 1 + 1}= "foo\\nbar"
313
+ %p{:a => 1 + 1}~ "foo\\nbar"
314
+ %p{:a => 1 + 1}
315
+ foo
316
+ HAML
317
+ end
318
+
319
+ def test_end_of_file_multiline
320
+ assert_equal("<p>0</p>\n<p>1</p>\n<p>2</p>\n", render("- for i in (0...3)\n %p= |\n i |"))
321
+ end
322
+
323
+ def test_cr_newline
324
+ assert_equal("<p>foo</p>\n<p>bar</p>\n<p>baz</p>\n<p>boom</p>\n", render("%p foo\r%p bar\r\n%p baz\n\r%p boom"))
325
+ end
326
+
327
+ def test_textareas
328
+ assert_equal("<textarea>Foo&#x000A; bar&#x000A; baz</textarea>\n",
329
+ render('%textarea= "Foo\n bar\n baz"'))
330
+
331
+ assert_equal("<pre>Foo&#x000A; bar&#x000A; baz</pre>\n",
332
+ render('%pre= "Foo\n bar\n baz"'))
333
+
334
+ assert_equal("<textarea>#{'a' * 100}</textarea>\n",
335
+ render("%textarea #{'a' * 100}"))
336
+
337
+ assert_equal("<p>\n <textarea>Foo\n Bar\n Baz</textarea>\n</p>\n", render(<<SOURCE))
338
+ %p
339
+ %textarea
340
+ Foo
341
+ Bar
342
+ Baz
343
+ SOURCE
344
+ end
345
+
346
+ def test_pre_code
347
+ assert_equal(<<HTML, render(<<HAML))
348
+ <pre><code>Foo&#x000A; bar&#x000A; baz</code></pre>
349
+ HTML
350
+ %pre
351
+ %code
352
+ :preserve
353
+ Foo
354
+ bar
355
+ baz
356
+ HAML
357
+ end
358
+
359
+ def test_boolean_attributes
360
+ assert_equal("<p bar baz='true' foo='bar'></p>\n",
361
+ render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :html4))
362
+ assert_equal("<p bar='bar' baz='true' foo='bar'></p>\n",
363
+ render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :xhtml))
364
+
365
+ assert_equal("<p baz='false' foo='bar'></p>\n",
366
+ render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :html4))
367
+ assert_equal("<p baz='false' foo='bar'></p>\n",
368
+ render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :xhtml))
369
+ end
370
+
371
+ def test_both_whitespace_nukes_work_together
372
+ assert_equal(<<RESULT, render(<<SOURCE))
373
+ <p><q>Foo
374
+ Bar</q></p>
375
+ RESULT
376
+ %p
377
+ %q><= "Foo\\nBar"
378
+ SOURCE
379
+ end
380
+
381
+ def test_nil_option
382
+ assert_equal("<p foo='bar'></p>\n", render('%p{:foo => "bar"}', :attr_wrapper => nil))
383
+ end
384
+
385
+ def test_comment_with_crazy_nesting
386
+ assert_equal(<<HTML, render(<<HAML))
387
+ foo
388
+ bar
389
+ HTML
390
+ foo
391
+ -#
392
+ ul
393
+ %li{
394
+ foo
395
+ bar
396
+ HAML
397
+ end
398
+
399
+ # Regression tests
400
+
401
+ def test_whitespace_nuke_with_both_newlines
402
+ assert_equal("<p>foo</p>\n", render('%p<= "\nfoo\n"'))
403
+ assert_equal(<<HTML, render(<<HAML))
404
+ <p>
405
+ <p>foo</p>
406
+ </p>
407
+ HTML
408
+ %p
409
+ %p<= "\\nfoo\\n"
410
+ HAML
411
+ end
412
+
413
+ def test_whitespace_nuke_with_tags_and_else
414
+ assert_equal(<<HTML, render(<<HAML))
415
+ <a>
416
+ <b>foo</b>
417
+ </a>
418
+ HTML
419
+ %a
420
+ %b<
421
+ - if false
422
+ = "foo"
423
+ - else
424
+ foo
425
+ HAML
426
+
427
+ assert_equal(<<HTML, render(<<HAML))
428
+ <a>
429
+ <b>
430
+ foo
431
+ </b>
432
+ </a>
433
+ HTML
434
+ %a
435
+ %b
436
+ - if false
437
+ = "foo"
438
+ - else
439
+ foo
440
+ HAML
441
+ end
442
+
443
+ def test_outer_whitespace_nuke_with_empty_script
444
+ assert_equal(<<HTML, render(<<HAML))
445
+ <p>
446
+ foo<a></a></p>
447
+ HTML
448
+ %p
449
+ foo
450
+ = " "
451
+ %a>
452
+ HAML
453
+ end
454
+
455
+ def test_both_case_indentation_work_with_deeply_nested_code
456
+ result = <<RESULT
457
+ <h2>
458
+ other
459
+ </h2>
460
+ RESULT
461
+ assert_equal(result, render(<<HAML))
462
+ - case 'other'
463
+ - when 'test'
464
+ %h2
465
+ hi
466
+ - when 'other'
467
+ %h2
468
+ other
469
+ HAML
470
+ assert_equal(result, render(<<HAML))
471
+ - case 'other'
472
+ - when 'test'
473
+ %h2
474
+ hi
475
+ - when 'other'
476
+ %h2
477
+ other
478
+ HAML
479
+ end
480
+
481
+ def test_equals_block_with_ugly
482
+ assert_equal("foo\n", render(<<HAML, :ugly => true))
483
+ = capture_haml do
484
+ foo
485
+ HAML
486
+ end
487
+
488
+ def test_plain_equals_with_ugly
489
+ assert_equal("foo\nbar\n", render(<<HAML, :ugly => true))
490
+ = "foo"
491
+ bar
492
+ HAML
493
+ end
494
+
495
+ def test_inline_if
496
+ assert_equal(<<HTML, render(<<HAML))
497
+ <p>One</p>
498
+ <p></p>
499
+ <p>Three</p>
500
+ HTML
501
+ - for name in ["One", "Two", "Three"]
502
+ %p= name unless name == "Two"
503
+ HAML
504
+ end
505
+
506
+ def test_end_with_method_call
507
+ assert_equal(<<HTML, render(<<HAML))
508
+ 2|3|4
509
+ b-a-r
510
+ HTML
511
+ = [1, 2, 3].map do |i|
512
+ - i + 1
513
+ - end.join("|")
514
+ = "bar".gsub(/./) do |s|
515
+ - s + "-"
516
+ - end.gsub(/-$/) do |s|
517
+ - ''
518
+ HAML
519
+ end
520
+
521
+ def test_nested_end_with_method_call
522
+ assert_equal(<<HTML, render(<<HAML))
523
+ <p>
524
+ 2|3|4
525
+ b-a-r
526
+ </p>
527
+ HTML
528
+ %p
529
+ = [1, 2, 3].map do |i|
530
+ - i + 1
531
+ - end.join("|")
532
+ = "bar".gsub(/./) do |s|
533
+ - s + "-"
534
+ - end.gsub(/-$/) do |s|
535
+ - ''
536
+ HAML
537
+ end
538
+
539
+ def test_silent_end_with_stuff
540
+ assert_equal(<<HTML, render(<<HAML))
541
+ e
542
+ d
543
+ c
544
+ b
545
+ a
546
+ HTML
547
+ - str = "abcde"
548
+ - if true
549
+ = str.slice!(-1).chr
550
+ - end until str.empty?
551
+ HAML
552
+
553
+ assert_equal(<<HTML, render(<<HAML))
554
+ <p>hi!</p>
555
+ HTML
556
+ - if true
557
+ %p hi!
558
+ - end if "foo".gsub(/f/) do
559
+ - "z"
560
+ - end + "bar"
561
+ HAML
562
+ end
563
+
564
+ def test_multiline_with_colon_after_filter
565
+ assert_equal(<<HTML, render(<<HAML))
566
+ Foo
567
+ Bar
568
+ HTML
569
+ :plain
570
+ Foo
571
+ = { :a => "Bar", |
572
+ :b => "Baz" }[:a] |
573
+ HAML
574
+ assert_equal(<<HTML, render(<<HAML))
575
+
576
+ Bar
577
+ HTML
578
+ :plain
579
+ = { :a => "Bar", |
580
+ :b => "Baz" }[:a] |
581
+ HAML
582
+ end
583
+
584
+ def test_multiline_in_filter
585
+ assert_equal(<<HTML, render(<<HAML))
586
+ Foo |
587
+ Bar |
588
+ Baz
589
+ HTML
590
+ :plain
591
+ Foo |
592
+ Bar |
593
+ Baz
594
+ HAML
595
+ end
596
+
597
+ def test_curly_brace
598
+ assert_equal(<<HTML, render(<<HAML))
599
+ Foo { Bar
600
+ HTML
601
+ == Foo { Bar
602
+ HAML
603
+ end
604
+
605
+ def test_escape_attrs_false
606
+ assert_equal(<<HTML, render(<<HAML, :escape_attrs => false))
607
+ <div class='<?php echo "&quot;" ?>' id='foo'>
608
+ bar
609
+ </div>
610
+ HTML
611
+ #foo{:class => '<?php echo "&quot;" ?>'}
612
+ bar
613
+ HAML
614
+ end
615
+
616
+ def test_escape_attrs_always
617
+ assert_equal(<<HTML, render(<<HAML, :escape_attrs => :always))
618
+ <div class='"&amp;lt;&amp;gt;&amp;amp;"' id='foo'>
619
+ bar
620
+ </div>
621
+ HTML
622
+ #foo{:class => '"&lt;&gt;&amp;"'}
623
+ bar
624
+ HAML
625
+ end
626
+
627
+ def test_escape_html
628
+ html = <<HTML
629
+ &amp;
630
+ &
631
+ &amp;
632
+ HTML
633
+
634
+ assert_equal(html, render(<<HAML, :escape_html => true))
635
+ &= "&"
636
+ != "&"
637
+ = "&"
638
+ HAML
639
+
640
+ assert_equal(html, render(<<HAML, :escape_html => true))
641
+ &~ "&"
642
+ !~ "&"
643
+ ~ "&"
644
+ HAML
645
+
646
+ assert_equal(html, render(<<HAML, :escape_html => true))
647
+ & \#{"&"}
648
+ ! \#{"&"}
649
+ \#{"&"}
650
+ HAML
651
+
652
+ assert_equal(html, render(<<HAML, :escape_html => true))
653
+ &== \#{"&"}
654
+ !== \#{"&"}
655
+ == \#{"&"}
656
+ HAML
657
+
658
+ tag_html = <<HTML
659
+ <p>&amp;</p>
660
+ <p>&</p>
661
+ <p>&amp;</p>
662
+ HTML
663
+
664
+ assert_equal(tag_html, render(<<HAML, :escape_html => true))
665
+ %p&= "&"
666
+ %p!= "&"
667
+ %p= "&"
668
+ HAML
669
+
670
+ assert_equal(tag_html, render(<<HAML, :escape_html => true))
671
+ %p&~ "&"
672
+ %p!~ "&"
673
+ %p~ "&"
674
+ HAML
675
+
676
+ assert_equal(tag_html, render(<<HAML, :escape_html => true))
677
+ %p& \#{"&"}
678
+ %p! \#{"&"}
679
+ %p \#{"&"}
680
+ HAML
681
+
682
+ assert_equal(tag_html, render(<<HAML, :escape_html => true))
683
+ %p&== \#{"&"}
684
+ %p!== \#{"&"}
685
+ %p== \#{"&"}
686
+ HAML
687
+ end
688
+
689
+ def test_new_attrs_with_hash
690
+ assert_equal("<a href='#'></a>\n", render('%a(href="#")'))
691
+ end
692
+
693
+ def test_javascript_filter_with_dynamic_interp_and_escape_html
694
+ assert_equal(<<HTML, render(<<HAML, :escape_html => true))
695
+ <script type='text/javascript'>
696
+ //<![CDATA[
697
+ & < > &
698
+ //]]>
699
+ </script>
700
+ HTML
701
+ :javascript
702
+ & < > \#{"&"}
703
+ HAML
704
+ end
705
+
706
+ def test_html5_javascript_filter
707
+ assert_equal(<<HTML, render(<<HAML, :format => :html5))
708
+ <script>
709
+ //<![CDATA[
710
+ foo bar
711
+ //]]>
712
+ </script>
713
+ HTML
714
+ :javascript
715
+ foo bar
716
+ HAML
717
+ end
718
+
719
+ def test_html5_css_filter
720
+ assert_equal(<<HTML, render(<<HAML, :format => :html5))
721
+ <style>
722
+ /*<![CDATA[*/
723
+ foo bar
724
+ /*]]>*/
725
+ </style>
726
+ HTML
727
+ :css
728
+ foo bar
729
+ HAML
730
+ end
731
+
732
+ def test_erb_filter_with_multiline_expr
733
+ assert_equal(<<HTML, render(<<HAML))
734
+ foobarbaz
735
+ HTML
736
+ :erb
737
+ <%= "foo" +
738
+ "bar" +
739
+ "baz" %>
740
+ HAML
741
+ end
742
+
743
+ def test_silent_script_with_hyphen_case
744
+ assert_equal("", render("- 'foo-case-bar-case'"))
745
+ end
746
+
747
+ def test_silent_script_with_hyphen_end
748
+ assert_equal("", render("- 'foo-end-bar-end'"))
749
+ end
750
+
751
+ def test_silent_script_with_hyphen_end_and_block
752
+ assert_equal(<<HTML, render(<<HAML))
753
+ <p>foo-end</p>
754
+ <p>bar-end</p>
755
+ HTML
756
+ - ("foo-end-bar-end".gsub(/\\w+-end/) do |s|
757
+ %p= s
758
+ - end; nil)
759
+ HAML
760
+ end
761
+
762
+ def test_if_without_content_and_else
763
+ assert_equal(<<HTML, render(<<HAML))
764
+ foo
765
+ HTML
766
+ - if false
767
+ - else
768
+ foo
769
+ HAML
770
+
771
+ assert_equal(<<HTML, render(<<HAML))
772
+ foo
773
+ HTML
774
+ - if true
775
+ - if false
776
+ - else
777
+ foo
778
+ HAML
779
+ end
780
+
781
+ def test_html_attributes_with_hash
782
+ assert_equal("<a href='#' rel='top'>Foo</a>\n",
783
+ render('%a(href="#" rel="top") Foo'))
784
+ assert_equal("<a href='#'>Foo</a>\n",
785
+ render('%a(href="#") #{"Foo"}'))
786
+
787
+ assert_equal("<a href='#\"'></a>\n", render('%a(href="#\\"")'))
788
+ end
789
+
790
+ def test_filter_with_newline_and_interp
791
+ assert_equal(<<HTML, render(<<HAML))
792
+ \\n
793
+ HTML
794
+ :plain
795
+ \\n\#{""}
796
+ HAML
797
+ end
798
+
799
+ def test_case_assigned_to_var
800
+ assert_equal(<<HTML, render(<<HAML))
801
+ bar
802
+ HTML
803
+ - var = case 12
804
+ - when 1; "foo"
805
+ - when 12; "bar"
806
+ = var
807
+ HAML
808
+
809
+ assert_equal(<<HTML, render(<<HAML))
810
+ bar
811
+ HTML
812
+ - var = case 12
813
+ - when 1
814
+ - "foo"
815
+ - when 12
816
+ - "bar"
817
+ = var
818
+ HAML
819
+
820
+ assert_equal(<<HTML, render(<<HAML))
821
+ bar
822
+ HTML
823
+ - var = case 12
824
+ - when 1
825
+ - "foo"
826
+ - when 12
827
+ - "bar"
828
+ = var
829
+ HAML
830
+ end
831
+
832
+ def test_nested_case_assigned_to_var
833
+ assert_equal(<<HTML, render(<<HAML))
834
+ bar
835
+ HTML
836
+ - if true
837
+ - var = case 12
838
+ - when 1; "foo"
839
+ - when 12; "bar"
840
+ = var
841
+ HAML
842
+ end
843
+
844
+ def test_case_assigned_to_multiple_vars
845
+ assert_equal(<<HTML, render(<<HAML))
846
+ bar
847
+ bip
848
+ HTML
849
+ - var, vip = case 12
850
+ - when 1; ["foo", "baz"]
851
+ - when 12; ["bar", "bip"]
852
+ = var
853
+ = vip
854
+ HAML
855
+ end
856
+
857
+ def test_if_assigned_to_var
858
+ assert_equal(<<HTML, render(<<HAML))
859
+ foo
860
+ HTML
861
+ - var = if false
862
+ - else
863
+ - "foo"
864
+ = var
865
+ HAML
866
+
867
+ assert_equal(<<HTML, render(<<HAML))
868
+ foo
869
+ HTML
870
+ - var = if false
871
+ - elsif 12
872
+ - "foo"
873
+ - elsif 14; "bar"
874
+ - else
875
+ - "baz"
876
+ = var
877
+ HAML
878
+
879
+ assert_equal(<<HTML, render(<<HAML))
880
+ foo
881
+ HTML
882
+ - var = if false
883
+ - "bar"
884
+ - else
885
+ - "foo"
886
+ = var
887
+ HAML
888
+ end
889
+
890
+ def test_case_with_newline_after_case
891
+ assert_equal(<<HTML, render(<<HAML))
892
+ foo
893
+ HTML
894
+ - case 1
895
+
896
+ - when 1
897
+ foo
898
+ - when 2
899
+ bar
900
+ HAML
901
+
902
+ assert_equal(<<HTML, render(<<HAML))
903
+ bar
904
+ HTML
905
+ - case 2
906
+
907
+ - when 1
908
+ foo
909
+ - when 2
910
+ bar
911
+ HAML
912
+ end
913
+
914
+ def test_escape_html_with_interpolated_if_statement
915
+ assert_equal(<<HTML, render(<<HAML, :escape_html => true))
916
+ foo,
917
+ HTML
918
+ foo\#{"," if true}
919
+ HAML
920
+ end
921
+
922
+ # HTML escaping tests
923
+
924
+ def test_ampersand_equals_should_escape
925
+ assert_equal("<p>\n foo &amp; bar\n</p>\n", render("%p\n &= 'foo & bar'", :escape_html => false))
926
+ end
927
+
928
+ def test_ampersand_equals_inline_should_escape
929
+ assert_equal("<p>foo &amp; bar</p>\n", render("%p&= 'foo & bar'", :escape_html => false))
930
+ end
931
+
932
+ def test_ampersand_equals_should_escape_before_preserve
933
+ assert_equal("<textarea>foo&#x000A;bar</textarea>\n", render('%textarea&= "foo\nbar"', :escape_html => false))
934
+ end
935
+
936
+ def test_bang_equals_should_not_escape
937
+ assert_equal("<p>\n foo & bar\n</p>\n", render("%p\n != 'foo & bar'", :escape_html => true))
938
+ end
939
+
940
+ def test_bang_equals_inline_should_not_escape
941
+ assert_equal("<p>foo & bar</p>\n", render("%p!= 'foo & bar'", :escape_html => true))
942
+ end
943
+
944
+ def test_static_attributes_should_be_escaped
945
+ assert_equal("<img class='atlantis' style='ugly&amp;stupid' />\n",
946
+ render("%img.atlantis{:style => 'ugly&stupid'}"))
947
+ assert_equal("<div class='atlantis' style='ugly&amp;stupid'>foo</div>\n",
948
+ render(".atlantis{:style => 'ugly&stupid'} foo"))
949
+ assert_equal("<p class='atlantis' style='ugly&amp;stupid'>foo</p>\n",
950
+ render("%p.atlantis{:style => 'ugly&stupid'}= 'foo'"))
951
+ assert_equal("<p class='atlantis' style='ugly&#x000A;stupid'></p>\n",
952
+ render("%p.atlantis{:style => \"ugly\\nstupid\"}"))
953
+ end
954
+
955
+ def test_dynamic_attributes_should_be_escaped
956
+ assert_equal("<img alt='' src='&amp;foo.png' />\n",
957
+ render("%img{:width => nil, :src => '&foo.png', :alt => String.new}"))
958
+ assert_equal("<p alt='' src='&amp;foo.png'>foo</p>\n",
959
+ render("%p{:width => nil, :src => '&foo.png', :alt => String.new} foo"))
960
+ assert_equal("<div alt='' src='&amp;foo.png'>foo</div>\n",
961
+ render("%div{:width => nil, :src => '&foo.png', :alt => String.new}= 'foo'"))
962
+ assert_equal("<img alt='' src='foo&#x000A;.png' />\n",
963
+ render("%img{:width => nil, :src => \"foo\\n.png\", :alt => String.new}"))
964
+ end
965
+
966
+ def test_string_double_equals_should_be_esaped
967
+ assert_equal("<p>4&&lt;</p>\n", render("%p== \#{2+2}&\#{'<'}", :escape_html => true))
968
+ assert_equal("<p>4&<</p>\n", render("%p== \#{2+2}&\#{'<'}", :escape_html => false))
969
+ end
970
+
971
+ def test_escaped_inline_string_double_equals
972
+ assert_equal("<p>4&&lt;</p>\n", render("%p&== \#{2+2}&\#{'<'}", :escape_html => true))
973
+ assert_equal("<p>4&&lt;</p>\n", render("%p&== \#{2+2}&\#{'<'}", :escape_html => false))
974
+ end
975
+
976
+ def test_unescaped_inline_string_double_equals
977
+ assert_equal("<p>4&<</p>\n", render("%p!== \#{2+2}&\#{'<'}", :escape_html => true))
978
+ assert_equal("<p>4&<</p>\n", render("%p!== \#{2+2}&\#{'<'}", :escape_html => false))
979
+ end
980
+
981
+ def test_escaped_string_double_equals
982
+ assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => true))
983
+ assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => false))
984
+ end
985
+
986
+ def test_unescaped_string_double_equals
987
+ assert_equal("<p>\n 4&<\n</p>\n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => true))
988
+ assert_equal("<p>\n 4&<\n</p>\n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => false))
989
+ end
990
+
991
+ def test_string_interpolation_should_be_esaped
992
+ assert_equal("<p>4&&lt;</p>\n", render("%p \#{2+2}&\#{'<'}", :escape_html => true))
993
+ assert_equal("<p>4&<</p>\n", render("%p \#{2+2}&\#{'<'}", :escape_html => false))
994
+ end
995
+
996
+ def test_escaped_inline_string_interpolation
997
+ assert_equal("<p>4&&lt;</p>\n", render("%p& \#{2+2}&\#{'<'}", :escape_html => true))
998
+ assert_equal("<p>4&&lt;</p>\n", render("%p& \#{2+2}&\#{'<'}", :escape_html => false))
999
+ end
1000
+
1001
+ def test_unescaped_inline_string_interpolation
1002
+ assert_equal("<p>4&<</p>\n", render("%p! \#{2+2}&\#{'<'}", :escape_html => true))
1003
+ assert_equal("<p>4&<</p>\n", render("%p! \#{2+2}&\#{'<'}", :escape_html => false))
1004
+ end
1005
+
1006
+ def test_escaped_string_interpolation
1007
+ assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => true))
1008
+ assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => false))
1009
+ end
1010
+
1011
+ def test_unescaped_string_interpolation
1012
+ assert_equal("<p>\n 4&<\n</p>\n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => true))
1013
+ assert_equal("<p>\n 4&<\n</p>\n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => false))
1014
+ end
1015
+
1016
+ def test_scripts_should_respect_escape_html_option
1017
+ assert_equal("<p>\n foo &amp; bar\n</p>\n", render("%p\n = 'foo & bar'", :escape_html => true))
1018
+ assert_equal("<p>\n foo & bar\n</p>\n", render("%p\n = 'foo & bar'", :escape_html => false))
1019
+ end
1020
+
1021
+ def test_inline_scripts_should_respect_escape_html_option
1022
+ assert_equal("<p>foo &amp; bar</p>\n", render("%p= 'foo & bar'", :escape_html => true))
1023
+ assert_equal("<p>foo & bar</p>\n", render("%p= 'foo & bar'", :escape_html => false))
1024
+ end
1025
+
1026
+ def test_script_ending_in_comment_should_render_when_html_is_escaped
1027
+ assert_equal("foo&amp;bar\n", render("= 'foo&bar' #comment", :escape_html => true))
1028
+ end
1029
+
1030
+ def test_script_with_if_shouldnt_output
1031
+ assert_equal(<<HTML, render(<<HAML))
1032
+ <p>foo</p>
1033
+ <p></p>
1034
+ HTML
1035
+ %p= "foo"
1036
+ %p= "bar" if false
1037
+ HAML
1038
+ end
1039
+
1040
+ # Options tests
1041
+
1042
+ def test_filename_and_line
1043
+ begin
1044
+ render("\n\n = abc", :filename => 'test', :line => 2)
1045
+ rescue Exception => e
1046
+ assert_kind_of Haml::SyntaxError, e
1047
+ assert_match(/test:4/, e.backtrace.first)
1048
+ end
1049
+
1050
+ begin
1051
+ render("\n\n= 123\n\n= nil[]", :filename => 'test', :line => 2)
1052
+ rescue Exception => e
1053
+ assert_kind_of NoMethodError, e
1054
+ assert_match(/test:6/, e.backtrace.first)
1055
+ end
1056
+ end
1057
+
1058
+ def test_stop_eval
1059
+ assert_equal("", render("= 'Hello'", :suppress_eval => true))
1060
+ assert_equal("", render("- haml_concat 'foo'", :suppress_eval => true))
1061
+ assert_equal("<div id='foo' yes='no' />\n", render("#foo{:yes => 'no'}/", :suppress_eval => true))
1062
+ assert_equal("<div id='foo' />\n", render("#foo{:yes => 'no', :call => a_function() }/", :suppress_eval => true))
1063
+ assert_equal("<div />\n", render("%div[1]/", :suppress_eval => true))
1064
+ assert_equal("", render(":ruby\n Kernel.puts 'hello'", :suppress_eval => true))
1065
+ end
1066
+
1067
+ def test_doctypes
1068
+ assert_equal('<!DOCTYPE html>',
1069
+ render('!!!', :format => :html5).strip)
1070
+ assert_equal('<!DOCTYPE html>', render('!!! 5').strip)
1071
+ assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
1072
+ render('!!! strict').strip)
1073
+ assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
1074
+ render('!!! frameset').strip)
1075
+ assert_equal('<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">',
1076
+ render('!!! mobile').strip)
1077
+ assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
1078
+ render('!!! basic').strip)
1079
+ assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
1080
+ render('!!! transitional').strip)
1081
+ assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
1082
+ render('!!!').strip)
1083
+ assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
1084
+ render('!!! strict', :format => :html4).strip)
1085
+ assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
1086
+ render('!!! frameset', :format => :html4).strip)
1087
+ assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
1088
+ render('!!! transitional', :format => :html4).strip)
1089
+ assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
1090
+ render('!!!', :format => :html4).strip)
1091
+ end
1092
+
1093
+ def test_attr_wrapper
1094
+ assert_equal("<p strange=*attrs*></p>\n", render("%p{ :strange => 'attrs'}", :attr_wrapper => '*'))
1095
+ assert_equal("<p escaped='quo\"te'></p>\n", render("%p{ :escaped => 'quo\"te'}", :attr_wrapper => '"'))
1096
+ assert_equal("<p escaped=\"quo'te\"></p>\n", render("%p{ :escaped => 'quo\\'te'}", :attr_wrapper => '"'))
1097
+ assert_equal("<p escaped=\"q'uo&quot;te\"></p>\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"'))
1098
+ assert_equal("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n", render("!!! XML", :attr_wrapper => '"'))
1099
+ end
1100
+
1101
+ def test_autoclose_option
1102
+ assert_equal("<flaz foo='bar' />\n", render("%flaz{:foo => 'bar'}", :autoclose => ["flaz"]))
1103
+ assert_equal(<<HTML, render(<<HAML, :autoclose => [/^flaz/]))
1104
+ <flaz />
1105
+ <flaznicate />
1106
+ <flan></flan>
1107
+ HTML
1108
+ %flaz
1109
+ %flaznicate
1110
+ %flan
1111
+ HAML
1112
+ end
1113
+
1114
+ def test_attrs_parsed_correctly
1115
+ assert_equal("<p boom=>biddly='bar =&gt; baz'></p>\n", render("%p{'boom=>biddly' => 'bar => baz'}"))
1116
+ assert_equal("<p foo,bar='baz, qux'></p>\n", render("%p{'foo,bar' => 'baz, qux'}"))
1117
+ assert_equal("<p escaped='quo&#x000A;te'></p>\n", render("%p{ :escaped => \"quo\\nte\"}"))
1118
+ assert_equal("<p escaped='quo4te'></p>\n", render("%p{ :escaped => \"quo\#{2 + 2}te\"}"))
1119
+ end
1120
+
1121
+ def test_correct_parsing_with_brackets
1122
+ assert_equal("<p class='foo'>{tada} foo</p>\n", render("%p{:class => 'foo'} {tada} foo"))
1123
+ assert_equal("<p class='foo'>deep {nested { things }}</p>\n", render("%p{:class => 'foo'} deep {nested { things }}"))
1124
+ assert_equal("<p class='bar foo'>{a { d</p>\n", render("%p{{:class => 'foo'}, :class => 'bar'} {a { d"))
1125
+ assert_equal("<p foo='bar'>a}</p>\n", render("%p{:foo => 'bar'} a}"))
1126
+
1127
+ foo = []
1128
+ foo[0] = Struct.new('Foo', :id).new
1129
+ assert_equal("<p class='struct_foo' id='struct_foo_new'>New User]</p>\n",
1130
+ render("%p[foo[0]] New User]", :locals => {:foo => foo}))
1131
+ assert_equal("<p class='prefix_struct_foo' id='prefix_struct_foo_new'>New User]</p>\n",
1132
+ render("%p[foo[0], :prefix] New User]", :locals => {:foo => foo}))
1133
+
1134
+ foo[0].id = 1
1135
+ assert_equal("<p class='struct_foo' id='struct_foo_1'>New User]</p>\n",
1136
+ render("%p[foo[0]] New User]", :locals => {:foo => foo}))
1137
+ assert_equal("<p class='prefix_struct_foo' id='prefix_struct_foo_1'>New User]</p>\n",
1138
+ render("%p[foo[0], :prefix] New User]", :locals => {:foo => foo}))
1139
+ end
1140
+
1141
+ def test_empty_attrs
1142
+ assert_equal("<p attr=''>empty</p>\n", render("%p{ :attr => '' } empty"))
1143
+ assert_equal("<p attr=''>empty</p>\n", render("%p{ :attr => x } empty", :locals => {:x => ''}))
1144
+ end
1145
+
1146
+ def test_nil_attrs
1147
+ assert_equal("<p>nil</p>\n", render("%p{ :attr => nil } nil"))
1148
+ assert_equal("<p>nil</p>\n", render("%p{ :attr => x } nil", :locals => {:x => nil}))
1149
+ end
1150
+
1151
+ def test_nil_id_with_syntactic_id
1152
+ assert_equal("<p id='foo'>nil</p>\n", render("%p#foo{:id => nil} nil"))
1153
+ assert_equal("<p id='foo_bar'>nil</p>\n", render("%p#foo{{:id => 'bar'}, :id => nil} nil"))
1154
+ assert_equal("<p id='foo_bar'>nil</p>\n", render("%p#foo{{:id => nil}, :id => 'bar'} nil"))
1155
+ end
1156
+
1157
+ def test_nil_class_with_syntactic_class
1158
+ assert_equal("<p class='foo'>nil</p>\n", render("%p.foo{:class => nil} nil"))
1159
+ assert_equal("<p class='bar foo'>nil</p>\n", render("%p.bar.foo{:class => nil} nil"))
1160
+ assert_equal("<p class='bar foo'>nil</p>\n", render("%p.foo{{:class => 'bar'}, :class => nil} nil"))
1161
+ assert_equal("<p class='bar foo'>nil</p>\n", render("%p.foo{{:class => nil}, :class => 'bar'} nil"))
1162
+ end
1163
+
1164
+ def test_locals
1165
+ assert_equal("<p>Paragraph!</p>\n", render("%p= text", :locals => { :text => "Paragraph!" }))
1166
+ end
1167
+
1168
+ def test_dynamic_attrs_shouldnt_register_as_literal_values
1169
+ assert_equal("<p a='b2c'></p>\n", render('%p{:a => "b#{1 + 1}c"}'))
1170
+ assert_equal("<p a='b2c'></p>\n", render("%p{:a => 'b' + (1 + 1).to_s + 'c'}"))
1171
+ end
1172
+
1173
+ def test_dynamic_attrs_with_self_closed_tag
1174
+ assert_equal("<a b='2' />\nc\n", render("%a{'b' => 1 + 1}/\n= 'c'\n"))
1175
+ end
1176
+
1177
+ EXCEPTION_MAP.each do |key, value|
1178
+ define_method("test_exception (#{key.inspect})") do
1179
+ begin
1180
+ render(key, :filename => __FILE__)
1181
+ rescue Exception => err
1182
+ value = [value] unless value.is_a?(Array)
1183
+ expected_message, line_no = value
1184
+ line_no ||= key.split("\n").length
1185
+
1186
+ if expected_message == :compile
1187
+ if Haml::Util.ruby1_8?
1188
+ assert_match(/^compile error\n/, err.message, "Line: #{key}")
1189
+ else
1190
+ assert_match(/^#{Regexp.quote __FILE__}:#{line_no}: syntax error,/, err.message, "Line: #{key}")
1191
+ end
1192
+ else
1193
+ assert_equal(expected_message, err.message, "Line: #{key}")
1194
+ end
1195
+
1196
+ if Haml::Util.ruby1_8?
1197
+ # Sometimes, the first backtrace entry is *only* in the message.
1198
+ # No idea why.
1199
+ bt =
1200
+ if expected_message == :compile && err.message.include?("\n")
1201
+ err.message.split("\n", 2)[1]
1202
+ else
1203
+ err.backtrace[0]
1204
+ end
1205
+ assert_match(/^#{Regexp.escape(__FILE__)}:#{line_no}/, bt, "Line: #{key}")
1206
+ end
1207
+ else
1208
+ assert(false, "Exception not raised for\n#{key}")
1209
+ end
1210
+ end
1211
+ end
1212
+
1213
+ def test_exception_line
1214
+ render("a\nb\n!!!\n c\nd")
1215
+ rescue Haml::SyntaxError => e
1216
+ assert_equal("(test_exception_line):4", e.backtrace[0])
1217
+ else
1218
+ assert(false, '"a\nb\n!!!\n c\nd" doesn\'t produce an exception')
1219
+ end
1220
+
1221
+ def test_exception
1222
+ render("%p\n hi\n %a= undefined\n= 12")
1223
+ rescue Exception => e
1224
+ assert_match("(test_exception):3", e.backtrace[0])
1225
+ else
1226
+ # Test failed... should have raised an exception
1227
+ assert(false)
1228
+ end
1229
+
1230
+ def test_compile_error
1231
+ render("a\nb\n- fee)\nc")
1232
+ rescue Exception => e
1233
+ assert_match(/\(test_compile_error\):3: syntax error/i, e.message)
1234
+ else
1235
+ assert(false,
1236
+ '"a\nb\n- fee)\nc" doesn\'t produce an exception!')
1237
+ end
1238
+
1239
+ def test_unbalanced_brackets
1240
+ render('foo #{1 + 5} foo #{6 + 7 bar #{8 + 9}')
1241
+ rescue Haml::SyntaxError => e
1242
+ assert_equal("Unbalanced brackets.", e.message)
1243
+ end
1244
+
1245
+ def test_balanced_conditional_comments
1246
+ assert_equal("<!--[if !(IE 6)|(IE 7)]> Bracket: ] <![endif]-->\n",
1247
+ render("/[if !(IE 6)|(IE 7)] Bracket: ]"))
1248
+ end
1249
+
1250
+ def test_empty_filter
1251
+ assert_equal(<<END, render(':javascript'))
1252
+ <script type='text/javascript'>
1253
+ //<![CDATA[
1254
+
1255
+ //]]>
1256
+ </script>
1257
+ END
1258
+ end
1259
+
1260
+ def test_ugly_filter
1261
+ assert_equal(<<END, render(":sass\n #foo\n bar: baz", :ugly => true))
1262
+ #foo {
1263
+ bar: baz; }
1264
+ END
1265
+ end
1266
+
1267
+ def test_css_filter
1268
+ assert_equal(<<HTML, render(<<HAML))
1269
+ <style type='text/css'>
1270
+ /*<![CDATA[*/
1271
+ #foo {
1272
+ bar: baz; }
1273
+ /*]]>*/
1274
+ </style>
1275
+ HTML
1276
+ :css
1277
+ #foo {
1278
+ bar: baz; }
1279
+ HAML
1280
+ end
1281
+
1282
+ def test_local_assigns_dont_modify_class
1283
+ assert_equal("bar\n", render("= foo", :locals => {:foo => 'bar'}))
1284
+ assert_equal(nil, defined?(foo))
1285
+ end
1286
+
1287
+ def test_object_ref_with_nil_id
1288
+ user = User.new
1289
+ assert_equal("<p class='struct_user' id='struct_user_new'>New User</p>\n",
1290
+ render("%p[user] New User", :locals => {:user => user}))
1291
+ end
1292
+
1293
+ def test_object_ref_before_attrs
1294
+ user = User.new 42
1295
+ assert_equal("<p class='struct_user' id='struct_user_42' style='width: 100px;'>New User</p>\n",
1296
+ render("%p[user]{:style => 'width: 100px;'} New User", :locals => {:user => user}))
1297
+ end
1298
+
1299
+ def test_object_ref_with_custom_haml_class
1300
+ custom = CustomHamlClass.new 42
1301
+ assert_equal("<p class='my_thing' id='my_thing_42' style='width: 100px;'>My Thing</p>\n",
1302
+ render("%p[custom]{:style => 'width: 100px;'} My Thing", :locals => {:custom => custom}))
1303
+ end
1304
+
1305
+ def test_non_literal_attributes
1306
+ assert_equal("<p a1='foo' a2='bar' a3='baz' />\n",
1307
+ render("%p{a2, a1, :a3 => 'baz'}/",
1308
+ :locals => {:a1 => {:a1 => 'foo'}, :a2 => {:a2 => 'bar'}}))
1309
+ end
1310
+
1311
+ def test_render_should_accept_a_binding_as_scope
1312
+ string = "This is a string!"
1313
+ string.instance_variable_set("@var", "Instance variable")
1314
+ b = string.instance_eval do
1315
+ var = "Local variable"
1316
+ binding
1317
+ end
1318
+
1319
+ assert_equal("<p>THIS IS A STRING!</p>\n<p>Instance variable</p>\n<p>Local variable</p>\n",
1320
+ render("%p= upcase\n%p= @var\n%p= var", :scope => b))
1321
+ end
1322
+
1323
+ def test_yield_should_work_with_binding
1324
+ assert_equal("12\nFOO\n", render("= yield\n= upcase", :scope => "foo".instance_eval{binding}) { 12 })
1325
+ end
1326
+
1327
+ def test_yield_should_work_with_def_method
1328
+ s = "foo"
1329
+ engine("= yield\n= upcase").def_method(s, :render)
1330
+ assert_equal("12\nFOO\n", s.render { 12 })
1331
+ end
1332
+
1333
+ def test_def_method_with_module
1334
+ engine("= yield\n= upcase").def_method(String, :render_haml)
1335
+ assert_equal("12\nFOO\n", "foo".render_haml { 12 })
1336
+ end
1337
+
1338
+ def test_def_method_locals
1339
+ obj = Object.new
1340
+ engine("%p= foo\n.bar{:baz => baz}= boom").def_method(obj, :render, :foo, :baz, :boom)
1341
+ assert_equal("<p>1</p>\n<div baz='2' class='bar'>3</div>\n", obj.render(:foo => 1, :baz => 2, :boom => 3))
1342
+ end
1343
+
1344
+ def test_render_proc_locals
1345
+ proc = engine("%p= foo\n.bar{:baz => baz}= boom").render_proc(Object.new, :foo, :baz, :boom)
1346
+ assert_equal("<p>1</p>\n<div baz='2' class='bar'>3</div>\n", proc[:foo => 1, :baz => 2, :boom => 3])
1347
+ end
1348
+
1349
+ def test_render_proc_with_binding
1350
+ assert_equal("FOO\n", engine("= upcase").render_proc("foo".instance_eval{binding}).call)
1351
+ end
1352
+
1353
+ def test_haml_buffer_gets_reset_even_with_exception
1354
+ scope = Object.new
1355
+ render("- raise Haml::Error", :scope => scope)
1356
+ assert(false, "Expected exception")
1357
+ rescue Exception
1358
+ assert_nil(scope.send(:haml_buffer))
1359
+ end
1360
+
1361
+ def test_def_method_haml_buffer_gets_reset_even_with_exception
1362
+ scope = Object.new
1363
+ engine("- raise Haml::Error").def_method(scope, :render)
1364
+ scope.render
1365
+ assert(false, "Expected exception")
1366
+ rescue Exception
1367
+ assert_nil(scope.send(:haml_buffer))
1368
+ end
1369
+
1370
+ def test_render_proc_haml_buffer_gets_reset_even_with_exception
1371
+ scope = Object.new
1372
+ proc = engine("- raise Haml::Error").render_proc(scope)
1373
+ proc.call
1374
+ assert(false, "Expected exception")
1375
+ rescue Exception
1376
+ assert_nil(scope.send(:haml_buffer))
1377
+ end
1378
+
1379
+ def test_ugly_true
1380
+ assert_equal("<div id='outer'>\n<div id='inner'>\n<p>hello world</p>\n</div>\n</div>\n",
1381
+ render("#outer\n #inner\n %p hello world", :ugly => true))
1382
+
1383
+ assert_equal("<p>#{'s' * 75}</p>\n",
1384
+ render("%p #{'s' * 75}", :ugly => true))
1385
+
1386
+ assert_equal("<p>#{'s' * 75}</p>\n",
1387
+ render("%p= 's' * 75", :ugly => true))
1388
+ end
1389
+
1390
+ def test_auto_preserve_unless_ugly
1391
+ assert_equal("<pre>foo&#x000A;bar</pre>\n", render('%pre="foo\nbar"'))
1392
+ assert_equal("<pre>foo\nbar</pre>\n", render("%pre\n foo\n bar"))
1393
+ assert_equal("<pre>foo\nbar</pre>\n", render('%pre="foo\nbar"', :ugly => true))
1394
+ assert_equal("<pre>foo\nbar</pre>\n", render("%pre\n foo\n bar", :ugly => true))
1395
+ end
1396
+
1397
+ def test_xhtml_output_option
1398
+ assert_equal "<p>\n <br />\n</p>\n", render("%p\n %br", :format => :xhtml)
1399
+ assert_equal "<a />\n", render("%a/", :format => :xhtml)
1400
+ end
1401
+
1402
+ def test_arbitrary_output_option
1403
+ assert_raise_message(Haml::Error, "Invalid output format :html1") do
1404
+ engine("%br", :format => :html1)
1405
+ end
1406
+ end
1407
+
1408
+ def test_static_hashes
1409
+ assert_equal("<a b='a =&gt; b'></a>\n", render("%a{:b => 'a => b'}", :suppress_eval => true))
1410
+ assert_equal("<a b='a, b'></a>\n", render("%a{:b => 'a, b'}", :suppress_eval => true))
1411
+ assert_equal("<a b='a\tb'></a>\n", render('%a{:b => "a\tb"}', :suppress_eval => true))
1412
+ assert_equal("<a b='a\#{foo}b'></a>\n", render('%a{:b => "a\\#{foo}b"}', :suppress_eval => true))
1413
+ end
1414
+
1415
+ def test_dynamic_hashes_with_suppress_eval
1416
+ assert_equal("<a></a>\n", render('%a{:b => "a #{1 + 1} b", :c => "d"}', :suppress_eval => true))
1417
+ end
1418
+
1419
+ def test_utf8_attrs
1420
+ assert_equal("<a href='héllo'></a>\n", render("%a{:href => 'héllo'}"))
1421
+ assert_equal("<a href='héllo'></a>\n", render("%a(href='héllo')"))
1422
+ end
1423
+
1424
+ # HTML 4.0
1425
+
1426
+ def test_html_has_no_self_closing_tags
1427
+ assert_equal "<p>\n <br>\n</p>\n", render("%p\n %br", :format => :html4)
1428
+ assert_equal "<br>\n", render("%br/", :format => :html4)
1429
+ end
1430
+
1431
+ def test_html_renders_empty_node_with_closing_tag
1432
+ assert_equal "<div class='foo'></div>\n", render(".foo", :format => :html4)
1433
+ end
1434
+
1435
+ def test_html_doesnt_add_slash_to_self_closing_tags
1436
+ assert_equal "<a>\n", render("%a/", :format => :html4)
1437
+ assert_equal "<a foo='2'>\n", render("%a{:foo => 1 + 1}/", :format => :html4)
1438
+ assert_equal "<meta>\n", render("%meta", :format => :html4)
1439
+ assert_equal "<meta foo='2'>\n", render("%meta{:foo => 1 + 1}", :format => :html4)
1440
+ end
1441
+
1442
+ def test_html_ignores_xml_prolog_declaration
1443
+ assert_equal "", render('!!! XML', :format => :html4)
1444
+ end
1445
+
1446
+ def test_html_has_different_doctype
1447
+ assert_equal %{<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n},
1448
+ render('!!!', :format => :html4)
1449
+ end
1450
+
1451
+ # because anything before the doctype triggers quirks mode in IE
1452
+ def test_xml_prolog_and_doctype_dont_result_in_a_leading_whitespace_in_html
1453
+ assert_no_match(/^\s+/, render("!!! xml\n!!!", :format => :html4))
1454
+ end
1455
+
1456
+ # HTML5
1457
+ def test_html5_doctype
1458
+ assert_equal %{<!DOCTYPE html>\n}, render('!!!', :format => :html5)
1459
+ end
1460
+
1461
+ # HTML5 custom data attributes
1462
+ def test_html5_data_attributes
1463
+ assert_equal("<div data-author_id='123' data-biz='baz' data-foo='bar'></div>\n",
1464
+ render("%div{:data => {:author_id => 123, :foo => 'bar', :biz => 'baz'}}"))
1465
+
1466
+ assert_equal("<div data-one_plus_one='2'></div>\n",
1467
+ render("%div{:data => {:one_plus_one => 1+1}}"))
1468
+
1469
+ assert_equal("<div data-foo='Here&apos;s a \"quoteful\" string.'></div>\n",
1470
+ render(%{%div{:data => {:foo => %{Here's a "quoteful" string.}}}})) #'
1471
+ end
1472
+
1473
+ def test_html5_data_attributes_with_multiple_defs
1474
+ # Should always use the more-explicit attribute
1475
+ assert_equal("<div data-foo='second'></div>\n",
1476
+ render("%div{:data => {:foo => 'first'}, 'data-foo' => 'second'}"))
1477
+ assert_equal("<div data-foo='first'></div>\n",
1478
+ render("%div{'data-foo' => 'first', :data => {:foo => 'second'}}"))
1479
+ end
1480
+
1481
+ def test_html5_data_attributes_with_attr_method
1482
+ Haml::Helpers.module_eval do
1483
+ def data_hash
1484
+ {:data => {:foo => "bar", :baz => "bang"}}
1485
+ end
1486
+
1487
+ def data_val
1488
+ {:data => "dat"}
1489
+ end
1490
+ end
1491
+
1492
+ assert_equal("<div data-baz='bang' data-brat='wurst' data-foo='blip'></div>\n",
1493
+ render("%div{data_hash, :data => {:foo => 'blip', :brat => 'wurst'}}"))
1494
+ assert_equal("<div data-baz='bang' data-foo='blip'></div>\n",
1495
+ render("%div{data_hash, 'data-foo' => 'blip'}"))
1496
+ assert_equal("<div data-baz='bang' data-foo='bar' data='dat'></div>\n",
1497
+ render("%div{data_hash, :data => 'dat'}"))
1498
+ assert_equal("<div data-brat='wurst' data-foo='blip' data='dat'></div>\n",
1499
+ render("%div{data_val, :data => {:foo => 'blip', :brat => 'wurst'}}"))
1500
+ end
1501
+
1502
+ # New attributes
1503
+
1504
+ def test_basic_new_attributes
1505
+ assert_equal("<a>bar</a>\n", render("%a() bar"))
1506
+ assert_equal("<a href='foo'>bar</a>\n", render("%a(href='foo') bar"))
1507
+ assert_equal("<a b='c' c='d' d='e'>baz</a>\n", render(%q{%a(b="c" c='d' d="e") baz}))
1508
+ end
1509
+
1510
+ def test_new_attribute_ids
1511
+ assert_equal("<div id='foo_bar'></div>\n", render("#foo(id='bar')"))
1512
+ assert_equal("<div id='foo_baz_bar'></div>\n", render("#foo{:id => 'bar'}(id='baz')"))
1513
+ assert_equal("<div id='foo_baz_bar'></div>\n", render("#foo(id='baz'){:id => 'bar'}"))
1514
+ foo = User.new(42)
1515
+ assert_equal("<div class='struct_user' id='foo_baz_bar_struct_user_42'></div>\n",
1516
+ render("#foo(id='baz'){:id => 'bar'}[foo]", :locals => {:foo => foo}))
1517
+ assert_equal("<div class='struct_user' id='foo_baz_bar_struct_user_42'></div>\n",
1518
+ render("#foo(id='baz')[foo]{:id => 'bar'}", :locals => {:foo => foo}))
1519
+ assert_equal("<div class='struct_user' id='foo_baz_bar_struct_user_42'></div>\n",
1520
+ render("#foo[foo](id='baz'){:id => 'bar'}", :locals => {:foo => foo}))
1521
+ assert_equal("<div class='struct_user' id='foo_baz_bar_struct_user_42'></div>\n",
1522
+ render("#foo[foo]{:id => 'bar'}(id='baz')", :locals => {:foo => foo}))
1523
+ end
1524
+
1525
+ def test_new_attribute_classes
1526
+ assert_equal("<div class='bar foo'></div>\n", render(".foo(class='bar')"))
1527
+ assert_equal("<div class='bar baz foo'></div>\n", render(".foo{:class => 'bar'}(class='baz')"))
1528
+ assert_equal("<div class='bar baz foo'></div>\n", render(".foo(class='baz'){:class => 'bar'}"))
1529
+ foo = User.new(42)
1530
+ assert_equal("<div class='bar baz foo struct_user' id='struct_user_42'></div>\n",
1531
+ render(".foo(class='baz'){:class => 'bar'}[foo]", :locals => {:foo => foo}))
1532
+ assert_equal("<div class='bar baz foo struct_user' id='struct_user_42'></div>\n",
1533
+ render(".foo[foo](class='baz'){:class => 'bar'}", :locals => {:foo => foo}))
1534
+ assert_equal("<div class='bar baz foo struct_user' id='struct_user_42'></div>\n",
1535
+ render(".foo[foo]{:class => 'bar'}(class='baz')", :locals => {:foo => foo}))
1536
+ end
1537
+
1538
+ def test_dynamic_new_attributes
1539
+ assert_equal("<a href='12'>bar</a>\n", render("%a(href=foo) bar", :locals => {:foo => 12}))
1540
+ assert_equal("<a b='12' c='13' d='14'>bar</a>\n", render("%a(b=b c='13' d=d) bar", :locals => {:b => 12, :d => 14}))
1541
+ end
1542
+
1543
+ def test_new_attribute_interpolation
1544
+ assert_equal("<a href='12'>bar</a>\n", render('%a(href="1#{1 + 1}") bar'))
1545
+ assert_equal("<a href='2: 2, 3: 3'>bar</a>\n", render(%q{%a(href='2: #{1 + 1}, 3: #{foo}') bar}, :locals => {:foo => 3}))
1546
+ assert_equal(%Q{<a href='1\#{1 + 1}'>bar</a>\n}, render('%a(href="1\#{1 + 1}") bar'))
1547
+ end
1548
+
1549
+ def test_truthy_new_attributes
1550
+ assert_equal("<a href='href'>bar</a>\n", render("%a(href) bar"))
1551
+ assert_equal("<a bar='baz' href>bar</a>\n", render("%a(href bar='baz') bar", :format => :html5))
1552
+ assert_equal("<a href='href'>bar</a>\n", render("%a(href=true) bar"))
1553
+ assert_equal("<a>bar</a>\n", render("%a(href=false) bar"))
1554
+ end
1555
+
1556
+ def test_new_attribute_parsing
1557
+ assert_equal("<a a2='b2'>bar</a>\n", render("%a(a2=b2) bar", :locals => {:b2 => 'b2'}))
1558
+ assert_equal(%Q{<a a='foo"bar'>bar</a>\n}, render(%q{%a(a="#{'foo"bar'}") bar})) #'
1559
+ assert_equal(%Q{<a a="foo'bar">bar</a>\n}, render(%q{%a(a="#{"foo'bar"}") bar})) #'
1560
+ assert_equal(%Q{<a a='foo"bar'>bar</a>\n}, render(%q{%a(a='foo"bar') bar}))
1561
+ assert_equal(%Q{<a a="foo'bar">bar</a>\n}, render(%q{%a(a="foo'bar") bar}))
1562
+ assert_equal("<a a:b='foo'>bar</a>\n", render("%a(a:b='foo') bar"))
1563
+ assert_equal("<a a='foo' b='bar'>bar</a>\n", render("%a(a = 'foo' b = 'bar') bar"))
1564
+ assert_equal("<a a='foo' b='bar'>bar</a>\n", render("%a(a = foo b = bar) bar", :locals => {:foo => 'foo', :bar => 'bar'}))
1565
+ assert_equal("<a a='foo'>(b='bar')</a>\n", render("%a(a='foo')(b='bar')"))
1566
+ assert_equal("<a a='foo)bar'>baz</a>\n", render("%a(a='foo)bar') baz"))
1567
+ assert_equal("<a a='foo'>baz</a>\n", render("%a( a = 'foo' ) baz"))
1568
+ end
1569
+
1570
+ def test_new_attribute_escaping
1571
+ assert_equal(%Q{<a a='foo " bar'>bar</a>\n}, render(%q{%a(a="foo \" bar") bar}))
1572
+ assert_equal(%Q{<a a='foo \\" bar'>bar</a>\n}, render(%q{%a(a="foo \\\\\" bar") bar}))
1573
+
1574
+ assert_equal(%Q{<a a="foo ' bar">bar</a>\n}, render(%q{%a(a='foo \' bar') bar}))
1575
+ assert_equal(%Q{<a a="foo \\' bar">bar</a>\n}, render(%q{%a(a='foo \\\\\' bar') bar}))
1576
+
1577
+ assert_equal(%Q{<a a='foo \\ bar'>bar</a>\n}, render(%q{%a(a="foo \\\\ bar") bar}))
1578
+ assert_equal(%Q{<a a='foo \#{1 + 1} bar'>bar</a>\n}, render(%q{%a(a="foo \#{1 + 1} bar") bar}))
1579
+ end
1580
+
1581
+ def test_multiline_new_attribute
1582
+ assert_equal("<a a='b' c='d'>bar</a>\n", render("%a(a='b'\n c='d') bar"))
1583
+ assert_equal("<a a='b' b='c' c='d' d='e' e='f' f='j'>bar</a>\n",
1584
+ render("%a(a='b' b='c'\n c='d' d=e\n e='f' f='j') bar", :locals => {:e => 'e'}))
1585
+ end
1586
+
1587
+ def test_new_and_old_attributes
1588
+ assert_equal("<a a='b' c='d'>bar</a>\n", render("%a(a='b'){:c => 'd'} bar"))
1589
+ assert_equal("<a a='b' c='d'>bar</a>\n", render("%a{:c => 'd'}(a='b') bar"))
1590
+ assert_equal("<a a='b' c='d'>bar</a>\n", render("%a(c='d'){:a => 'b'} bar"))
1591
+ assert_equal("<a a='b' c='d'>bar</a>\n", render("%a{:a => 'b'}(c='d') bar"))
1592
+
1593
+ # Old-style always takes precedence over new-style,
1594
+ # because theoretically old-style could have arbitrary end-of-method-call syntax.
1595
+ assert_equal("<a a='b'>bar</a>\n", render("%a{:a => 'b'}(a='d') bar"))
1596
+ assert_equal("<a a='b'>bar</a>\n", render("%a(a='d'){:a => 'b'} bar"))
1597
+
1598
+ assert_equal("<a a='b' b='c' c='d' d='e'>bar</a>\n",
1599
+ render("%a{:a => 'b',\n:b => 'c'}(c='d'\nd='e') bar"))
1600
+
1601
+ locals = {:b => 'b', :d => 'd'}
1602
+ assert_equal("<p a='b' c='d'></p>\n", render("%p{:a => b}(c=d)", :locals => locals))
1603
+ assert_equal("<p a='b' c='d'></p>\n", render("%p(a=b){:c => d}", :locals => locals))
1604
+ end
1605
+
1606
+ # Ruby Multiline
1607
+
1608
+ def test_silent_ruby_multiline
1609
+ assert_equal(<<HTML, render(<<HAML))
1610
+ bar, baz, bang
1611
+ <p>foo</p>
1612
+ HTML
1613
+ - foo = ["bar",
1614
+ "baz",
1615
+ "bang"]
1616
+ = foo.join(", ")
1617
+ %p foo
1618
+ HAML
1619
+ end
1620
+
1621
+ def test_loud_ruby_multiline
1622
+ assert_equal(<<HTML, render(<<HAML))
1623
+ bar, baz, bang
1624
+ <p>foo</p>
1625
+ <p>bar</p>
1626
+ HTML
1627
+ = ["bar",
1628
+ "baz",
1629
+ "bang"].join(", ")
1630
+ %p foo
1631
+ %p bar
1632
+ HAML
1633
+ end
1634
+
1635
+ def test_escaped_loud_ruby_multiline
1636
+ assert_equal(<<HTML, render(<<HAML))
1637
+ bar&lt;, baz, bang
1638
+ <p>foo</p>
1639
+ <p>bar</p>
1640
+ HTML
1641
+ &= ["bar<",
1642
+ "baz",
1643
+ "bang"].join(", ")
1644
+ %p foo
1645
+ %p bar
1646
+ HAML
1647
+ end
1648
+
1649
+ def test_unescaped_loud_ruby_multiline
1650
+ assert_equal(<<HTML, render(<<HAML, :escape_html => true))
1651
+ bar<, baz, bang
1652
+ <p>foo</p>
1653
+ <p>bar</p>
1654
+ HTML
1655
+ != ["bar<",
1656
+ "baz",
1657
+ "bang"].join(", ")
1658
+ %p foo
1659
+ %p bar
1660
+ HAML
1661
+ end
1662
+
1663
+ def test_flattened_loud_ruby_multiline
1664
+ assert_equal(<<HTML, render(<<HAML))
1665
+ <pre>bar&#x000A;baz&#x000A;bang</pre>
1666
+ <p>foo</p>
1667
+ <p>bar</p>
1668
+ HTML
1669
+ ~ "<pre>" + ["bar",
1670
+ "baz",
1671
+ "bang"].join("\\n") + "</pre>"
1672
+ %p foo
1673
+ %p bar
1674
+ HAML
1675
+ end
1676
+
1677
+ def test_loud_ruby_multiline_with_block
1678
+ assert_equal(<<HTML, render(<<HAML))
1679
+ #{%w[far faz fang]}
1680
+ <p>foo</p>
1681
+ <p>bar</p>
1682
+ HTML
1683
+ = ["bar",
1684
+ "baz",
1685
+ "bang"].map do |str|
1686
+ - str.gsub("ba",
1687
+ "fa")
1688
+ %p foo
1689
+ %p bar
1690
+ HAML
1691
+ end
1692
+
1693
+ def test_silent_ruby_multiline_with_block
1694
+ assert_equal(<<HTML, render(<<HAML))
1695
+ far
1696
+ faz
1697
+ fang
1698
+ <p>foo</p>
1699
+ <p>bar</p>
1700
+ HTML
1701
+ - ["bar",
1702
+ "baz",
1703
+ "bang"].map do |str|
1704
+ = str.gsub("ba",
1705
+ "fa")
1706
+ %p foo
1707
+ %p bar
1708
+ HAML
1709
+ end
1710
+
1711
+ def test_ruby_multiline_in_tag
1712
+ assert_equal(<<HTML, render(<<HAML))
1713
+ <p>foo, bar, baz</p>
1714
+ <p>foo</p>
1715
+ <p>bar</p>
1716
+ HTML
1717
+ %p= ["foo",
1718
+ "bar",
1719
+ "baz"].join(", ")
1720
+ %p foo
1721
+ %p bar
1722
+ HAML
1723
+ end
1724
+
1725
+ def test_escaped_ruby_multiline_in_tag
1726
+ assert_equal(<<HTML, render(<<HAML))
1727
+ <p>foo&lt;, bar, baz</p>
1728
+ <p>foo</p>
1729
+ <p>bar</p>
1730
+ HTML
1731
+ %p&= ["foo<",
1732
+ "bar",
1733
+ "baz"].join(", ")
1734
+ %p foo
1735
+ %p bar
1736
+ HAML
1737
+ end
1738
+
1739
+ def test_unescaped_ruby_multiline_in_tag
1740
+ assert_equal(<<HTML, render(<<HAML, :escape_html => true))
1741
+ <p>foo<, bar, baz</p>
1742
+ <p>foo</p>
1743
+ <p>bar</p>
1744
+ HTML
1745
+ %p!= ["foo<",
1746
+ "bar",
1747
+ "baz"].join(", ")
1748
+ %p foo
1749
+ %p bar
1750
+ HAML
1751
+ end
1752
+
1753
+ def test_ruby_multiline_with_normal_multiline
1754
+ assert_equal(<<HTML, render(<<HAML))
1755
+ foobarbar, baz, bang
1756
+ <p>foo</p>
1757
+ <p>bar</p>
1758
+ HTML
1759
+ = "foo" + |
1760
+ "bar" + |
1761
+ ["bar", |
1762
+ "baz",
1763
+ "bang"].join(", ")
1764
+ %p foo
1765
+ %p bar
1766
+ HAML
1767
+ end
1768
+
1769
+ def test_ruby_multiline_after_filter
1770
+ assert_equal(<<HTML, render(<<HAML))
1771
+ foo
1772
+ bar
1773
+ bar, baz, bang
1774
+ <p>foo</p>
1775
+ <p>bar</p>
1776
+ HTML
1777
+ :plain
1778
+ foo
1779
+ bar
1780
+ = ["bar",
1781
+ "baz",
1782
+ "bang"].join(", ")
1783
+ %p foo
1784
+ %p bar
1785
+ HAML
1786
+ end
1787
+
1788
+ # Encodings
1789
+
1790
+ def test_utf_8_bom
1791
+ assert_equal <<HTML, render(<<HAML)
1792
+ <div class='foo'>
1793
+ <p>baz</p>
1794
+ </div>
1795
+ HTML
1796
+ \xEF\xBB\xBF.foo
1797
+ %p baz
1798
+ HAML
1799
+ end
1800
+
1801
+ unless Haml::Util.ruby1_8?
1802
+ def test_default_encoding
1803
+ assert_equal(Encoding.find("utf-8"), render(<<HAML.encode("us-ascii")).encoding)
1804
+ %p bar
1805
+ %p foo
1806
+ HAML
1807
+ end
1808
+
1809
+ def test_fake_ascii_encoding
1810
+ assert_encoded_equal(<<HTML.force_encoding("ascii-8bit"), render(<<HAML, :encoding => "ascii-8bit"))
1811
+ <p>bâr</p>
1812
+ <p>föö</p>
1813
+ HTML
1814
+ %p bâr
1815
+ %p föö
1816
+ HAML
1817
+ end
1818
+
1819
+ def test_convert_template_render_proc
1820
+ assert_converts_template_properly {|e| e.render_proc.call}
1821
+ end
1822
+
1823
+ def test_convert_template_render
1824
+ assert_converts_template_properly {|e| e.render}
1825
+ end
1826
+
1827
+ def test_convert_template_def_method
1828
+ assert_converts_template_properly do |e|
1829
+ o = Object.new
1830
+ e.def_method(o, :render)
1831
+ o.render
1832
+ end
1833
+ end
1834
+
1835
+ def test_encoding_error
1836
+ render("foo\nbar\nb\xFEaz".force_encoding("utf-8"))
1837
+ assert(false, "Expected exception")
1838
+ rescue Haml::Error => e
1839
+ assert_equal(3, e.line)
1840
+ assert_equal('Invalid UTF-8 character "\xFE"', e.message)
1841
+ end
1842
+
1843
+ def test_ascii_incompatible_encoding_error
1844
+ template = "foo\nbar\nb_z".encode("utf-16le")
1845
+ template[9] = "\xFE".force_encoding("utf-16le")
1846
+ render(template)
1847
+ assert(false, "Expected exception")
1848
+ rescue Haml::Error => e
1849
+ assert_equal(3, e.line)
1850
+ assert_equal('Invalid UTF-16LE character "\xFE"', e.message)
1851
+ end
1852
+
1853
+ def test_same_coding_comment_as_encoding
1854
+ assert_renders_encoded(<<HTML, <<HAML)
1855
+ <p>bâr</p>
1856
+ <p>föö</p>
1857
+ HTML
1858
+ -# coding: utf-8
1859
+ %p bâr
1860
+ %p föö
1861
+ HAML
1862
+ end
1863
+
1864
+ def test_coding_comments
1865
+ assert_valid_encoding_comment("-# coding: ibm866")
1866
+ assert_valid_encoding_comment("-# CodINg: IbM866")
1867
+ assert_valid_encoding_comment("-#coding:ibm866")
1868
+ assert_valid_encoding_comment("-# CodINg= ibm866")
1869
+ assert_valid_encoding_comment("-# foo BAR FAOJcoding: ibm866")
1870
+ assert_valid_encoding_comment("-# coding: ibm866 ASFJ (&(&#!$")
1871
+ assert_valid_encoding_comment("-# -*- coding: ibm866")
1872
+ assert_valid_encoding_comment("-# coding: ibm866 -*- coding: blah")
1873
+ assert_valid_encoding_comment("-# -*- coding: ibm866 -*-")
1874
+ assert_valid_encoding_comment("-# -*- encoding: ibm866 -*-")
1875
+ assert_valid_encoding_comment('-# -*- coding: "ibm866" -*-')
1876
+ assert_valid_encoding_comment("-#-*-coding:ibm866-*-")
1877
+ assert_valid_encoding_comment("-#-*-coding:ibm866-*-")
1878
+ assert_valid_encoding_comment("-# -*- foo: bar; coding: ibm866; baz: bang -*-")
1879
+ assert_valid_encoding_comment("-# foo bar coding: baz -*- coding: ibm866 -*-")
1880
+ assert_valid_encoding_comment("-# -*- coding: ibm866 -*- foo bar coding: baz")
1881
+ end
1882
+
1883
+ def test_different_coding_than_system
1884
+ assert_renders_encoded(<<HTML.encode("IBM866"), <<HAML.encode("IBM866"))
1885
+ <p>тАЬ</p>
1886
+ HTML
1887
+ %p тАЬ
1888
+ HAML
1889
+ end
1890
+ end
1891
+
1892
+ private
1893
+
1894
+ def assert_valid_encoding_comment(comment)
1895
+ assert_renders_encoded(<<HTML.encode("IBM866"), <<HAML.encode("IBM866").force_encoding("UTF-8"))
1896
+ <p>ЖЛЫ</p>
1897
+ <p>тАЬ</p>
1898
+ HTML
1899
+ #{comment}
1900
+ %p ЖЛЫ
1901
+ %p тАЬ
1902
+ HAML
1903
+ end
1904
+
1905
+ def assert_converts_template_properly
1906
+ engine = Haml::Engine.new(<<HAML.encode("iso-8859-1"), :encoding => "macRoman")
1907
+ %p bâr
1908
+ %p föö
1909
+ HAML
1910
+ assert_encoded_equal(<<HTML.encode("macRoman"), yield(engine))
1911
+ <p>bâr</p>
1912
+ <p>föö</p>
1913
+ HTML
1914
+ end
1915
+
1916
+ def assert_renders_encoded(html, haml)
1917
+ result = render(haml)
1918
+ assert_encoded_equal html, result
1919
+ end
1920
+
1921
+ def assert_encoded_equal(expected, actual)
1922
+ assert_equal expected.encoding, actual.encoding
1923
+ assert_equal expected, actual
1924
+ end
1925
+ end