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,51 @@
1
+ require 'sass/script/literal'
2
+
3
+ module Sass::Script
4
+ # A SassScript object representing a CSS string *or* a CSS identifier.
5
+ class String < Literal
6
+ # The Ruby value of the string.
7
+ #
8
+ # @return [String]
9
+ attr_reader :value
10
+
11
+ # Whether this is a CSS string or a CSS identifier.
12
+ # The difference is that strings are written with double-quotes,
13
+ # while identifiers aren't.
14
+ #
15
+ # @return [Symbol] `:string` or `:identifier`
16
+ attr_reader :type
17
+
18
+ # Creates a new string.
19
+ #
20
+ # @param value [String] See \{#value}
21
+ # @param type [Symbol] See \{#type}
22
+ def initialize(value, type = :identifier)
23
+ super(value)
24
+ @type = type
25
+ end
26
+
27
+ # @see Literal#plus
28
+ def plus(other)
29
+ other_str = other.is_a?(Sass::Script::String) ? other.value : other.to_s
30
+ Sass::Script::String.new(self.value + other_str, self.type)
31
+ end
32
+
33
+ # @see Node#to_s
34
+ def to_s(opts = {})
35
+ if @type == :identifier
36
+ return @value.tr("\n", " ")
37
+ end
38
+
39
+ return "\"#{value.gsub('"', "\\\"")}\"" if opts[:quote] == %q{"}
40
+ return "'#{value.gsub("'", "\\'")}'" if opts[:quote] == %q{'}
41
+ return "\"#{value}\"" unless value.include?('"')
42
+ return "'#{value}'" unless value.include?("'")
43
+ "\"#{value.gsub('"', "\\\"")}\"" #'
44
+ end
45
+
46
+ # @see Node#to_sass
47
+ def to_sass(opts = {})
48
+ to_s
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,94 @@
1
+ module Sass::Script
2
+ # A SassScript object representing `#{}` interpolation within a string.
3
+ #
4
+ # @see Interpolation
5
+ class StringInterpolation < Node
6
+ # Interpolation in a string is of the form `"before #{mid} after"`,
7
+ # where `before` and `after` may include more interpolation.
8
+ #
9
+ # @param before [Node] The string before the interpolation
10
+ # @param mid [Node] The SassScript within the interpolation
11
+ # @param after [Node] The string after the interpolation
12
+ def initialize(before, mid, after)
13
+ @before = before
14
+ @mid = mid
15
+ @after = after
16
+ end
17
+
18
+ # @return [String] A human-readable s-expression representation of the interpolation
19
+ def inspect
20
+ "(string_interpolation #{@before.inspect} #{@mid.inspect} #{@after.inspect})"
21
+ end
22
+
23
+ # @see Node#to_sass
24
+ def to_sass(opts = {})
25
+ # We can get rid of all of this when we remove the deprecated :equals context
26
+ # XXX CE: It's gone now but I'm not sure what can be removed now.
27
+ before_unquote, before_quote_char, before_str = parse_str(@before.to_sass(opts))
28
+ after_unquote, after_quote_char, after_str = parse_str(@after.to_sass(opts))
29
+ unquote = before_unquote || after_unquote ||
30
+ (before_quote_char && !after_quote_char && !after_str.empty?) ||
31
+ (!before_quote_char && after_quote_char && !before_str.empty?)
32
+ quote_char =
33
+ if before_quote_char && after_quote_char && before_quote_char != after_quote_char
34
+ before_str.gsub!("\\'", "'")
35
+ before_str.gsub!('"', "\\\"")
36
+ after_str.gsub!("\\'", "'")
37
+ after_str.gsub!('"', "\\\"")
38
+ '"'
39
+ else
40
+ before_quote_char || after_quote_char
41
+ end
42
+
43
+ res = ""
44
+ res << 'unquote(' if unquote
45
+ res << quote_char if quote_char
46
+ res << before_str
47
+ res << '#{' << @mid.to_sass(opts) << '}'
48
+ res << after_str
49
+ res << quote_char if quote_char
50
+ res << ')' if unquote
51
+ res
52
+ end
53
+
54
+ # Returns the three components of the interpolation, `before`, `mid`, and `after`.
55
+ #
56
+ # @return [Array<Node>]
57
+ # @see #initialize
58
+ # @see Node#children
59
+ def children
60
+ [@before, @mid, @after].compact
61
+ end
62
+
63
+ protected
64
+
65
+ # Evaluates the interpolation.
66
+ #
67
+ # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
68
+ # @return [Sass::Script::String] The SassScript string that is the value of the interpolation
69
+ def _perform(environment)
70
+ res = ""
71
+ before = @before.perform(environment)
72
+ res << before.value
73
+ mid = @mid.perform(environment)
74
+ res << (mid.is_a?(Sass::Script::String) ? mid.value : mid.to_s)
75
+ res << @after.perform(environment).value
76
+ opts(Sass::Script::String.new(res, before.type))
77
+ end
78
+
79
+ private
80
+
81
+ def parse_str(str)
82
+ case str
83
+ when /^unquote\((["'])(.*)\1\)$/
84
+ return true, $1, $2
85
+ when '""'
86
+ return false, nil, ""
87
+ when /^(["'])(.*)\1$/
88
+ return false, $1, $2
89
+ else
90
+ return false, nil, str
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,57 @@
1
+ module Sass::Script
2
+ # A SassScript parse node representing a unary operation,
3
+ # such as `-$b` or `not true`.
4
+ #
5
+ # Currently only `-`, `/`, and `not` are unary operators.
6
+ class UnaryOperation < Node
7
+ # @param operand [Script::Node] The parse-tree node
8
+ # for the object of the operator
9
+ # @param operator [Symbol] The operator to perform
10
+ def initialize(operand, operator)
11
+ @operand = operand
12
+ @operator = operator
13
+ super()
14
+ end
15
+
16
+ # @return [String] A human-readable s-expression representation of the operation
17
+ def inspect
18
+ "(#{@operator.inspect} #{@operand.inspect})"
19
+ end
20
+
21
+ # @see Node#to_sass
22
+ def to_sass(opts = {})
23
+ operand = @operand.to_sass(opts)
24
+ if @operand.is_a?(Operation) ||
25
+ (@operator == :minus &&
26
+ (operand =~ Sass::SCSS::RX::IDENT) == 0)
27
+ operand = "(#{@operand.to_sass(opts)})"
28
+ end
29
+ op = Lexer::OPERATORS_REVERSE[@operator]
30
+ op + (op =~ /[a-z]/ ? " " : "") + operand
31
+ end
32
+
33
+ # Returns the operand of the operation.
34
+ #
35
+ # @return [Array<Node>]
36
+ # @see Node#children
37
+ def children
38
+ [@operand]
39
+ end
40
+
41
+ protected
42
+
43
+ # Evaluates the operation.
44
+ #
45
+ # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
46
+ # @return [Literal] The SassScript object that is the value of the operation
47
+ # @raise [Sass::SyntaxError] if the operation is undefined for the operand
48
+ def _perform(environment)
49
+ operator = "unary_#{@operator}"
50
+ literal = @operand.perform(environment)
51
+ literal.send(operator)
52
+ rescue NoMethodError => e
53
+ raise e unless e.name.to_s == operator.to_s
54
+ raise Sass::SyntaxError.new("Undefined unary operation: \"#{@operator} #{literal}\".")
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,54 @@
1
+ module Sass
2
+ module Script
3
+ # A SassScript parse node representing a variable.
4
+ class Variable < Node
5
+ # The name of the variable.
6
+ #
7
+ # @return [String]
8
+ attr_reader :name
9
+
10
+ # The underscored name of the variable.
11
+ #
12
+ # @return [String]
13
+ attr_reader :underscored_name
14
+
15
+ # @param name [String] See \{#name}
16
+ def initialize(name)
17
+ @name = name
18
+ @underscored_name = name.gsub(/-/,"_")
19
+ super()
20
+ end
21
+
22
+ # @return [String] A string representation of the variable
23
+ def inspect(opts = {})
24
+ return "!important" if name == "important"
25
+ "$#{dasherize(name, opts)}"
26
+ end
27
+ alias_method :to_sass, :inspect
28
+
29
+ # Returns an empty array.
30
+ #
31
+ # @return [Array<Node>] empty
32
+ # @see Node#children
33
+ def children
34
+ []
35
+ end
36
+
37
+ protected
38
+
39
+ # Evaluates the variable.
40
+ #
41
+ # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
42
+ # @return [Literal] The SassScript object that is the value of the variable
43
+ # @raise [Sass::SyntaxError] if the variable is undefined
44
+ def _perform(environment)
45
+ raise SyntaxError.new("Undefined variable: \"$#{name}\".") unless val = environment.var(name)
46
+ if val.is_a?(Number)
47
+ val = val.dup
48
+ val.original = nil
49
+ end
50
+ return val
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,17 @@
1
+ require 'sass/scss/rx'
2
+ require 'sass/scss/script_lexer'
3
+ require 'sass/scss/script_parser'
4
+ require 'sass/scss/parser'
5
+ require 'sass/scss/sass_parser'
6
+ require 'sass/scss/static_parser'
7
+ require 'sass/scss/css_parser'
8
+
9
+ module Sass
10
+ # SCSS is the CSS syntax for Sass.
11
+ # It parses into the same syntax tree as Sass,
12
+ # and generates the same sort of output CSS.
13
+ #
14
+ # This module contains code for the parsing of SCSS.
15
+ # The evaluation is handled by the broader {Sass} module.
16
+ module SCSS; end
17
+ end
@@ -0,0 +1,46 @@
1
+ require 'sass/script/css_parser'
2
+
3
+ module Sass
4
+ module SCSS
5
+ # This is a subclass of {Parser} which only parses plain CSS.
6
+ # It doesn't support any Sass extensions, such as interpolation,
7
+ # parent references, nested selectors, and so forth.
8
+ # It does support all the same CSS hacks as the SCSS parser, though.
9
+ class CssParser < StaticParser
10
+ # Parse a selector, and return its value as a string.
11
+ #
12
+ # @return [String, nil] The parsed selector, or nil if no selector was parsed
13
+ # @raise [Sass::SyntaxError] if there's a syntax error in the selector
14
+ def parse_selector_string
15
+ init_scanner!
16
+ str {return unless selector}
17
+ end
18
+
19
+ private
20
+
21
+ def parent_selector; nil; end
22
+ def interpolation; nil; end
23
+ def interp_string; tok(STRING); end
24
+ def interp_ident(ident = IDENT); tok(ident); end
25
+ def use_css_import?; true; end
26
+
27
+ def block_child(context)
28
+ case context
29
+ when :ruleset
30
+ declaration
31
+ when :stylesheet
32
+ directive || ruleset
33
+ when :directive
34
+ directive || declaration_or_ruleset
35
+ end
36
+ end
37
+
38
+ def nested_properties!(node, space)
39
+ expected('expression (e.g. 1px, bold)');
40
+ end
41
+
42
+ @sass_script_parser = Class.new(Sass::Script::CssParser)
43
+ @sass_script_parser.send(:include, ScriptParser)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,920 @@
1
+ require 'strscan'
2
+ require 'set'
3
+
4
+ module Sass
5
+ module SCSS
6
+ # The parser for SCSS.
7
+ # It parses a string of code into a tree of {Sass::Tree::Node}s.
8
+ class Parser
9
+ # @param str [String, StringScanner] The source document to parse.
10
+ # Note that `Parser` *won't* raise a nice error message if this isn't properly parsed;
11
+ # for that, you should use the higher-level {Sass::Engine} or {Sass::CSS}.
12
+ # @param line [Fixnum] The line on which the source string appeared,
13
+ # if it's part of another document
14
+ def initialize(str, line = 1)
15
+ @template = str
16
+ @line = line
17
+ @strs = []
18
+ end
19
+
20
+ # Parses an SCSS document.
21
+ #
22
+ # @return [Sass::Tree::RootNode] The root node of the document tree
23
+ # @raise [Sass::SyntaxError] if there's a syntax error in the document
24
+ def parse
25
+ init_scanner!
26
+ root = stylesheet
27
+ expected("selector or at-rule") unless @scanner.eos?
28
+ root
29
+ end
30
+
31
+ # Parses an identifier with interpolation.
32
+ # Note that this won't assert that the identifier takes up the entire input string;
33
+ # it's meant to be used with `StringScanner`s as part of other parsers.
34
+ #
35
+ # @return [Array<String, Sass::Script::Node>, nil]
36
+ # The interpolated identifier, or nil if none could be parsed
37
+ def parse_interp_ident
38
+ init_scanner!
39
+ interp_ident
40
+ end
41
+
42
+ private
43
+
44
+ include Sass::SCSS::RX
45
+
46
+ def init_scanner!
47
+ @scanner =
48
+ if @template.is_a?(StringScanner)
49
+ @template
50
+ else
51
+ StringScanner.new(@template.gsub("\r", ""))
52
+ end
53
+ end
54
+
55
+ def stylesheet
56
+ node = node(Sass::Tree::RootNode.new(@scanner.string))
57
+ block_contents(node, :stylesheet) {s(node)}
58
+ end
59
+
60
+ def s(node)
61
+ while tok(S) || tok(CDC) || tok(CDO) || (c = tok(SINGLE_LINE_COMMENT)) || (c = tok(COMMENT))
62
+ next unless c
63
+ process_comment c, node
64
+ c = nil
65
+ end
66
+ true
67
+ end
68
+
69
+ def ss
70
+ nil while tok(S) || tok(SINGLE_LINE_COMMENT) || tok(COMMENT)
71
+ true
72
+ end
73
+
74
+ def ss_comments(node)
75
+ while tok(S) || (c = tok(SINGLE_LINE_COMMENT)) || (c = tok(COMMENT))
76
+ next unless c
77
+ process_comment c, node
78
+ c = nil
79
+ end
80
+
81
+ true
82
+ end
83
+
84
+ def whitespace
85
+ return unless tok(S) || tok(SINGLE_LINE_COMMENT) || tok(COMMENT)
86
+ ss
87
+ end
88
+
89
+ def process_comment(text, node)
90
+ single_line = text =~ /^\/\//
91
+ pre_str = single_line ? "" : @scanner.
92
+ string[0...@scanner.pos].
93
+ reverse[/.*?\*\/(.*?)($|\Z)/, 1].
94
+ reverse.gsub(/[^\s]/, ' ')
95
+ text = text.sub(/^\s*\/\//, '/*').gsub(/^\s*\/\//, ' *') + ' */' if single_line
96
+ comment = Sass::Tree::CommentNode.new(pre_str + text, single_line)
97
+ comment.line = @line - text.count("\n")
98
+ node << comment
99
+ end
100
+
101
+ DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
102
+ :each, :while, :if, :else, :extend, :import, :media, :charset]
103
+
104
+ def directive
105
+ return unless tok(/@/)
106
+ name = tok!(IDENT)
107
+ ss
108
+
109
+ if dir = special_directive(name)
110
+ return dir
111
+ end
112
+
113
+ # Most at-rules take expressions (e.g. @import),
114
+ # but some (e.g. @page) take selector-like arguments
115
+ val = str {break unless expr}
116
+ val ||= CssParser.new(@scanner, @line).parse_selector_string
117
+ node = node(Sass::Tree::DirectiveNode.new("@#{name} #{val}".strip))
118
+
119
+ if tok(/\{/)
120
+ node.has_children = true
121
+ block_contents(node, :directive)
122
+ tok!(/\}/)
123
+ end
124
+
125
+ node
126
+ end
127
+
128
+ def special_directive(name)
129
+ sym = name.gsub('-', '_').to_sym
130
+ DIRECTIVES.include?(sym) && send("#{sym}_directive")
131
+ end
132
+
133
+ def mixin_directive
134
+ name = tok! IDENT
135
+ args = sass_script(:parse_mixin_definition_arglist)
136
+ ss
137
+ block(node(Sass::Tree::MixinDefNode.new(name, args)), :directive)
138
+ end
139
+
140
+ def include_directive
141
+ name = tok! IDENT
142
+ args, keywords = sass_script(:parse_mixin_include_arglist)
143
+ ss
144
+ node(Sass::Tree::MixinNode.new(name, args, keywords))
145
+ end
146
+
147
+ def function_directive
148
+ name = tok! IDENT
149
+ args = sass_script(:parse_function_definition_arglist)
150
+ ss
151
+ block(node(Sass::Tree::FunctionNode.new(name, args)), :function)
152
+ end
153
+
154
+ def return_directive
155
+ node(Sass::Tree::ReturnNode.new(sass_script(:parse)))
156
+ end
157
+
158
+ def debug_directive
159
+ node(Sass::Tree::DebugNode.new(sass_script(:parse)))
160
+ end
161
+
162
+ def warn_directive
163
+ node(Sass::Tree::WarnNode.new(sass_script(:parse)))
164
+ end
165
+
166
+ def for_directive
167
+ tok!(/\$/)
168
+ var = tok! IDENT
169
+ ss
170
+
171
+ tok!(/from/)
172
+ from = sass_script(:parse_until, Set["to", "through"])
173
+ ss
174
+
175
+ @expected = '"to" or "through"'
176
+ exclusive = (tok(/to/) || tok!(/through/)) == 'to'
177
+ to = sass_script(:parse)
178
+ ss
179
+
180
+ block(node(Sass::Tree::ForNode.new(var, from, to, exclusive)), :directive)
181
+ end
182
+
183
+ def each_directive
184
+ tok!(/\$/)
185
+ var = tok! IDENT
186
+ ss
187
+
188
+ tok!(/in/)
189
+ list = sass_script(:parse)
190
+ ss
191
+
192
+ block(node(Sass::Tree::EachNode.new(var, list)), :directive)
193
+ end
194
+
195
+ def while_directive
196
+ expr = sass_script(:parse)
197
+ ss
198
+ block(node(Sass::Tree::WhileNode.new(expr)), :directive)
199
+ end
200
+
201
+ def if_directive
202
+ expr = sass_script(:parse)
203
+ ss
204
+ node = block(node(Sass::Tree::IfNode.new(expr)), :directive)
205
+ pos = @scanner.pos
206
+ line = @line
207
+ ss
208
+
209
+ else_block(node) ||
210
+ begin
211
+ # Backtrack in case there are any comments we want to parse
212
+ @scanner.pos = pos
213
+ @line = line
214
+ node
215
+ end
216
+ end
217
+
218
+ def else_block(node)
219
+ return unless tok(/@else/)
220
+ ss
221
+ else_node = block(
222
+ Sass::Tree::IfNode.new((sass_script(:parse) if tok(/if/))),
223
+ :directive)
224
+ node.add_else(else_node)
225
+ pos = @scanner.pos
226
+ line = @line
227
+ ss
228
+
229
+ else_block(node) ||
230
+ begin
231
+ # Backtrack in case there are any comments we want to parse
232
+ @scanner.pos = pos
233
+ @line = line
234
+ node
235
+ end
236
+ end
237
+
238
+ def else_directive
239
+ err("Invalid CSS: @else must come after @if")
240
+ end
241
+
242
+ def extend_directive
243
+ node(Sass::Tree::ExtendNode.new(expr!(:selector)))
244
+ end
245
+
246
+ def import_directive
247
+ values = []
248
+
249
+ loop do
250
+ values << expr!(:import_arg)
251
+ break if use_css_import? || !tok(/,\s*/)
252
+ end
253
+
254
+ return values
255
+ end
256
+
257
+ def import_arg
258
+ return unless arg = tok(STRING) || (uri = tok!(URI))
259
+ path = @scanner[1] || @scanner[2] || @scanner[3]
260
+ ss
261
+
262
+ media = str {media_query_list}.strip
263
+
264
+ if uri || path =~ /^http:\/\// || !media.strip.empty? || use_css_import?
265
+ return node(Sass::Tree::DirectiveNode.new("@import #{arg} #{media}".strip))
266
+ end
267
+
268
+ node(Sass::Tree::ImportNode.new(path.strip))
269
+ end
270
+
271
+ def use_css_import?; false; end
272
+
273
+ def media_directive
274
+ val = str {media_query_list}.strip
275
+ block(node(Sass::Tree::MediaNode.new(val)), :directive)
276
+ end
277
+
278
+ # http://www.w3.org/TR/css3-mediaqueries/#syntax
279
+ def media_query_list
280
+ return unless media_query
281
+
282
+ ss
283
+ while tok(/,/)
284
+ ss; expr!(:media_query); ss
285
+ end
286
+
287
+ true
288
+ end
289
+
290
+ def media_query
291
+ if tok(/only|not/i)
292
+ ss
293
+ @expected = "media type (e.g. print, screen)"
294
+ tok!(IDENT)
295
+ ss
296
+ elsif !tok(IDENT) && !media_expr
297
+ return
298
+ end
299
+
300
+ ss
301
+ while tok(/and/i)
302
+ ss; expr!(:media_expr); ss
303
+ end
304
+
305
+ true
306
+ end
307
+
308
+ def media_expr
309
+ return unless tok(/\(/)
310
+ ss
311
+ @expected = "media feature (e.g. min-device-width, color)"
312
+ tok!(IDENT)
313
+ ss
314
+
315
+ if tok(/:/)
316
+ ss; expr!(:expr)
317
+ end
318
+ tok!(/\)/)
319
+ ss
320
+
321
+ true
322
+ end
323
+
324
+ def charset_directive
325
+ tok! STRING
326
+ name = @scanner[1] || @scanner[2]
327
+ ss
328
+ node(Sass::Tree::CharsetNode.new(name))
329
+ end
330
+
331
+ def variable
332
+ return unless tok(/\$/)
333
+ name = tok!(IDENT)
334
+ ss; tok!(/:/); ss
335
+
336
+ expr = sass_script(:parse)
337
+ guarded = tok(DEFAULT)
338
+ node(Sass::Tree::VariableNode.new(name, expr, guarded))
339
+ end
340
+
341
+ def operator
342
+ # Many of these operators (all except / and ,)
343
+ # are disallowed by the CSS spec,
344
+ # but they're included here for compatibility
345
+ # with some proprietary MS properties
346
+ str {ss if tok(/[\/,:.=]/)}
347
+ end
348
+
349
+ def unary_operator
350
+ tok(/[+-]/)
351
+ end
352
+
353
+ def ruleset
354
+ return unless rules = selector_sequence
355
+ block(node(Sass::Tree::RuleNode.new(rules.flatten.compact)), :ruleset)
356
+ end
357
+
358
+ def block(node, context)
359
+ node.has_children = true
360
+ tok!(/\{/)
361
+ block_contents(node, context)
362
+ tok!(/\}/)
363
+ node
364
+ end
365
+
366
+ # A block may contain declarations and/or rulesets
367
+ def block_contents(node, context)
368
+ block_given? ? yield : ss_comments(node)
369
+ node << (child = block_child(context))
370
+ while tok(/;/) || has_children?(child)
371
+ block_given? ? yield : ss_comments(node)
372
+ node << (child = block_child(context))
373
+ end
374
+ node
375
+ end
376
+
377
+ def block_child(context)
378
+ return variable || directive if context == :function
379
+ return variable || directive || ruleset if context == :stylesheet
380
+ variable || directive || declaration_or_ruleset
381
+ end
382
+
383
+ def has_children?(child_or_array)
384
+ return false unless child_or_array
385
+ return child_or_array.last.has_children if child_or_array.is_a?(Array)
386
+ return child_or_array.has_children
387
+ end
388
+
389
+ # This is a nasty hack, and the only place in the parser
390
+ # that requires backtracking.
391
+ # The reason is that we can't figure out if certain strings
392
+ # are declarations or rulesets with fixed finite lookahead.
393
+ # For example, "foo:bar baz baz baz..." could be either a property
394
+ # or a selector.
395
+ #
396
+ # To handle this, we simply check if it works as a property
397
+ # (which is the most common case)
398
+ # and, if it doesn't, try it as a ruleset.
399
+ #
400
+ # We could eke some more efficiency out of this
401
+ # by handling some easy cases (first token isn't an identifier,
402
+ # no colon after the identifier, whitespace after the colon),
403
+ # but I'm not sure the gains would be worth the added complexity.
404
+ def declaration_or_ruleset
405
+ old_use_property_exception, @use_property_exception =
406
+ @use_property_exception, false
407
+ decl_err = catch_error do
408
+ decl = declaration
409
+ unless decl && decl.has_children
410
+ # We want an exception if it's not there,
411
+ # but we don't want to consume if it is
412
+ tok!(/[;}]/) unless tok?(/[;}]/)
413
+ end
414
+ return decl
415
+ end
416
+
417
+ ruleset_err = catch_error {return ruleset}
418
+ rethrow(@use_property_exception ? decl_err : ruleset_err)
419
+ ensure
420
+ @use_property_exception = old_use_property_exception
421
+ end
422
+
423
+ def selector_sequence
424
+ if sel = tok(STATIC_SELECTOR)
425
+ return [sel]
426
+ end
427
+
428
+ rules = []
429
+ return unless v = selector
430
+ rules.concat v
431
+
432
+ ws = ''
433
+ while tok(/,/)
434
+ ws << str {ss}
435
+ if v = selector
436
+ rules << ',' << ws
437
+ rules.concat v
438
+ ws = ''
439
+ end
440
+ end
441
+ rules
442
+ end
443
+
444
+ def selector
445
+ return unless sel = _selector
446
+ sel.to_a
447
+ end
448
+
449
+ def selector_comma_sequence
450
+ return unless sel = _selector
451
+ selectors = [sel]
452
+ ws = ''
453
+ while tok(/,/)
454
+ ws << str{ss}
455
+ if sel = _selector
456
+ selectors << sel
457
+ selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members) if ws.include?("\n")
458
+ ws = ''
459
+ end
460
+ end
461
+ Selector::CommaSequence.new(selectors)
462
+ end
463
+
464
+ def _selector
465
+ # The combinator here allows the "> E" hack
466
+ return unless val = combinator || simple_selector_sequence
467
+ nl = str{ss}.include?("\n")
468
+ res = []
469
+ res << val
470
+ res << "\n" if nl
471
+
472
+ while val = combinator || simple_selector_sequence
473
+ res << val
474
+ res << "\n" if str{ss}.include?("\n")
475
+ end
476
+ Selector::Sequence.new(res.compact)
477
+ end
478
+
479
+ def combinator
480
+ tok(PLUS) || tok(GREATER) || tok(TILDE)
481
+ end
482
+
483
+ def simple_selector_sequence
484
+ # This allows for stuff like http://www.w3.org/TR/css3-animations/#keyframes-
485
+ return expr unless e = element_name || id_selector || class_selector ||
486
+ attrib || negation || pseudo || parent_selector || interpolation_selector
487
+ res = [e]
488
+
489
+ # The tok(/\*/) allows the "E*" hack
490
+ while v = element_name || id_selector || class_selector ||
491
+ attrib || negation || pseudo || interpolation_selector ||
492
+ (tok(/\*/) && Selector::Universal.new(nil))
493
+ res << v
494
+ end
495
+
496
+ if tok?(/&/)
497
+ begin
498
+ expected('"{"')
499
+ rescue Sass::SyntaxError => e
500
+ e.message << "\n\n" << <<MESSAGE
501
+ In Sass 3, the parent selector & can only be used where element names are valid,
502
+ since it could potentially be replaced by an element name.
503
+ MESSAGE
504
+ raise e
505
+ end
506
+ end
507
+
508
+ Selector::SimpleSequence.new(res)
509
+ end
510
+
511
+ def parent_selector
512
+ return unless tok(/&/)
513
+ Selector::Parent.new
514
+ end
515
+
516
+ def class_selector
517
+ return unless tok(/\./)
518
+ @expected = "class name"
519
+ Selector::Class.new(merge(expr!(:interp_ident)))
520
+ end
521
+
522
+ def id_selector
523
+ return unless tok(/#(?!\{)/)
524
+ @expected = "id name"
525
+ Selector::Id.new(merge(expr!(:interp_name)))
526
+ end
527
+
528
+ def element_name
529
+ return unless name = interp_ident || tok(/\*/) || (tok?(/\|/) && "")
530
+ if tok(/\|/)
531
+ @expected = "element name or *"
532
+ ns = name
533
+ name = interp_ident || tok!(/\*/)
534
+ end
535
+
536
+ if name == '*'
537
+ Selector::Universal.new(merge(ns))
538
+ else
539
+ Selector::Element.new(merge(name), merge(ns))
540
+ end
541
+ end
542
+
543
+ def interpolation_selector
544
+ return unless script = interpolation
545
+ Selector::Interpolation.new(script)
546
+ end
547
+
548
+ def attrib
549
+ return unless tok(/\[/)
550
+ ss
551
+ ns, name = attrib_name!
552
+ ss
553
+
554
+ if op = tok(/=/) ||
555
+ tok(INCLUDES) ||
556
+ tok(DASHMATCH) ||
557
+ tok(PREFIXMATCH) ||
558
+ tok(SUFFIXMATCH) ||
559
+ tok(SUBSTRINGMATCH)
560
+ @expected = "identifier or string"
561
+ ss
562
+ if val = tok(IDENT)
563
+ val = [val]
564
+ else
565
+ val = expr!(:interp_string)
566
+ end
567
+ ss
568
+ end
569
+ tok(/\]/)
570
+
571
+ Selector::Attribute.new(merge(name), merge(ns), op, merge(val))
572
+ end
573
+
574
+ def attrib_name!
575
+ if name_or_ns = interp_ident
576
+ # E, E|E
577
+ if tok(/\|(?!=)/)
578
+ ns = name_or_ns
579
+ name = interp_ident
580
+ else
581
+ name = name_or_ns
582
+ end
583
+ else
584
+ # *|E or |E
585
+ ns = [tok(/\*/) || ""]
586
+ tok!(/\|/)
587
+ name = expr!(:interp_ident)
588
+ end
589
+ return ns, name
590
+ end
591
+
592
+ def pseudo
593
+ return unless s = tok(/::?/)
594
+ @expected = "pseudoclass or pseudoelement"
595
+ name = expr!(:interp_ident)
596
+ if tok(/\(/)
597
+ ss
598
+ arg = expr!(:pseudo_expr)
599
+ tok!(/\)/)
600
+ end
601
+ Selector::Pseudo.new(s == ':' ? :class : :element, merge(name), merge(arg))
602
+ end
603
+
604
+ def pseudo_expr
605
+ return unless e = tok(PLUS) || tok(/-/) || tok(NUMBER) ||
606
+ interp_string || tok(IDENT) || interpolation
607
+ res = [e, str{ss}]
608
+ while e = tok(PLUS) || tok(/-/) || tok(NUMBER) ||
609
+ interp_string || tok(IDENT) || interpolation
610
+ res << e << str{ss}
611
+ end
612
+ res
613
+ end
614
+
615
+ def negation
616
+ return unless name = tok(NOT) || tok(MOZ_ANY)
617
+ ss
618
+ @expected = "selector"
619
+ sel = selector_comma_sequence
620
+ tok!(/\)/)
621
+ Selector::SelectorPseudoClass.new(name[1...-1], sel)
622
+ end
623
+
624
+ def declaration
625
+ # This allows the "*prop: val", ":prop: val", and ".prop: val" hacks
626
+ if s = tok(/[:\*\.]|\#(?!\{)/)
627
+ @use_property_exception = s !~ /[\.\#]/
628
+ name = [s, str{ss}, *expr!(:interp_ident)]
629
+ else
630
+ return unless name = interp_ident
631
+ name = [name] if name.is_a?(String)
632
+ end
633
+ if comment = tok(COMMENT)
634
+ name << comment
635
+ end
636
+ ss
637
+
638
+ tok!(/:/)
639
+ space, value = value!
640
+ ss
641
+ important = tok(IMPORTANT)
642
+ ss
643
+ require_block = tok?(/\{/)
644
+
645
+ node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, !!important, :new))
646
+
647
+ return node unless require_block
648
+ nested_properties! node, space
649
+ end
650
+
651
+ def value!
652
+ space = !str {ss}.empty?
653
+ @use_property_exception ||= space || !tok?(IDENT)
654
+
655
+ return true, Sass::Script::String.new("") if tok?(/\{/)
656
+ # This is a bit of a dirty trick:
657
+ # if the value is completely static,
658
+ # we don't parse it at all, and instead return a plain old string
659
+ # containing the value.
660
+ # This results in a dramatic speed increase.
661
+ if val = tok(STATIC_VALUE)
662
+ return space, Sass::Script::String.new(val.strip)
663
+ end
664
+ return space, sass_script(:parse)
665
+ end
666
+
667
+ def plain_value
668
+ return unless tok(/:/)
669
+ space = !str {ss}.empty?
670
+ @use_property_exception ||= space || !tok?(IDENT)
671
+
672
+ expression = expr
673
+ expression << tok(IMPORTANT) if expression
674
+ # expression, space, value
675
+ return expression, space, expression || [""]
676
+ end
677
+
678
+ def nested_properties!(node, space)
679
+ err(<<MESSAGE) unless space
680
+ Invalid CSS: a space is required between a property and its definition
681
+ when it has other properties nested beneath it.
682
+ MESSAGE
683
+
684
+ @use_property_exception = true
685
+ @expected = 'expression (e.g. 1px, bold) or "{"'
686
+ block(node, :property)
687
+ end
688
+
689
+ def expr
690
+ return unless t = term
691
+ res = [t, str{ss}]
692
+
693
+ while (o = operator) && (t = term)
694
+ res << o << t << str{ss}
695
+ end
696
+
697
+ res
698
+ end
699
+
700
+ def term
701
+ unless e = tok(NUMBER) ||
702
+ tok(URI) ||
703
+ function ||
704
+ tok(STRING) ||
705
+ tok(UNICODERANGE) ||
706
+ tok(IDENT) ||
707
+ tok(HEXCOLOR)
708
+
709
+ return unless op = unary_operator
710
+ @expected = "number or function"
711
+ return [op, tok(NUMBER) || expr!(:function)]
712
+ end
713
+ e
714
+ end
715
+
716
+ def function
717
+ return unless name = tok(FUNCTION)
718
+ if name == "expression(" || name == "calc("
719
+ str, _ = Sass::Shared.balance(@scanner, ?(, ?), 1)
720
+ [name, str]
721
+ else
722
+ [name, str{ss}, expr, tok!(/\)/)]
723
+ end
724
+ end
725
+
726
+ def interpolation
727
+ return unless tok(INTERP_START)
728
+ sass_script(:parse_interpolated)
729
+ end
730
+
731
+ def interp_string
732
+ _interp_string(:double) || _interp_string(:single)
733
+ end
734
+
735
+ def _interp_string(type)
736
+ return unless start = tok(Sass::Script::Lexer::STRING_REGULAR_EXPRESSIONS[[type, false]])
737
+ res = [start]
738
+
739
+ mid_re = Sass::Script::Lexer::STRING_REGULAR_EXPRESSIONS[[type, true]]
740
+ # @scanner[2].empty? means we've started an interpolated section
741
+ while @scanner[2] == '#{'
742
+ @scanner.pos -= 2 # Don't consume the #{
743
+ res.last.slice!(-2..-1)
744
+ res << expr!(:interpolation) << tok(mid_re)
745
+ end
746
+ res
747
+ end
748
+
749
+ def interp_ident(start = IDENT)
750
+ return unless val = tok(start) || interpolation
751
+ res = [val]
752
+ while val = tok(NAME) || interpolation
753
+ res << val
754
+ end
755
+ res
756
+ end
757
+
758
+ def interp_name
759
+ interp_ident NAME
760
+ end
761
+
762
+ def str
763
+ @strs.push ""
764
+ yield
765
+ @strs.last
766
+ ensure
767
+ @strs.pop
768
+ end
769
+
770
+ def str?
771
+ @strs.push ""
772
+ yield && @strs.last
773
+ ensure
774
+ @strs.pop
775
+ end
776
+
777
+ def node(node)
778
+ node.line = @line
779
+ node
780
+ end
781
+
782
+ @sass_script_parser = Class.new(Sass::Script::Parser)
783
+ @sass_script_parser.send(:include, ScriptParser)
784
+ # @private
785
+ def self.sass_script_parser; @sass_script_parser; end
786
+
787
+ def sass_script(*args)
788
+ parser = self.class.sass_script_parser.new(@scanner, @line,
789
+ @scanner.pos - (@scanner.string[0...@scanner.pos].rindex("\n") || 0))
790
+ result = parser.send(*args)
791
+ @line = parser.line
792
+ result
793
+ rescue Sass::SyntaxError => e
794
+ throw(:_sass_parser_error, true) if @throw_error
795
+ raise e
796
+ end
797
+
798
+ def merge(arr)
799
+ arr && Sass::Util.merge_adjacent_strings([arr].flatten)
800
+ end
801
+
802
+ EXPR_NAMES = {
803
+ :media_query => "media query (e.g. print, screen, print and screen)",
804
+ :media_expr => "media expression (e.g. (min-device-width: 800px)))",
805
+ :pseudo_expr => "expression (e.g. fr, 2n+1)",
806
+ :interp_ident => "identifier",
807
+ :interp_name => "identifier",
808
+ :expr => "expression (e.g. 1px, bold)",
809
+ :_selector => "selector",
810
+ :selector_comma_sequence => "selector",
811
+ :simple_selector_sequence => "selector",
812
+ :import_arg => "file to import (string or url())",
813
+ }
814
+
815
+ TOK_NAMES = Sass::Util.to_hash(
816
+ Sass::SCSS::RX.constants.map {|c| [Sass::SCSS::RX.const_get(c), c.downcase]}).
817
+ merge(IDENT => "identifier", /[;}]/ => '";"')
818
+
819
+ def tok?(rx)
820
+ @scanner.match?(rx)
821
+ end
822
+
823
+ def expr!(name)
824
+ (e = send(name)) && (return e)
825
+ expected(EXPR_NAMES[name] || name.to_s)
826
+ end
827
+
828
+ def tok!(rx)
829
+ (t = tok(rx)) && (return t)
830
+ name = TOK_NAMES[rx]
831
+
832
+ unless name
833
+ # Display basic regexps as plain old strings
834
+ string = rx.source.gsub(/\\(.)/, '\1')
835
+ name = rx.source == Regexp.escape(string) ? string.inspect : rx.inspect
836
+ end
837
+
838
+ expected(name)
839
+ end
840
+
841
+ def expected(name)
842
+ throw(:_sass_parser_error, true) if @throw_error
843
+ self.class.expected(@scanner, @expected || name, @line)
844
+ end
845
+
846
+ def err(msg)
847
+ throw(:_sass_parser_error, true) if @throw_error
848
+ raise Sass::SyntaxError.new(msg, :line => @line)
849
+ end
850
+
851
+ def catch_error(&block)
852
+ old_throw_error, @throw_error = @throw_error, true
853
+ pos = @scanner.pos
854
+ line = @line
855
+ expected = @expected
856
+ if catch(:_sass_parser_error, &block)
857
+ @scanner.pos = pos
858
+ @line = line
859
+ @expected = expected
860
+ {:pos => pos, :line => line, :expected => @expected, :block => block}
861
+ end
862
+ ensure
863
+ @throw_error = old_throw_error
864
+ end
865
+
866
+ def rethrow(err)
867
+ if @throw_err
868
+ throw :_sass_parser_error, err
869
+ else
870
+ @scanner = StringScanner.new(@scanner.string)
871
+ @scanner.pos = err[:pos]
872
+ @line = err[:line]
873
+ @expected = err[:expected]
874
+ err[:block].call
875
+ end
876
+ end
877
+
878
+ # @private
879
+ def self.expected(scanner, expected, line)
880
+ pos = scanner.pos
881
+
882
+ after = scanner.string[0...pos]
883
+ # Get rid of whitespace between pos and the last token,
884
+ # but only if there's a newline in there
885
+ after.gsub!(/\s*\n\s*$/, '')
886
+ # Also get rid of stuff before the last newline
887
+ after.gsub!(/.*\n/, '')
888
+ after = "..." + after[-15..-1] if after.size > 18
889
+
890
+ was = scanner.rest.dup
891
+ # Get rid of whitespace between pos and the next token,
892
+ # but only if there's a newline in there
893
+ was.gsub!(/^\s*\n\s*/, '')
894
+ # Also get rid of stuff after the next newline
895
+ was.gsub!(/\n.*/, '')
896
+ was = was[0...15] + "..." if was.size > 18
897
+
898
+ raise Sass::SyntaxError.new(
899
+ "Invalid CSS after \"#{after}\": expected #{expected}, was \"#{was}\"",
900
+ :line => line)
901
+ end
902
+
903
+ # Avoid allocating lots of new strings for `#tok`.
904
+ # This is important because `#tok` is called all the time.
905
+ NEWLINE = "\n"
906
+
907
+ def tok(rx)
908
+ res = @scanner.scan(rx)
909
+ if res
910
+ @line += res.count(NEWLINE)
911
+ @expected = nil
912
+ if !@strs.empty? && rx != COMMENT && rx != SINGLE_LINE_COMMENT
913
+ @strs.each {|s| s << res}
914
+ end
915
+ res
916
+ end
917
+ end
918
+ end
919
+ end
920
+ end