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,760 @@
1
+ require 'strscan'
2
+ require 'haml/shared'
3
+
4
+ module Haml
5
+ module Parser
6
+ include Haml::Util
7
+
8
+ # Designates an XHTML/XML element.
9
+ ELEMENT = ?%
10
+
11
+ # Designates a `<div>` element with the given class.
12
+ DIV_CLASS = ?.
13
+
14
+ # Designates a `<div>` element with the given id.
15
+ DIV_ID = ?#
16
+
17
+ # Designates an XHTML/XML comment.
18
+ COMMENT = ?/
19
+
20
+ # Designates an XHTML doctype or script that is never HTML-escaped.
21
+ DOCTYPE = ?!
22
+
23
+ # Designates script, the result of which is output.
24
+ SCRIPT = ?=
25
+
26
+ # Designates script that is always HTML-escaped.
27
+ SANITIZE = ?&
28
+
29
+ # Designates script, the result of which is flattened and output.
30
+ FLAT_SCRIPT = ?~
31
+
32
+ # Designates script which is run but not output.
33
+ SILENT_SCRIPT = ?-
34
+
35
+ # When following SILENT_SCRIPT, designates a comment that is not output.
36
+ SILENT_COMMENT = ?#
37
+
38
+ # Designates a non-parsed line.
39
+ ESCAPE = ?\\
40
+
41
+ # Designates a block of filtered text.
42
+ FILTER = ?:
43
+
44
+ # Designates a non-parsed line. Not actually a character.
45
+ PLAIN_TEXT = -1
46
+
47
+ # Designates a piece of client-side ejs functionality
48
+ HAML_EJS = "^"
49
+ # Designates a client-side interpolated ejs value
50
+ HAML_EJS_INTERPOLATE = /^#{Regexp.escape(HAML_EJS)}=\s+(.*)$/
51
+ # Designates a client-side conditional ejs block
52
+ HAML_EJS_CONDITIONAL = /^#{Regexp.escape(HAML_EJS)}if\s+(.*)$/
53
+ # Designates a client-side negated conditional ejs block
54
+ HAML_EJS_NEGATED_CONDITIONAL = /^#{Regexp.escape(HAML_EJS)}unless\s+(.*)$/
55
+ # Designates a client-side negated conditional ejs block
56
+ HAML_EJS_ELSEIF_CONDITIONAL = /^#{Regexp.escape(HAML_EJS)}elsif\s+(.*)$/
57
+ # Designates a client-side negated conditional ejs block
58
+ HAML_EJS_ELSE_CONDITIONAL = /^#{Regexp.escape(HAML_EJS)}else\s*$/
59
+ # Designates a client-side iteration ejs block
60
+ HAML_EJS_ITERATE = /^#{Regexp.escape(HAML_EJS)}each\s+(.*)$/
61
+
62
+ # Keeps track of the ASCII values of the characters that begin a
63
+ # specially-interpreted line.
64
+ SPECIAL_CHARACTERS = [
65
+ ELEMENT,
66
+ DIV_CLASS,
67
+ DIV_ID,
68
+ COMMENT,
69
+ DOCTYPE,
70
+ SCRIPT,
71
+ SANITIZE,
72
+ FLAT_SCRIPT,
73
+ SILENT_SCRIPT,
74
+ ESCAPE,
75
+ FILTER,
76
+ HAML_EJS
77
+ ]
78
+
79
+ # The value of the character that designates that a line is part
80
+ # of a multiline string.
81
+ MULTILINE_CHAR_VALUE = ?|
82
+
83
+ MID_BLOCK_KEYWORDS = %w[else elsif rescue ensure end when]
84
+ START_BLOCK_KEYWORDS = %w[if begin case]
85
+ # Try to parse assignments to block starters as best as possible
86
+ START_BLOCK_KEYWORD_REGEX = /(?:\w+(?:,\s*\w+)*\s*=\s*)?(#{START_BLOCK_KEYWORDS.join('|')})/
87
+ BLOCK_KEYWORD_REGEX = /^-\s*(?:(#{MID_BLOCK_KEYWORDS.join('|')})|#{START_BLOCK_KEYWORD_REGEX.source})\b/
88
+ HAML_EJS_BLOCK_KEYWORD_REGEX = /^#{Regexp.escape(HAML_EJS)}(if|else|elsif|unless)\s*/
89
+
90
+ # The Regex that matches a Doctype command.
91
+ DOCTYPE_REGEX = /(\d(?:\.\d)?)?[\s]*([a-z]*)\s*([^ ]+)?/i
92
+
93
+ # The Regex that matches a literal string or symbol value
94
+ LITERAL_VALUE_REGEX = /:(\w*)|(["'])((?![\\#]|\2).|\\.)*\2/
95
+
96
+ private
97
+
98
+ # @private
99
+ class Line < Struct.new(:text, :unstripped, :full, :index, :compiler, :eod)
100
+ alias_method :eod?, :eod
101
+
102
+ # @private
103
+ def tabs
104
+ line = self
105
+ @tabs ||= compiler.instance_eval do
106
+ break 0 if line.text.empty? || !(whitespace = line.full[/^\s+/])
107
+
108
+ if @indentation.nil?
109
+ @indentation = whitespace
110
+
111
+ if @indentation.include?(?\s) && @indentation.include?(?\t)
112
+ raise SyntaxError.new("Indentation can't use both tabs and spaces.", line.index)
113
+ end
114
+
115
+ @flat_spaces = @indentation * (@template_tabs+1) if flat?
116
+ break 1
117
+ end
118
+
119
+ tabs = whitespace.length / @indentation.length
120
+ break tabs if whitespace == @indentation * tabs
121
+ break @template_tabs + 1 if flat? && whitespace =~ /^#{@flat_spaces}/
122
+
123
+ raise SyntaxError.new(<<END.strip.gsub("\n", ' '), line.index)
124
+ Inconsistent indentation: #{Haml::Shared.human_indentation whitespace, true} used for indentation,
125
+ but the rest of the document was indented using #{Haml::Shared.human_indentation @indentation}.
126
+ END
127
+ end
128
+ end
129
+ end
130
+
131
+ # @private
132
+ class ParseNode < Struct.new(:type, :line, :value, :parent, :children)
133
+ def initialize(*args)
134
+ super
135
+ self.children ||= []
136
+ end
137
+
138
+ def inspect
139
+ text = "(#{type} #{value.inspect}"
140
+ children.each {|c| text << "\n" << c.inspect.gsub(/^/, " ")}
141
+ text + ")"
142
+ end
143
+ end
144
+
145
+ def parse
146
+ @root = @parent = ParseNode.new(:root)
147
+ @haml_comment = false
148
+ @indentation = nil
149
+ @line = next_line
150
+
151
+ raise SyntaxError.new("Indenting at the beginning of the document is illegal.", @line.index) if @line.tabs != 0
152
+
153
+ while next_line
154
+ process_indent(@line) unless @line.text.empty?
155
+
156
+ if flat?
157
+ text = @line.full.dup
158
+ text = "" unless text.gsub!(/^#{@flat_spaces}/, '')
159
+ @filter_buffer << "#{text}\n"
160
+ @line = @next_line
161
+ next
162
+ end
163
+
164
+ @tab_up = nil
165
+ process_line(@line.text, @line.index) unless @line.text.empty? || @haml_comment
166
+ if @parent.type != :haml_comment && (block_opened? || @tab_up)
167
+ @template_tabs += 1
168
+ @parent = @parent.children.last
169
+ end
170
+
171
+ if !flat? && @next_line.tabs - @line.tabs > 1
172
+ raise SyntaxError.new("The line was indented #{@next_line.tabs - @line.tabs} levels deeper than the previous line.", @next_line.index)
173
+ end
174
+
175
+ @line = @next_line
176
+ end
177
+
178
+ # Close all the open tags
179
+ close until @parent.type == :root
180
+ @root
181
+ end
182
+
183
+ # Processes and deals with lowering indentation.
184
+ def process_indent(line)
185
+ return unless line.tabs <= @template_tabs && @template_tabs > 0
186
+
187
+ to_close = @template_tabs - line.tabs
188
+ to_close.times {|i| close unless to_close - 1 - i == 0 && mid_block_keyword?(line.text)}
189
+ end
190
+
191
+ # Processes a single line of Haml.
192
+ #
193
+ # This method doesn't return anything; it simply processes the line and
194
+ # adds the appropriate code to `@precompiled`.
195
+ def process_line(text, index)
196
+ @index = index + 1
197
+
198
+ case text[0]
199
+ when DIV_CLASS; push div(text)
200
+ when DIV_ID
201
+ return push plain(text) if text[1] == ?{
202
+ push div(text)
203
+ when ELEMENT; push tag(text)
204
+ when COMMENT; push comment(text[1..-1].strip)
205
+ when SANITIZE
206
+ return push plain(text[3..-1].strip, :escape_html) if text[1..2] == "=="
207
+ return push script(text[2..-1].strip, :escape_html) if text[1] == SCRIPT
208
+ return push flat_script(text[2..-1].strip, :escape_html) if text[1] == FLAT_SCRIPT
209
+ return push plain(text[1..-1].strip, :escape_html) if text[1] == ?\s
210
+ push plain(text)
211
+ when SCRIPT
212
+ return push plain(text[2..-1].strip) if text[1] == SCRIPT
213
+ push script(text[1..-1])
214
+ when FLAT_SCRIPT; push flat_script(text[1..-1])
215
+ when SILENT_SCRIPT; push silent_script(text)
216
+ when FILTER; push filter(text[1..-1].downcase)
217
+ when DOCTYPE
218
+ return push doctype(text) if text[0...3] == '!!!'
219
+ return push plain(text[3..-1].strip, !:escape_html) if text[1..2] == "=="
220
+ return push script(text[2..-1].strip, !:escape_html) if text[1] == SCRIPT
221
+ return push flat_script(text[2..-1].strip, !:escape_html) if text[1] == FLAT_SCRIPT
222
+ return push plain(text[1..-1].strip, !:escape_html) if text[1] == ?\s
223
+ push plain(text)
224
+ when ESCAPE; push plain(text[1..-1])
225
+ when HAML_EJS; push haml_ejs(text)
226
+ else; push plain(text)
227
+ end
228
+ end
229
+
230
+ def block_keyword(text)
231
+ if HamlEjs.enabled
232
+ haml_ejs_keyword = text.scan(HAML_EJS_BLOCK_KEYWORD_REGEX)[0]
233
+ return haml_ejs_keyword[0] if haml_ejs_keyword
234
+ end
235
+ return unless keyword = text.scan(BLOCK_KEYWORD_REGEX)[0]
236
+ keyword[0] || keyword[1]
237
+ end
238
+
239
+ def mid_block_keyword?(text)
240
+ MID_BLOCK_KEYWORDS.include?(block_keyword(text))
241
+ end
242
+
243
+ def push(node)
244
+ @parent.children << node
245
+ node.parent = @parent
246
+ end
247
+
248
+ def plain(text, escape_html = nil)
249
+ if block_opened?
250
+ raise SyntaxError.new("Illegal nesting: nesting within plain text is illegal.", @next_line.index)
251
+ end
252
+
253
+ unless contains_interpolation?(text)
254
+ return ParseNode.new(:plain, @index, :text => text)
255
+ end
256
+
257
+ escape_html = @options[:escape_html] if escape_html.nil?
258
+ script(unescape_interpolation(text, escape_html), !:escape_html)
259
+ end
260
+
261
+ def script(text, escape_html = nil, preserve = false)
262
+ raise SyntaxError.new("There's no Ruby code for = to evaluate.") if text.empty?
263
+ text = handle_ruby_multiline(text)
264
+ escape_html = @options[:escape_html] if escape_html.nil?
265
+
266
+ ParseNode.new(:script, @index, :text => text, :escape_html => escape_html,
267
+ :preserve => preserve)
268
+ end
269
+
270
+ def flat_script(text, escape_html = nil)
271
+ raise SyntaxError.new("There's no Ruby code for ~ to evaluate.") if text.empty?
272
+ script(text, escape_html, :preserve)
273
+ end
274
+
275
+ def silent_script(text)
276
+ return haml_comment(text[2..-1]) if text[1] == SILENT_COMMENT
277
+
278
+ raise SyntaxError.new(<<END.rstrip, @index - 1) if text[1..-1].strip == "end"
279
+ You don't need to use "- end" in Haml. Un-indent to close a block:
280
+ - if foo?
281
+ %strong Foo!
282
+ - else
283
+ Not foo.
284
+ %p This line is un-indented, so it isn't part of the "if" block
285
+ END
286
+
287
+ text = handle_ruby_multiline(text)
288
+ keyword = block_keyword(text)
289
+
290
+ @tab_up = ["if", "case"].include?(keyword)
291
+ ParseNode.new(:silent_script, @index,
292
+ :text => text[1..-1], :keyword => keyword)
293
+ end
294
+
295
+ def haml_comment(text)
296
+ @haml_comment = block_opened?
297
+ ParseNode.new(:haml_comment, @index, :text => text)
298
+ end
299
+
300
+ def tag(line)
301
+ tag_name, attributes, attributes_hashes, object_ref, nuke_outer_whitespace,
302
+ nuke_inner_whitespace, action, value, last_line = parse_tag(line)
303
+
304
+ preserve_tag = @options[:preserve].include?(tag_name)
305
+ nuke_inner_whitespace ||= preserve_tag
306
+ preserve_tag = false if @options[:ugly]
307
+ escape_html = (action == '&' || (action != '!' && @options[:escape_html]))
308
+
309
+ case action
310
+ when '/'; self_closing = true
311
+ when '~'; parse = preserve_script = true
312
+ when '='
313
+ parse = true
314
+ if value[0] == ?=
315
+ value = unescape_interpolation(value[1..-1].strip, escape_html)
316
+ escape_html = false
317
+ end
318
+ when '&', '!'
319
+ if value[0] == ?= || value[0] == ?~
320
+ parse = true
321
+ preserve_script = (value[0] == ?~)
322
+ if value[1] == ?=
323
+ value = unescape_interpolation(value[2..-1].strip, escape_html)
324
+ escape_html = false
325
+ else
326
+ value = value[1..-1].strip
327
+ end
328
+ elsif contains_interpolation?(value)
329
+ value = unescape_interpolation(value, escape_html)
330
+ parse = true
331
+ escape_html = false
332
+ end
333
+ else
334
+ if contains_interpolation?(value)
335
+ value = unescape_interpolation(value, escape_html)
336
+ parse = true
337
+ escape_html = false
338
+ end
339
+ end
340
+
341
+ attributes = Parser.parse_class_and_id(attributes)
342
+ attributes_list = []
343
+
344
+ if attributes_hashes[:new]
345
+ static_attributes, attributes_hash = attributes_hashes[:new]
346
+ Buffer.merge_attrs(attributes, static_attributes) if static_attributes
347
+ attributes_list << attributes_hash
348
+ end
349
+
350
+ if attributes_hashes[:old]
351
+ static_attributes = parse_static_hash(attributes_hashes[:old])
352
+ Buffer.merge_attrs(attributes, static_attributes) if static_attributes
353
+ attributes_list << attributes_hashes[:old] unless static_attributes || @options[:suppress_eval]
354
+ end
355
+
356
+ attributes_list.compact!
357
+
358
+ raise SyntaxError.new("Illegal nesting: nesting within a self-closing tag is illegal.", @next_line.index) if block_opened? && self_closing
359
+ raise SyntaxError.new("There's no Ruby code for #{action} to evaluate.", last_line - 1) if parse && value.empty?
360
+ raise SyntaxError.new("Self-closing tags can't have content.", last_line - 1) if self_closing && !value.empty?
361
+
362
+ if block_opened? && !value.empty? && !is_ruby_multiline?(value)
363
+ raise SyntaxError.new("Illegal nesting: content can't be both given on the same line as %#{tag_name} and nested within it.", @next_line.index)
364
+ end
365
+
366
+ self_closing ||= !!(!block_opened? && value.empty? && @options[:autoclose].any? {|t| t === tag_name})
367
+ value = nil if value.empty? && (block_opened? || self_closing)
368
+ value = handle_ruby_multiline(value) if parse
369
+
370
+ ParseNode.new(:tag, @index, :name => tag_name, :attributes => attributes,
371
+ :attributes_hashes => attributes_list, :self_closing => self_closing,
372
+ :nuke_inner_whitespace => nuke_inner_whitespace,
373
+ :nuke_outer_whitespace => nuke_outer_whitespace, :object_ref => object_ref,
374
+ :escape_html => escape_html, :preserve_tag => preserve_tag,
375
+ :preserve_script => preserve_script, :parse => parse, :value => value)
376
+ end
377
+
378
+ # Renders a line that creates an XHTML tag and has an implicit div because of
379
+ # `.` or `#`.
380
+ def div(line)
381
+ tag('%div' + line)
382
+ end
383
+
384
+ # Renders an XHTML comment.
385
+ def comment(line)
386
+ conditional, line = balance(line, ?[, ?]) if line[0] == ?[
387
+ line.strip!
388
+ conditional << ">" if conditional
389
+
390
+ if block_opened? && !line.empty?
391
+ raise SyntaxError.new('Illegal nesting: nesting within a tag that already has content is illegal.', @next_line.index)
392
+ end
393
+
394
+ ParseNode.new(:comment, @index, :conditional => conditional, :text => line)
395
+ end
396
+
397
+ # Renders an XHTML doctype or XML shebang.
398
+ def doctype(line)
399
+ raise SyntaxError.new("Illegal nesting: nesting within a header command is illegal.", @next_line.index) if block_opened?
400
+ version, type, encoding = line[3..-1].strip.downcase.scan(DOCTYPE_REGEX)[0]
401
+ ParseNode.new(:doctype, @index, :version => version, :type => type, :encoding => encoding)
402
+ end
403
+
404
+ def filter(name)
405
+ raise Error.new("Invalid filter name \":#{name}\".") unless name =~ /^\w+$/
406
+
407
+ @filter_buffer = String.new
408
+
409
+ if filter_opened?
410
+ @flat = true
411
+ # If we don't know the indentation by now, it'll be set in Line#tabs
412
+ @flat_spaces = @indentation * (@template_tabs+1) if @indentation
413
+ end
414
+
415
+ ParseNode.new(:filter, @index, :name => name, :text => @filter_buffer)
416
+ end
417
+
418
+ def close
419
+ node, @parent = @parent, @parent.parent
420
+ @template_tabs -= 1
421
+ send("close_#{node.type}", node) if respond_to?("close_#{node.type}", :include_private)
422
+ end
423
+
424
+ def haml_ejs text
425
+ return plain(text) unless HamlEjs.enabled
426
+ case text
427
+ when HAML_EJS_INTERPOLATE; haml_ejs_interpolate($1)
428
+ when HAML_EJS_CONDITIONAL; haml_ejs_conditional($1)
429
+ # when HAML_EJS_NEGATED_CONDITIONAL; haml_ejs_negated_conditional($1)
430
+ when HAML_EJS_ELSE_CONDITIONAL; haml_ejs_conditional($1, :else => true)
431
+ when HAML_EJS_ELSEIF_CONDITIONAL; haml_ejs_conditional($1, :else => true)
432
+ when HAML_EJS_NEGATED_CONDITIONAL; haml_ejs_conditional($1, :negate => true)
433
+ when HAML_EJS_ITERATE; haml_ejs_iterate($1)
434
+ else
435
+ raise SyntaxError.new("Unknow HamlEjs sigil #{text}")
436
+ end
437
+ end
438
+
439
+ def haml_ejs_interpolate text
440
+ ParseNode.new(:ejs_interpolate, @index, :text => text)
441
+ end
442
+
443
+ def haml_ejs_conditional text, options = {}
444
+ ParseNode.new(:ejs_conditional, @index, options.merge(:expression => text))
445
+ end
446
+
447
+ def haml_ejs_iterate text
448
+ ParseNode.new(:ejs_iterate, @index, :collection => text)
449
+ end
450
+
451
+ def close_filter(_)
452
+ @flat = false
453
+ @flat_spaces = nil
454
+ @filter_buffer = nil
455
+ end
456
+
457
+ def close_haml_comment(_)
458
+ @haml_comment = false
459
+ end
460
+
461
+ def close_silent_script(node)
462
+ # Post-process case statements to normalize the nesting of "when" clauses
463
+ return unless node.value[:keyword] == "case"
464
+ return unless first = node.children.first
465
+ return unless first.type == :silent_script && first.value[:keyword] == "when"
466
+ return if first.children.empty?
467
+ # If the case node has a "when" child with children, it's the
468
+ # only child. Then we want to put everything nested beneath it
469
+ # beneath the case itself (just like "if").
470
+ node.children = [first, *first.children]
471
+ first.children = []
472
+ end
473
+
474
+ # This is a class method so it can be accessed from {Haml::Helpers}.
475
+ #
476
+ # Iterates through the classes and ids supplied through `.`
477
+ # and `#` syntax, and returns a hash with them as attributes,
478
+ # that can then be merged with another attributes hash.
479
+ def self.parse_class_and_id(list)
480
+ attributes = {}
481
+ list.scan(/([#.])([-:_a-zA-Z0-9]+)/) do |type, property|
482
+ case type
483
+ when '.'
484
+ if attributes['class']
485
+ attributes['class'] += " "
486
+ else
487
+ attributes['class'] = ""
488
+ end
489
+ attributes['class'] += property
490
+ when '#'; attributes['id'] = property
491
+ end
492
+ end
493
+ attributes
494
+ end
495
+
496
+ def parse_static_hash(text)
497
+ attributes = {}
498
+ scanner = StringScanner.new(text)
499
+ scanner.scan(/\s+/)
500
+ until scanner.eos?
501
+ return unless key = scanner.scan(LITERAL_VALUE_REGEX)
502
+ return unless scanner.scan(/\s*=>\s*/)
503
+ return unless value = scanner.scan(LITERAL_VALUE_REGEX)
504
+ return unless scanner.scan(/\s*(?:,|$)\s*/)
505
+ attributes[eval(key).to_s] = eval(value).to_s
506
+ end
507
+ attributes
508
+ end
509
+
510
+ # Parses a line into tag_name, attributes, attributes_hash, object_ref, action, value
511
+ def parse_tag(line)
512
+ raise SyntaxError.new("Invalid tag: \"#{line}\".") unless match = line.scan(/%([-:\w]+)([-:\w\.\#]*)(.*)/)[0]
513
+
514
+ tag_name, attributes, rest = match
515
+ raise SyntaxError.new("Illegal element: classes and ids must have values.") if attributes =~ /[\.#](\.|#|\z)/
516
+
517
+ new_attributes_hash = old_attributes_hash = last_line = nil
518
+ object_ref = "nil"
519
+ attributes_hashes = {}
520
+ while rest
521
+ case rest[0]
522
+ when ?{
523
+ break if old_attributes_hash
524
+ old_attributes_hash, rest, last_line = parse_old_attributes(rest)
525
+ attributes_hashes[:old] = old_attributes_hash
526
+ when ?(
527
+ break if new_attributes_hash
528
+ new_attributes_hash, rest, last_line = parse_new_attributes(rest)
529
+ attributes_hashes[:new] = new_attributes_hash
530
+ when ?[
531
+ break unless object_ref == "nil"
532
+ object_ref, rest = balance(rest, ?[, ?])
533
+ else; break
534
+ end
535
+ end
536
+
537
+ if rest
538
+ nuke_whitespace, action, value = rest.scan(/(<>|><|[><])?([=\/\~&!])?(.*)?/)[0]
539
+ nuke_whitespace ||= ''
540
+ nuke_outer_whitespace = nuke_whitespace.include? '>'
541
+ nuke_inner_whitespace = nuke_whitespace.include? '<'
542
+ end
543
+
544
+ value = value.to_s.strip
545
+ [tag_name, attributes, attributes_hashes, object_ref, nuke_outer_whitespace,
546
+ nuke_inner_whitespace, action, value, last_line || @index]
547
+ end
548
+
549
+ def parse_old_attributes(line)
550
+ line = line.dup
551
+ last_line = @index
552
+
553
+ begin
554
+ attributes_hash, rest = balance(line, ?{, ?})
555
+ rescue SyntaxError => e
556
+ if line.strip[-1] == ?, && e.message == "Unbalanced brackets."
557
+ line << "\n" << @next_line.text
558
+ last_line += 1
559
+ next_line
560
+ retry
561
+ end
562
+
563
+ raise e
564
+ end
565
+
566
+ attributes_hash = attributes_hash[1...-1] if attributes_hash
567
+ return attributes_hash, rest, last_line
568
+ end
569
+
570
+ def parse_new_attributes(line)
571
+ line = line.dup
572
+ scanner = StringScanner.new(line)
573
+ last_line = @index
574
+ attributes = {}
575
+
576
+ scanner.scan(/\(\s*/)
577
+ loop do
578
+ name, value = parse_new_attribute(scanner)
579
+ break if name.nil?
580
+
581
+ if name == false
582
+ text = (Haml::Shared.balance(line, ?(, ?)) || [line]).first
583
+ raise Haml::SyntaxError.new("Invalid attribute list: #{text.inspect}.", last_line - 1)
584
+ end
585
+ attributes[name] = value
586
+ scanner.scan(/\s*/)
587
+
588
+ if scanner.eos?
589
+ line << " " << @next_line.text
590
+ last_line += 1
591
+ next_line
592
+ scanner.scan(/\s*/)
593
+ end
594
+ end
595
+
596
+ static_attributes = {}
597
+ dynamic_attributes = "{"
598
+ attributes.each do |name, (type, val)|
599
+ if type == :static
600
+ static_attributes[name] = val
601
+ else
602
+ dynamic_attributes << inspect_obj(name) << " => " << val << ","
603
+ end
604
+ end
605
+ dynamic_attributes << "}"
606
+ dynamic_attributes = nil if dynamic_attributes == "{}"
607
+
608
+ return [static_attributes, dynamic_attributes], scanner.rest, last_line
609
+ end
610
+
611
+ def parse_new_attribute(scanner)
612
+ unless name = scanner.scan(/[-:\w]+/)
613
+ return if scanner.scan(/\)/)
614
+ return false
615
+ end
616
+
617
+ scanner.scan(/\s*/)
618
+ return name, [:static, true] unless scanner.scan(/=/) #/end
619
+
620
+ scanner.scan(/\s*/)
621
+ unless quote = scanner.scan(/["']/)
622
+ return false unless var = scanner.scan(/(@@?|\$)?\w+/)
623
+ return name, [:dynamic, var]
624
+ end
625
+
626
+ re = /((?:\\.|\#(?!\{)|[^#{quote}\\#])*)(#{quote}|#\{)/
627
+ content = []
628
+ loop do
629
+ return false unless scanner.scan(re)
630
+ content << [:str, scanner[1].gsub(/\\(.)/, '\1')]
631
+ break if scanner[2] == quote
632
+ content << [:ruby, balance(scanner, ?{, ?}, 1).first[0...-1]]
633
+ end
634
+
635
+ return name, [:static, content.first[1]] if content.size == 1
636
+ return name, [:dynamic,
637
+ '"' + content.map {|(t, v)| t == :str ? inspect_obj(v)[1...-1] : "\#{#{v}}"}.join + '"']
638
+ end
639
+
640
+ def raw_next_line
641
+ text = @template.shift
642
+ return unless text
643
+
644
+ index = @template_index
645
+ @template_index += 1
646
+
647
+ return text, index
648
+ end
649
+
650
+ def next_line
651
+ text, index = raw_next_line
652
+ return unless text
653
+
654
+ # :eod is a special end-of-document marker
655
+ line =
656
+ if text == :eod
657
+ Line.new '-#', '-#', '-#', index, self, true
658
+ else
659
+ Line.new text.strip, text.lstrip.chomp, text, index, self, false
660
+ end
661
+
662
+ # `flat?' here is a little outdated,
663
+ # so we have to manually check if either the previous or current line
664
+ # closes the flat block, as well as whether a new block is opened.
665
+ @line.tabs if @line
666
+ unless (flat? && !closes_flat?(line) && !closes_flat?(@line)) ||
667
+ (@line && @line.text[0] == ?: && line.full =~ %r[^#{@line.full[/^\s+/]}\s])
668
+ return next_line if line.text.empty?
669
+
670
+ handle_multiline(line)
671
+ end
672
+
673
+ @next_line = line
674
+ end
675
+
676
+ def closes_flat?(line)
677
+ line && !line.text.empty? && line.full !~ /^#{@flat_spaces}/
678
+ end
679
+
680
+ def un_next_line(line)
681
+ @template.unshift line
682
+ @template_index -= 1
683
+ end
684
+
685
+ def handle_multiline(line)
686
+ return unless is_multiline?(line.text)
687
+ line.text.slice!(-1)
688
+ while new_line = raw_next_line.first
689
+ break if new_line == :eod
690
+ next if new_line.strip.empty?
691
+ break unless is_multiline?(new_line.strip)
692
+ line.text << new_line.strip[0...-1]
693
+ end
694
+ un_next_line new_line
695
+ end
696
+
697
+ # Checks whether or not `line` is in a multiline sequence.
698
+ def is_multiline?(text)
699
+ text && text.length > 1 && text[-1] == MULTILINE_CHAR_VALUE && text[-2] == ?\s
700
+ end
701
+
702
+ def handle_ruby_multiline(text)
703
+ text = text.rstrip
704
+ return text unless is_ruby_multiline?(text)
705
+ un_next_line @next_line.full
706
+ begin
707
+ new_line = raw_next_line.first
708
+ break if new_line == :eod
709
+ next if new_line.strip.empty?
710
+ text << " " << new_line.strip
711
+ end while is_ruby_multiline?(new_line.strip)
712
+ next_line
713
+ text
714
+ end
715
+
716
+ def is_ruby_multiline?(text)
717
+ text && text.length > 1 && text[-1] == ?, && text[-2] != ?? && text[-3..-2] != "?\\"
718
+ end
719
+
720
+ def contains_interpolation?(str)
721
+ str.include?('#{')
722
+ end
723
+
724
+ def unescape_interpolation(str, escape_html = nil)
725
+ res = ''
726
+ rest = Haml::Shared.handle_interpolation str.dump do |scan|
727
+ escapes = (scan[2].size - 1) / 2
728
+ res << scan.matched[0...-3 - escapes]
729
+ if escapes % 2 == 1
730
+ res << '#{'
731
+ else
732
+ content = eval('"' + balance(scan, ?{, ?}, 1)[0][0...-1] + '"')
733
+ content = "Haml::Helpers.html_escape((#{content}))" if escape_html
734
+ res << '#{' + content + "}"# Use eval to get rid of string escapes
735
+ end
736
+ end
737
+ res + rest
738
+ end
739
+
740
+ def balance(*args)
741
+ res = Haml::Shared.balance(*args)
742
+ return res if res
743
+ raise SyntaxError.new("Unbalanced brackets.")
744
+ end
745
+
746
+ def block_opened?
747
+ @next_line.tabs > @line.tabs
748
+ end
749
+
750
+ # Same semantics as block_opened?, except that block_opened? uses Line#tabs,
751
+ # which doesn't interact well with filter lines
752
+ def filter_opened?
753
+ @next_line.full =~ (@indentation ? /^#{@indentation * @template_tabs}/ : /^\s/)
754
+ end
755
+
756
+ def flat?
757
+ @flat
758
+ end
759
+ end
760
+ end