haml_ejs 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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,29 @@
1
+ module Sass
2
+ module Script
3
+ # This is a subclass of {Lexer} for use in parsing plain CSS properties.
4
+ #
5
+ # @see Sass::SCSS::CssParser
6
+ class CssLexer < Lexer
7
+ private
8
+
9
+ def token
10
+ important || super
11
+ end
12
+
13
+ def string(re, *args)
14
+ if re == :uri
15
+ return unless uri = scan(URI)
16
+ return [:string, Script::String.new(uri)]
17
+ end
18
+
19
+ return unless scan(STRING)
20
+ [:string, Script::String.new((@scanner[1] || @scanner[2]).gsub(/\\(['"])/, '\1'), :string)]
21
+ end
22
+
23
+ def important
24
+ return unless s = scan(IMPORTANT)
25
+ [:raw, s]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,31 @@
1
+ require 'sass/script'
2
+ require 'sass/script/css_lexer'
3
+
4
+ module Sass
5
+ module Script
6
+ # This is a subclass of {Parser} for use in parsing plain CSS properties.
7
+ #
8
+ # @see Sass::SCSS::CssParser
9
+ class CssParser < Parser
10
+ private
11
+
12
+ # @private
13
+ def lexer_class; CssLexer; end
14
+
15
+ # We need a production that only does /,
16
+ # since * and % aren't allowed in plain CSS
17
+ production :div, :unary_plus, :div
18
+
19
+ def string
20
+ return number unless tok = try_tok(:string)
21
+ return tok.value unless @lexer.peek && @lexer.peek.type == :begin_interpolation
22
+ end
23
+
24
+ # Short-circuit all the SassScript-only productions
25
+ alias_method :interpolation, :space
26
+ alias_method :or_expr, :div
27
+ alias_method :unary_div, :ident
28
+ alias_method :paren, :string
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,162 @@
1
+ require 'sass/script/functions'
2
+
3
+ module Sass
4
+ module Script
5
+ # A SassScript parse node representing a function call.
6
+ #
7
+ # A function call either calls one of the functions in {Script::Functions},
8
+ # or if no function with the given name exists
9
+ # it returns a string representation of the function call.
10
+ class Funcall < Node
11
+ # The name of the function.
12
+ #
13
+ # @return [String]
14
+ attr_reader :name
15
+
16
+ # The arguments to the function.
17
+ #
18
+ # @return [Array<Script::Node>]
19
+ attr_reader :args
20
+
21
+ # The keyword arguments to the function.
22
+ #
23
+ # @return [{String => Script::Node}]
24
+ attr_reader :keywords
25
+
26
+ # @param name [String] See \{#name}
27
+ # @param args [Array<Script::Node>] See \{#args}
28
+ # @param keywords [{String => Script::Node}] See \{#keywords}
29
+ def initialize(name, args, keywords)
30
+ @name = name
31
+ @args = args
32
+ @keywords = keywords
33
+ super()
34
+ end
35
+
36
+ # @return [String] A string representation of the function call
37
+ def inspect
38
+ args = @args.map {|a| a.inspect}.join(', ')
39
+ keywords = @keywords.sort_by {|k, v| k}.
40
+ map {|k, v| "$#{k}: #{v.inspect}"}.join(', ')
41
+ "#{name}(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords})"
42
+ end
43
+
44
+ # @see Node#to_sass
45
+ def to_sass(opts = {})
46
+ args = @args.map {|a| a.to_sass(opts)}.join(', ')
47
+ keywords = @keywords.sort_by {|k, v| k}.
48
+ map {|k, v| "$#{dasherize(k, opts)}: #{v.to_sass(opts)}"}.join(', ')
49
+ "#{dasherize(name, opts)}(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords})"
50
+ end
51
+
52
+ # Returns the arguments to the function.
53
+ #
54
+ # @return [Array<Node>]
55
+ # @see Node#children
56
+ def children
57
+ @args + @keywords.values
58
+ end
59
+
60
+ protected
61
+
62
+ # Evaluates the function call.
63
+ #
64
+ # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
65
+ # @return [Literal] The SassScript object that is the value of the function call
66
+ # @raise [Sass::SyntaxError] if the function call raises an ArgumentError
67
+ def _perform(environment)
68
+ args = @args.map {|a| a.perform(environment)}
69
+ if fn = environment.function(@name)
70
+ keywords = Sass::Util.map_hash(@keywords) {|k, v| [k, v.perform(environment)]}
71
+ return perform_sass_fn(fn, args, keywords)
72
+ end
73
+
74
+ ruby_name = @name.tr('-', '_')
75
+ args = construct_ruby_args(ruby_name, args, environment)
76
+
77
+ unless Functions.callable?(ruby_name)
78
+ opts(to_literal(args))
79
+ else
80
+ opts(Functions::EvaluationContext.new(environment.options).send(ruby_name, *args))
81
+ end
82
+ rescue ArgumentError => e
83
+ raise e unless e.backtrace.any? {|t| t =~ /:in `(block in )?(#{name}|perform)'$/}
84
+ raise Sass::SyntaxError.new("#{e.message} for `#{name}'")
85
+ end
86
+
87
+ # This method is factored out from `_perform` so that compass can override
88
+ # it with a cross-browser implementation for functions that require vendor prefixes
89
+ # in the generated css.
90
+ def to_literal(args)
91
+ Script::String.new("#{name}(#{args.join(', ')})")
92
+ end
93
+
94
+ private
95
+
96
+ def construct_ruby_args(name, args, environment)
97
+ unless signature = Functions.signature(name.to_sym, args.size, @keywords.size)
98
+ return args if keywords.empty?
99
+ raise Sass::SyntaxError.new("Function #{name} doesn't support keyword arguments")
100
+ end
101
+ keywords = Sass::Util.map_hash(@keywords) {|k, v| [k, v.perform(environment)]}
102
+
103
+ # If the user passes more non-keyword args than the function expects,
104
+ # but it does expect keyword args, Ruby's arg handling won't raise an error.
105
+ # Since we don't want to make functions think about this,
106
+ # we'll handle it for them here.
107
+ if signature.var_kwargs && !signature.var_args && args.size > signature.args.size
108
+ raise Sass::SyntaxError.new(
109
+ "#{args[signature.args.size].inspect} is not a keyword argument for `#{name}'")
110
+ elsif keywords.empty?
111
+ return args
112
+ end
113
+
114
+ args = args + signature.args[args.size..-1].map do |argname|
115
+ if keywords.has_key?(argname)
116
+ keywords.delete(argname)
117
+ else
118
+ raise Sass::SyntaxError.new("Function #{name} requires an argument named $#{argname}")
119
+ end
120
+ end
121
+
122
+ if keywords.size > 0
123
+ if signature.var_kwargs
124
+ args << keywords
125
+ else
126
+ raise Sass::SyntaxError.new("Function #{name} doesn't take an argument named $#{keywords.keys.sort.first}")
127
+ end
128
+ end
129
+
130
+ args
131
+ end
132
+
133
+ def perform_sass_fn(function, args, keywords)
134
+ # TODO: merge with mixin arg evaluation?
135
+ keywords.each do |name, value|
136
+ # TODO: Make this fast
137
+ unless function.args.find {|(var, default)| var.underscored_name == name}
138
+ raise Sass::SyntaxError.new("Function #{@name} doesn't have an argument named $#{name}")
139
+ end
140
+ end
141
+
142
+ if args.size > function.args.size
143
+ raise ArgumentError.new("Wrong number of arguments (#{args.size} for #{function.args.size})")
144
+ end
145
+
146
+ environment = function.args.zip(args).
147
+ inject(Sass::Environment.new(function.environment)) do |env, ((var, default), value)|
148
+ env.set_local_var(var.name,
149
+ value || keywords[var.underscored_name] || (default && default.perform(env)))
150
+ raise Sass::SyntaxError.new("Function #{@name} is missing parameter #{var.inspect}.") unless env.var(var.name)
151
+ env
152
+ end
153
+
154
+ val = catch :_sass_return do
155
+ function.tree.each {|c| Sass::Tree::Visitors::Perform.visit(c, environment)}
156
+ raise Sass::SyntaxError.new("Function #{@name} finished without @return")
157
+ end
158
+ val
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,1343 @@
1
+ module Sass::Script
2
+ # Methods in this module are accessible from the SassScript context.
3
+ # For example, you can write
4
+ #
5
+ # $color = hsl(120deg, 100%, 50%)
6
+ #
7
+ # and it will call {Sass::Script::Functions#hsl}.
8
+ #
9
+ # The following functions are provided:
10
+ #
11
+ # *Note: These functions are described in more detail below.*
12
+ #
13
+ # ## RGB Functions
14
+ #
15
+ # \{#rgb rgb($red, $green, $blue)}
16
+ # : Converts an `rgb(red, green, blue)` triplet into a color.
17
+ #
18
+ # \{#rgba rgba($red, $green, $blue, $alpha)}
19
+ # : Converts an `rgba(red, green, blue, alpha)` quadruplet into a color.
20
+ #
21
+ # \{#rgba rgba($color, $alpha)}
22
+ # : Adds an alpha layer to any color value.
23
+ #
24
+ # \{#red red($color)}
25
+ # : Gets the red component of a color.
26
+ #
27
+ # \{#green green($color)}
28
+ # : Gets the green component of a color.
29
+ #
30
+ # \{#blue blue($color)}
31
+ # : Gets the blue component of a color.
32
+ #
33
+ # \{#mix mix($color-1, $color-2, \[$weight\])}
34
+ # : Mixes two colors together.
35
+ #
36
+ # ## HSL Functions
37
+ #
38
+ # \{#hsl hsl($hue, $saturation, $lightness)}
39
+ # : Converts an `hsl(hue, saturation, lightness)` triplet into a color.
40
+ #
41
+ # \{#hsla hsla($hue, $saturation, $lightness, $alpha)}
42
+ # : Converts an `hsla(hue, saturation, lightness, alpha)` quadruplet into a color.
43
+ #
44
+ # \{#hue hue($color)}
45
+ # : Gets the hue component of a color.
46
+ #
47
+ # \{#saturation saturation($color)}
48
+ # : Gets the saturation component of a color.
49
+ #
50
+ # \{#lightness lightness($color)}
51
+ # : Gets the lightness component of a color.
52
+ #
53
+ # \{#adjust_hue adjust-hue($color, $degrees)}
54
+ # : Changes the hue of a color.
55
+ #
56
+ # \{#lighten lighten($color, $amount)}
57
+ # : Makes a color lighter.
58
+ #
59
+ # \{#darken darken($color, $amount)}
60
+ # : Makes a color darker.
61
+ #
62
+ # \{#saturate saturate($color, $amount)}
63
+ # : Makes a color more saturated.
64
+ #
65
+ # \{#desaturate desaturate($color, $amount)}
66
+ # : Makes a color less saturated.
67
+ #
68
+ # \{#grayscale grayscale($color)}
69
+ # : Converts a color to grayscale.
70
+ #
71
+ # \{#complement complement($color)}
72
+ # : Returns the complement of a color.
73
+ #
74
+ # \{#invert invert($color)}
75
+ # : Returns the inverse of a color.
76
+ #
77
+ # ## Opacity Functions
78
+ #
79
+ # \{#alpha alpha($color)} / \{#opacity opacity($color)}
80
+ # : Gets the alpha component (opacity) of a color.
81
+ #
82
+ # \{#rgba rgba($color, $alpha)}
83
+ # : Add or change an alpha layer for any color value.
84
+ #
85
+ # \{#opacify opacify($color, $amount)} / \{#fade_in fade-in($color, $amount)}
86
+ # : Makes a color more opaque.
87
+ #
88
+ # \{#transparentize transparentize($color, $amount)} / \{#fade_out fade-out($color, $amount)}
89
+ # : Makes a color more transparent.
90
+ #
91
+ # ## Other Color Functions
92
+ #
93
+ # \{#adjust_color adjust-color($color, \[$red\], \[$green\], \[$blue\], \[$hue\], \[$saturation\], \[$lightness\], \[$alpha\]}
94
+ # : Increase or decrease any of the components of a color.
95
+ #
96
+ # \{#scale_color scale-color($color, \[$red\], \[$green\], \[$blue\], \[$hue\], \[$saturation\], \[$lightness\], \[$alpha\]}
97
+ # : Fluidly scale one or more components of a color.
98
+ #
99
+ # \{#change_color change-color($color, \[$red\], \[$green\], \[$blue\], \[$hue\], \[$saturation\], \[$lightness\], \[$alpha\]}
100
+ # : Changes one or more properties of a color.
101
+ #
102
+ # ## String Functions
103
+ #
104
+ # \{#unquote unquote($string)}
105
+ # : Removes the quotes from a string.
106
+ #
107
+ # \{#quote quote($string)}
108
+ # : Adds quotes to a string.
109
+ #
110
+ # ## Number Functions
111
+ #
112
+ # \{#percentage percentage($value)}
113
+ # : Converts a unitless number to a percentage.
114
+ #
115
+ # \{#round round($value)}
116
+ # : Rounds a number to the nearest whole number.
117
+ #
118
+ # \{#ceil ceil($value)}
119
+ # : Rounds a number up to the nearest whole number.
120
+ #
121
+ # \{#floor floor($value)}
122
+ # : Rounds a number down to the nearest whole number.
123
+ #
124
+ # \{#abs abs($value)}
125
+ # : Returns the absolute value of a number.
126
+ #
127
+ # ## List Functions {#list-functions}
128
+ #
129
+ # \{#length length($list)}
130
+ # : Returns the length of a list.
131
+ #
132
+ # \{#nth nth($list, $n)}
133
+ # : Returns a specific item in a list.
134
+ #
135
+ # \{#join join($list1, $list2, \[$separator\])}
136
+ # : Joins together two lists into one.
137
+ #
138
+ # ## Introspection Functions
139
+ #
140
+ # \{#type_of type-of($value)}
141
+ # : Returns the type of a value.
142
+ #
143
+ # \{#unit unit($number)}
144
+ # : Returns the units associated with a number.
145
+ #
146
+ # \{#unitless unitless($number)}
147
+ # : Returns whether a number has units or not.
148
+ #
149
+ # \{#comparable comparable($number-1, $number-2)}
150
+ # : Returns whether two numbers can be added or compared.
151
+ #
152
+ # ## Miscellaneous Functions
153
+ #
154
+ # \{#if if($condition, $if-true, $if-false)}
155
+ # : Returns one of two values, depending on whether or not a condition is true.
156
+ #
157
+ # ## Adding Custom Functions
158
+ #
159
+ # New Sass functions can be added by adding Ruby methods to this module.
160
+ # For example:
161
+ #
162
+ # module Sass::Script::Functions
163
+ # def reverse(string)
164
+ # assert_type string, :String
165
+ # Sass::Script::String.new(string.value.reverse)
166
+ # end
167
+ # declare :reverse, :args => [:string]
168
+ # end
169
+ #
170
+ # Calling {declare} tells Sass the argument names for your function.
171
+ # If omitted, the function will still work, but will not be able to accept keyword arguments.
172
+ # {declare} can also allow your function to take arbitrary keyword arguments.
173
+ #
174
+ # There are a few things to keep in mind when modifying this module.
175
+ # First of all, the arguments passed are {Sass::Script::Literal} objects.
176
+ # Literal objects are also expected to be returned.
177
+ # This means that Ruby values must be unwrapped and wrapped.
178
+ #
179
+ # Most Literal objects support the {Sass::Script::Literal#value value} accessor
180
+ # for getting their Ruby values.
181
+ # Color objects, though, must be accessed using {Sass::Script::Color#rgb rgb},
182
+ # {Sass::Script::Color#red red}, {Sass::Script::Color#blue green}, or {Sass::Script::Color#blue blue}.
183
+ #
184
+ # Second, making Ruby functions accessible from Sass introduces the temptation
185
+ # to do things like database access within stylesheets.
186
+ # This is generally a bad idea;
187
+ # since Sass files are by default only compiled once,
188
+ # dynamic code is not a great fit.
189
+ #
190
+ # If you really, really need to compile Sass on each request,
191
+ # first make sure you have adequate caching set up.
192
+ # Then you can use {Sass::Engine} to render the code,
193
+ # using the {file:SASS_REFERENCE.md#custom-option `options` parameter}
194
+ # to pass in data that {EvaluationContext#options can be accessed}
195
+ # from your Sass functions.
196
+ #
197
+ # Within one of the functions in this module,
198
+ # methods of {EvaluationContext} can be used.
199
+ #
200
+ # ### Caveats
201
+ #
202
+ # When creating new {Literal} objects within functions,
203
+ # be aware that it's not safe to call {Literal#to_s #to_s}
204
+ # (or other methods that use the string representation)
205
+ # on those objects without first setting {Node#options= the #options attribute}.
206
+ module Functions
207
+ @signatures = {}
208
+
209
+ # A class representing a Sass function signature.
210
+ #
211
+ # @attr args [Array<Symbol>] The names of the arguments to the function.
212
+ # @attr var_args [Boolean] Whether the function takes a variable number of arguments.
213
+ # @attr var_kwargs [Boolean] Whether the function takes an arbitrary set of keyword arguments.
214
+ Signature = Struct.new(:args, :var_args, :var_kwargs)
215
+
216
+ # Declare a Sass signature for a Ruby-defined function.
217
+ # This includes the names of the arguments,
218
+ # whether the function takes a variable number of arguments,
219
+ # and whether the function takes an arbitrary set of keyword arguments.
220
+ #
221
+ # It's not necessary to declare a signature for a function.
222
+ # However, without a signature it won't support keyword arguments.
223
+ #
224
+ # A single function can have multiple signatures declared
225
+ # as long as each one takes a different number of arguments.
226
+ # It's also possible to declare multiple signatures
227
+ # that all take the same number of arguments,
228
+ # but none of them but the first will be used
229
+ # unless the user uses keyword arguments.
230
+ #
231
+ # @param method_name [Symbol] The name of the method
232
+ # whose signature is being declared.
233
+ # @param args [Array<Symbol>] The names of the arguments for the function signature.
234
+ # @option options :var_args [Boolean] (false)
235
+ # Whether the function accepts a variable number of (unnamed) arguments
236
+ # in addition to the named arguments.
237
+ # @option options :var_kwargs [Boolean] (false)
238
+ # Whether the function accepts other keyword arguments
239
+ # in addition to those in `:args`.
240
+ # If this is true, the Ruby function will be passed a hash from strings
241
+ # to {Sass::Script::Literal}s as the last argument.
242
+ # In addition, if this is true and `:var_args` is not,
243
+ # Sass will ensure that the last argument passed is a hash.
244
+ #
245
+ # @example
246
+ # declare :rgba, [:hex, :alpha]
247
+ # declare :rgba, [:red, :green, :blue, :alpha]
248
+ # declare :accepts_anything, [], :var_args => true, :var_kwargs => true
249
+ # declare :some_func, [:foo, :bar, :baz], :var_kwargs => true
250
+ def self.declare(method_name, args, options = {})
251
+ @signatures[method_name] ||= []
252
+ @signatures[method_name] << Signature.new(
253
+ args.map {|s| s.to_s},
254
+ options[:var_args],
255
+ options[:var_kwargs])
256
+ end
257
+
258
+ # Determine the correct signature for the number of arguments
259
+ # passed in for a given function.
260
+ # If no signatures match, the first signature is returned for error messaging.
261
+ #
262
+ # @param method_name [Symbol] The name of the Ruby function to be called.
263
+ # @param arg_arity [Number] The number of unnamed arguments the function was passed.
264
+ # @param kwarg_arity [Number] The number of keyword arguments the function was passed.
265
+ #
266
+ # @return [{Symbol => Object}, nil]
267
+ # The signature options for the matching signature,
268
+ # or nil if no signatures are declared for this function. See {declare}.
269
+ def self.signature(method_name, arg_arity, kwarg_arity)
270
+ return unless @signatures[method_name]
271
+ @signatures[method_name].each do |signature|
272
+ return signature if signature.args.size == arg_arity + kwarg_arity
273
+ next unless signature.args.size < arg_arity + kwarg_arity
274
+
275
+ # We have enough args.
276
+ # Now we need to figure out which args are varargs
277
+ # and if the signature allows them.
278
+ t_arg_arity, t_kwarg_arity = arg_arity, kwarg_arity
279
+ if signature.args.size > t_arg_arity
280
+ # we transfer some kwargs arity to args arity
281
+ # if it does not have enough args -- assuming the names will work out.
282
+ t_kwarg_arity -= (signature.args.size - t_arg_arity)
283
+ t_arg_arity = signature.args.size
284
+ end
285
+
286
+ if ( t_arg_arity == signature.args.size || t_arg_arity > signature.args.size && signature.var_args ) &&
287
+ (t_kwarg_arity == 0 || t_kwarg_arity > 0 && signature.var_kwargs)
288
+ return signature
289
+ end
290
+ end
291
+ @signatures[method_name].first
292
+ end
293
+
294
+ # The context in which methods in {Script::Functions} are evaluated.
295
+ # That means that all instance methods of {EvaluationContext}
296
+ # are available to use in functions.
297
+ class EvaluationContext
298
+ include Functions
299
+
300
+ # The options hash for the {Sass::Engine} that is processing the function call
301
+ #
302
+ # @return [{Symbol => Object}]
303
+ attr_reader :options
304
+
305
+ # @param options [{Symbol => Object}] See \{#options}
306
+ def initialize(options)
307
+ @options = options
308
+ end
309
+
310
+ # Asserts that the type of a given SassScript value
311
+ # is the expected type (designated by a symbol).
312
+ #
313
+ # Valid types are `:Bool`, `:Color`, `:Number`, and `:String`.
314
+ # Note that `:String` will match both double-quoted strings
315
+ # and unquoted identifiers.
316
+ #
317
+ # @example
318
+ # assert_type value, :String
319
+ # assert_type value, :Number
320
+ # @param value [Sass::Script::Literal] A SassScript value
321
+ # @param type [Symbol] The name of the type the value is expected to be
322
+ # @param name [String, nil] The name of the argument.
323
+ def assert_type(value, type, name = nil)
324
+ return if value.is_a?(Sass::Script.const_get(type))
325
+ err = "#{value.inspect} is not a #{type.to_s.downcase}"
326
+ err = "$#{name}: " + err if name
327
+ raise ArgumentError.new(err)
328
+ end
329
+ end
330
+
331
+ class << self
332
+ # Returns whether user function with a given name exists.
333
+ #
334
+ # @param function_name [String]
335
+ # @return [Boolean]
336
+ alias_method :callable?, :public_method_defined?
337
+
338
+ private
339
+ def include(*args)
340
+ r = super
341
+ # We have to re-include ourselves into EvaluationContext to work around
342
+ # an icky Ruby restriction.
343
+ EvaluationContext.send :include, self
344
+ r
345
+ end
346
+ end
347
+
348
+ # Creates a {Color} object from red, green, and blue values.
349
+ #
350
+ # @param red [Number]
351
+ # A number between 0 and 255 inclusive,
352
+ # or between 0% and 100% inclusive
353
+ # @param green [Number]
354
+ # A number between 0 and 255 inclusive,
355
+ # or between 0% and 100% inclusive
356
+ # @param blue [Number]
357
+ # A number between 0 and 255 inclusive,
358
+ # or between 0% and 100% inclusive
359
+ # @see #rgba
360
+ # @return [Color]
361
+ def rgb(red, green, blue)
362
+ assert_type red, :Number
363
+ assert_type green, :Number
364
+ assert_type blue, :Number
365
+
366
+ Color.new([red, green, blue].map do |c|
367
+ v = c.value
368
+ if c.numerator_units == ["%"] && c.denominator_units.empty?
369
+ next v * 255 / 100.0 if (0..100).include?(v)
370
+ raise ArgumentError.new("Color value #{c} must be between 0% and 100% inclusive")
371
+ else
372
+ next v if (0..255).include?(v)
373
+ raise ArgumentError.new("Color value #{v} must be between 0 and 255 inclusive")
374
+ end
375
+ end)
376
+ end
377
+ declare :rgb, [:red, :green, :blue]
378
+
379
+ # @see #rgb
380
+ # @overload rgba(red, green, blue, alpha)
381
+ # Creates a {Color} object from red, green, and blue values,
382
+ # as well as an alpha channel indicating opacity.
383
+ #
384
+ # @param red [Number]
385
+ # A number between 0 and 255 inclusive
386
+ # @param green [Number]
387
+ # A number between 0 and 255 inclusive
388
+ # @param blue [Number]
389
+ # A number between 0 and 255 inclusive
390
+ # @param alpha [Number]
391
+ # A number between 0 and 1
392
+ # @return [Color]
393
+ #
394
+ # @overload rgba(color, alpha)
395
+ # Sets the opacity of a color.
396
+ #
397
+ # @example
398
+ # rgba(#102030, 0.5) => rgba(16, 32, 48, 0.5)
399
+ # rgba(blue, 0.2) => rgba(0, 0, 255, 0.2)
400
+ #
401
+ # @param color [Color]
402
+ # @param alpha [Number]
403
+ # A number between 0 and 1
404
+ # @return [Color]
405
+ def rgba(*args)
406
+ case args.size
407
+ when 2
408
+ color, alpha = args
409
+
410
+ assert_type color, :Color
411
+ assert_type alpha, :Number
412
+
413
+ unless (0..1).include?(alpha.value)
414
+ raise ArgumentError.new("Alpha channel #{alpha.value} must be between 0 and 1 inclusive")
415
+ end
416
+
417
+ color.with(:alpha => alpha.value)
418
+ when 4
419
+ red, green, blue, alpha = args
420
+ rgba(rgb(red, green, blue), alpha)
421
+ else
422
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 4)")
423
+ end
424
+ end
425
+ declare :rgba, [:red, :green, :blue, :alpha]
426
+ declare :rgba, [:color, :alpha]
427
+
428
+ # Creates a {Color} object from hue, saturation, and lightness.
429
+ # Uses the algorithm from the [CSS3 spec](http://www.w3.org/TR/css3-color/#hsl-color).
430
+ #
431
+ # @param hue [Number] The hue of the color.
432
+ # Should be between 0 and 360 degrees, inclusive
433
+ # @param saturation [Number] The saturation of the color.
434
+ # Must be between `0%` and `100%`, inclusive
435
+ # @param lightness [Number] The lightness of the color.
436
+ # Must be between `0%` and `100%`, inclusive
437
+ # @return [Color] The resulting color
438
+ # @see #hsla
439
+ # @raise [ArgumentError] if `saturation` or `lightness` are out of bounds
440
+ def hsl(hue, saturation, lightness)
441
+ hsla(hue, saturation, lightness, Number.new(1))
442
+ end
443
+ declare :hsl, [:hue, :saturation, :lightness]
444
+
445
+ # Creates a {Color} object from hue, saturation, and lightness,
446
+ # as well as an alpha channel indicating opacity.
447
+ # Uses the algorithm from the [CSS3 spec](http://www.w3.org/TR/css3-color/#hsl-color).
448
+ #
449
+ # @param hue [Number] The hue of the color.
450
+ # Should be between 0 and 360 degrees, inclusive
451
+ # @param saturation [Number] The saturation of the color.
452
+ # Must be between `0%` and `100%`, inclusive
453
+ # @param lightness [Number] The lightness of the color.
454
+ # Must be between `0%` and `100%`, inclusive
455
+ # @param alpha [Number] The opacity of the color.
456
+ # Must be between 0 and 1, inclusive
457
+ # @return [Color] The resulting color
458
+ # @see #hsl
459
+ # @raise [ArgumentError] if `saturation`, `lightness`, or `alpha` are out of bounds
460
+ def hsla(hue, saturation, lightness, alpha)
461
+ assert_type hue, :Number
462
+ assert_type saturation, :Number
463
+ assert_type lightness, :Number
464
+ assert_type alpha, :Number
465
+
466
+ unless (0..1).include?(alpha.value)
467
+ raise ArgumentError.new("Alpha channel #{alpha.value} must be between 0 and 1")
468
+ end
469
+
470
+ original_s = saturation
471
+ original_l = lightness
472
+ # This algorithm is from http://www.w3.org/TR/css3-color#hsl-color
473
+ h, s, l = [hue, saturation, lightness].map { |a| a.value }
474
+ raise ArgumentError.new("Saturation #{s} must be between 0% and 100%") unless (0..100).include?(s)
475
+ raise ArgumentError.new("Lightness #{l} must be between 0% and 100%") unless (0..100).include?(l)
476
+
477
+ Color.new(:hue => h, :saturation => s, :lightness => l, :alpha => alpha.value)
478
+ end
479
+ declare :hsla, [:hue, :saturation, :lightness, :alpha]
480
+
481
+ # Returns the red component of a color.
482
+ #
483
+ # @param color [Color]
484
+ # @return [Number]
485
+ # @raise [ArgumentError] If `color` isn't a color
486
+ def red(color)
487
+ assert_type color, :Color
488
+ Sass::Script::Number.new(color.red)
489
+ end
490
+ declare :red, [:color]
491
+
492
+ # Returns the green component of a color.
493
+ #
494
+ # @param color [Color]
495
+ # @return [Number]
496
+ # @raise [ArgumentError] If `color` isn't a color
497
+ def green(color)
498
+ assert_type color, :Color
499
+ Sass::Script::Number.new(color.green)
500
+ end
501
+ declare :green, [:color]
502
+
503
+ # Returns the blue component of a color.
504
+ #
505
+ # @param color [Color]
506
+ # @return [Number]
507
+ # @raise [ArgumentError] If `color` isn't a color
508
+ def blue(color)
509
+ assert_type color, :Color
510
+ Sass::Script::Number.new(color.blue)
511
+ end
512
+ declare :blue, [:color]
513
+
514
+ # Returns the hue component of a color.
515
+ #
516
+ # See [the CSS3 HSL specification](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
517
+ #
518
+ # Calculated from RGB where necessary via [this algorithm](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
519
+ #
520
+ # @param color [Color]
521
+ # @return [Number] between 0deg and 360deg
522
+ # @see #adjust_hue
523
+ # @raise [ArgumentError] if `color` isn't a color
524
+ def hue(color)
525
+ assert_type color, :Color
526
+ Sass::Script::Number.new(color.hue, ["deg"])
527
+ end
528
+ declare :hue, [:color]
529
+
530
+ # Returns the saturation component of a color.
531
+ #
532
+ # See [the CSS3 HSL specification](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
533
+ #
534
+ # Calculated from RGB where necessary via [this algorithm](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
535
+ #
536
+ # @param color [Color]
537
+ # @return [Number] between 0% and 100%
538
+ # @see #saturate
539
+ # @see #desaturate
540
+ # @raise [ArgumentError] if `color` isn't a color
541
+ def saturation(color)
542
+ assert_type color, :Color
543
+ Sass::Script::Number.new(color.saturation, ["%"])
544
+ end
545
+ declare :saturation, [:color]
546
+
547
+ # Returns the hue component of a color.
548
+ #
549
+ # See [the CSS3 HSL specification](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
550
+ #
551
+ # Calculated from RGB where necessary via [this algorithm](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
552
+ #
553
+ # @param color [Color]
554
+ # @return [Number] between 0% and 100%
555
+ # @see #lighten
556
+ # @see #darken
557
+ # @raise [ArgumentError] if `color` isn't a color
558
+ def lightness(color)
559
+ assert_type color, :Color
560
+ Sass::Script::Number.new(color.lightness, ["%"])
561
+ end
562
+ declare :lightness, [:color]
563
+
564
+ # Returns the alpha component (opacity) of a color.
565
+ # This is 1 unless otherwise specified.
566
+ #
567
+ # This function also supports the proprietary Microsoft
568
+ # `alpha(opacity=20)` syntax.
569
+ #
570
+ # @overload def alpha(color)
571
+ # @param color [Color]
572
+ # @return [Number]
573
+ # @see #opacify
574
+ # @see #transparentize
575
+ # @raise [ArgumentError] If `color` isn't a color
576
+ def alpha(*args)
577
+ if args.all? do |a|
578
+ a.is_a?(Sass::Script::String) && a.type == :identifier &&
579
+ a.value =~ /^[a-zA-Z]+\s*=/
580
+ end
581
+ # Support the proprietary MS alpha() function
582
+ return Sass::Script::String.new("alpha(#{args.map {|a| a.to_s}.join(", ")})")
583
+ end
584
+
585
+ opacity(*args)
586
+ end
587
+ declare :alpha, [:color]
588
+
589
+ # Returns the alpha component (opacity) of a color.
590
+ # This is 1 unless otherwise specified.
591
+ #
592
+ # @param color [Color]
593
+ # @return [Number]
594
+ # @see #opacify
595
+ # @see #transparentize
596
+ # @raise [ArgumentError] If `color` isn't a color
597
+ def opacity(color)
598
+ assert_type color, :Color
599
+ Sass::Script::Number.new(color.alpha)
600
+ end
601
+ declare :opacity, [:color]
602
+
603
+ # Makes a color more opaque.
604
+ # Takes a color and an amount between 0 and 1,
605
+ # and returns a color with the opacity increased by that value.
606
+ #
607
+ # @example
608
+ # opacify(rgba(0, 0, 0, 0.5), 0.1) => rgba(0, 0, 0, 0.6)
609
+ # opacify(rgba(0, 0, 17, 0.8), 0.2) => #001
610
+ # @param color [Color]
611
+ # @param amount [Number]
612
+ # @return [Color]
613
+ # @see #transparentize
614
+ # @raise [ArgumentError] If `color` isn't a color,
615
+ # or `number` isn't a number between 0 and 1
616
+ def opacify(color, amount)
617
+ _adjust(color, amount, :alpha, 0..1, :+)
618
+ end
619
+ declare :opacify, [:color, :amount]
620
+
621
+ alias_method :fade_in, :opacify
622
+ declare :fade_in, [:color, :amount]
623
+
624
+ # Makes a color more transparent.
625
+ # Takes a color and an amount between 0 and 1,
626
+ # and returns a color with the opacity decreased by that value.
627
+ #
628
+ # @example
629
+ # transparentize(rgba(0, 0, 0, 0.5), 0.1) => rgba(0, 0, 0, 0.4)
630
+ # transparentize(rgba(0, 0, 0, 0.8), 0.2) => rgba(0, 0, 0, 0.6)
631
+ # @param color [Color]
632
+ # @param amount [Number]
633
+ # @return [Color]
634
+ # @see #opacify
635
+ # @raise [ArgumentError] If `color` isn't a color,
636
+ # or `number` isn't a number between 0 and 1
637
+ def transparentize(color, amount)
638
+ _adjust(color, amount, :alpha, 0..1, :-)
639
+ end
640
+ declare :transparentize, [:color, :amount]
641
+
642
+ alias_method :fade_out, :transparentize
643
+ declare :fade_out, [:color, :amount]
644
+
645
+ # Makes a color lighter.
646
+ # Takes a color and an amount between 0% and 100%,
647
+ # and returns a color with the lightness increased by that value.
648
+ #
649
+ # @example
650
+ # lighten(hsl(0, 0%, 0%), 30%) => hsl(0, 0, 30)
651
+ # lighten(#800, 20%) => #e00
652
+ # @param color [Color]
653
+ # @param amount [Number]
654
+ # @return [Color]
655
+ # @see #darken
656
+ # @raise [ArgumentError] If `color` isn't a color,
657
+ # or `number` isn't a number between 0% and 100%
658
+ def lighten(color, amount)
659
+ _adjust(color, amount, :lightness, 0..100, :+, "%")
660
+ end
661
+ declare :lighten, [:color, :amount]
662
+
663
+ # Makes a color darker.
664
+ # Takes a color and an amount between 0% and 100%,
665
+ # and returns a color with the lightness decreased by that value.
666
+ #
667
+ # @example
668
+ # darken(hsl(25, 100%, 80%), 30%) => hsl(25, 100%, 50%)
669
+ # darken(#800, 20%) => #200
670
+ # @param color [Color]
671
+ # @param amount [Number]
672
+ # @return [Color]
673
+ # @see #lighten
674
+ # @raise [ArgumentError] If `color` isn't a color,
675
+ # or `number` isn't a number between 0% and 100%
676
+ def darken(color, amount)
677
+ _adjust(color, amount, :lightness, 0..100, :-, "%")
678
+ end
679
+ declare :darken, [:color, :amount]
680
+
681
+ # Makes a color more saturated.
682
+ # Takes a color and an amount between 0% and 100%,
683
+ # and returns a color with the saturation increased by that value.
684
+ #
685
+ # @example
686
+ # saturate(hsl(120, 30%, 90%), 20%) => hsl(120, 50%, 90%)
687
+ # saturate(#855, 20%) => #9e3f3f
688
+ # @param color [Color]
689
+ # @param amount [Number]
690
+ # @return [Color]
691
+ # @see #desaturate
692
+ # @raise [ArgumentError] If `color` isn't a color,
693
+ # or `number` isn't a number between 0% and 100%
694
+ def saturate(color, amount)
695
+ _adjust(color, amount, :saturation, 0..100, :+, "%")
696
+ end
697
+ declare :saturate, [:color, :amount]
698
+
699
+ # Makes a color less saturated.
700
+ # Takes a color and an amount between 0% and 100%,
701
+ # and returns a color with the saturation decreased by that value.
702
+ #
703
+ # @example
704
+ # desaturate(hsl(120, 30%, 90%), 20%) => hsl(120, 10%, 90%)
705
+ # desaturate(#855, 20%) => #726b6b
706
+ # @param color [Color]
707
+ # @param amount [Number]
708
+ # @return [Color]
709
+ # @see #saturate
710
+ # @raise [ArgumentError] If `color` isn't a color,
711
+ # or `number` isn't a number between 0% and 100%
712
+ def desaturate(color, amount)
713
+ _adjust(color, amount, :saturation, 0..100, :-, "%")
714
+ end
715
+ declare :desaturate, [:color, :amount]
716
+
717
+ # Changes the hue of a color while retaining the lightness and saturation.
718
+ # Takes a color and a number of degrees (usually between -360deg and 360deg),
719
+ # and returns a color with the hue rotated by that value.
720
+ #
721
+ # @example
722
+ # adjust-hue(hsl(120, 30%, 90%), 60deg) => hsl(180, 30%, 90%)
723
+ # adjust-hue(hsl(120, 30%, 90%), 060deg) => hsl(60, 30%, 90%)
724
+ # adjust-hue(#811, 45deg) => #886a11
725
+ # @param color [Color]
726
+ # @param amount [Number]
727
+ # @return [Color]
728
+ # @raise [ArgumentError] If `color` isn't a color, or `number` isn't a number
729
+ def adjust_hue(color, degrees)
730
+ assert_type color, :Color
731
+ assert_type degrees, :Number
732
+ color.with(:hue => color.hue + degrees.value)
733
+ end
734
+ declare :adjust_hue, [:color, :degrees]
735
+
736
+ # Adjusts one or more properties of a color.
737
+ # This can change the red, green, blue, hue, saturation, value, and alpha properties.
738
+ # The properties are specified as keyword arguments,
739
+ # and are added to or subtracted from the color's current value for that property.
740
+ #
741
+ # `$red`, `$green`, and `$blue` properties should be between 0 and 255.
742
+ # `$saturation` and `$lightness` should be between 0% and 100%.
743
+ # `$alpha` should be between 0 and 1.
744
+ #
745
+ # All properties are optional.
746
+ # You can't specify both RGB properties (`$red`, `$green`, `$blue`)
747
+ # and HSL properties (`$hue`, `$saturation`, `$value`) at the same time.
748
+ #
749
+ # @example
750
+ # adjust-color(#102030, $blue: 5) => #102035
751
+ # adjust-color(#102030, $red: -5, $blue: 5) => #0b2035
752
+ # adjust-color(hsl(25, 100%, 80%), $lightness: -30%, $alpha: -0.4) => hsla(25, 100%, 50%, 0.6)
753
+ # @param color [Color]
754
+ # @param red [Number]
755
+ # @param green [Number]
756
+ # @param blue [Number]
757
+ # @param hue [Number]
758
+ # @param saturation [Number]
759
+ # @param lightness [Number]
760
+ # @param alpha [Number]
761
+ # @return [Color]
762
+ # @raise [ArgumentError] if `color` is not a color,
763
+ # if any keyword argument is not a number,
764
+ # if any keyword argument is not in the legal range,
765
+ # if an unexpected keyword argument is given,
766
+ # or if both HSL and RGB properties are given.
767
+ def adjust_color(color, kwargs)
768
+ assert_type color, :Color
769
+ with = Sass::Util.map_hash({
770
+ "red" => [-255..255, ""],
771
+ "green" => [-255..255, ""],
772
+ "blue" => [-255..255, ""],
773
+ "hue" => nil,
774
+ "saturation" => [-100..100, "%"],
775
+ "lightness" => [-100..100, "%"],
776
+ "alpha" => [-1..1, ""]
777
+ }) do |name, (range, units)|
778
+
779
+ next unless val = kwargs.delete(name)
780
+ assert_type val, :Number, name
781
+ if range && !range.include?(val.value)
782
+ raise ArgumentError.new("$#{name}: Amount #{val} must be between #{range.first}#{units} and #{range.last}#{units}")
783
+ end
784
+ adjusted = color.send(name) + val.value
785
+ adjusted = [0, Sass::Util.restrict(adjusted, range)].max if range
786
+ [name.to_sym, adjusted]
787
+ end
788
+
789
+ unless kwargs.empty?
790
+ name, val = kwargs.to_a.first
791
+ raise ArgumentError.new("Unknown argument $#{name} (#{val})")
792
+ end
793
+
794
+ color.with(with)
795
+ end
796
+ declare :adjust_color, [:color], :var_kwargs => true
797
+
798
+ # Scales one or more properties of a color by a percentage value.
799
+ # Unlike \{#adjust_color adjust-color}, which changes a color's properties by fixed amounts,
800
+ # \{#scale_color scale-color} fluidly changes them based on how high or low they already are.
801
+ # That means that lightening an already-light color with \{#scale_color scale-color}
802
+ # won't change the lightness much,
803
+ # but lightening a dark color by the same amount will change it more dramatically.
804
+ # This has the benefit of making `scale-color($color, ...)` have a similar effect
805
+ # regardless of what `$color` is.
806
+ #
807
+ # For example, the lightness of a color can be anywhere between 0 and 100.
808
+ # If `scale-color($color, $lightness: 40%)` is called, the resulting color's lightness
809
+ # will be 40% of the way between its original lightness and 100.
810
+ # If `scale-color($color, $lightness: -40%)` is called instead,
811
+ # the lightness will be 40% of the way between the original and 0.
812
+ #
813
+ # This can change the red, green, blue, saturation, value, and alpha properties.
814
+ # The properties are specified as keyword arguments.
815
+ # All arguments should be percentages between 0% and 100%.
816
+ #
817
+ # All properties are optional.
818
+ # You can't specify both RGB properties (`$red`, `$green`, `$blue`)
819
+ # and HSL properties (`$saturation`, `$value`) at the same time.
820
+ #
821
+ # @example
822
+ # scale-color(hsl(120, 70, 80), $lightness: 50%) => hsl(120, 70, 90)
823
+ # scale-color(rgb(200, 150, 170), $green: -40%, $blue: 70%) => rgb(200, 90, 229)
824
+ # scale-color(hsl(200, 70, 80), $saturation: -90%, $alpha: -30%) => hsla(200, 7, 80, 0.7)
825
+ # @param color [Color]
826
+ # @param red [Number]
827
+ # @param green [Number]
828
+ # @param blue [Number]
829
+ # @param saturation [Number]
830
+ # @param lightness [Number]
831
+ # @param alpha [Number]
832
+ # @return [Color]
833
+ # @raise [ArgumentError] if `color` is not a color,
834
+ # if any keyword argument is not a percentage between 0% and 100%,
835
+ # if an unexpected keyword argument is given,
836
+ # or if both HSL and RGB properties are given.
837
+ def scale_color(color, kwargs)
838
+ assert_type color, :Color
839
+ with = Sass::Util.map_hash({
840
+ "red" => 255,
841
+ "green" => 255,
842
+ "blue" => 255,
843
+ "saturation" => 100,
844
+ "lightness" => 100,
845
+ "alpha" => 1
846
+ }) do |name, max|
847
+
848
+ next unless val = kwargs.delete(name)
849
+ assert_type val, :Number, name
850
+ if !(val.numerator_units == ['%'] && val.denominator_units.empty?)
851
+ raise ArgumentError.new("$#{name}: Amount #{val} must be a % (e.g. #{val.value}%)")
852
+ elsif !(-100..100).include?(val.value)
853
+ raise ArgumentError.new("$#{name}: Amount #{val} must be between -100% and 100%")
854
+ end
855
+
856
+ current = color.send(name)
857
+ scale = val.value/100.0
858
+ diff = scale > 0 ? max - current : current
859
+ [name.to_sym, current + diff*scale]
860
+ end
861
+
862
+ unless kwargs.empty?
863
+ name, val = kwargs.to_a.first
864
+ raise ArgumentError.new("Unknown argument $#{name} (#{val})")
865
+ end
866
+
867
+ color.with(with)
868
+ end
869
+ declare :scale_color, [:color], :var_kwargs => true
870
+
871
+ # Changes one or more properties of a color.
872
+ # This can change the red, green, blue, hue, saturation, value, and alpha properties.
873
+ # The properties are specified as keyword arguments,
874
+ # and replace the color's current value for that property.
875
+ #
876
+ # `$red`, `$green`, and `$blue` properties should be between 0 and 255.
877
+ # `$saturation` and `$lightness` should be between 0% and 100%.
878
+ # `$alpha` should be between 0 and 1.
879
+ #
880
+ # All properties are optional.
881
+ # You can't specify both RGB properties (`$red`, `$green`, `$blue`)
882
+ # and HSL properties (`$hue`, `$saturation`, `$value`) at the same time.
883
+ #
884
+ # @example
885
+ # change-color(#102030, $blue: 5) => #102005
886
+ # change-color(#102030, $red: 120, $blue: 5) => #782005
887
+ # change-color(hsl(25, 100%, 80%), $lightness: 40%, $alpha: 0.8) => hsla(25, 100%, 40%, 0.8)
888
+ # @param color [Color]
889
+ # @param red [Number]
890
+ # @param green [Number]
891
+ # @param blue [Number]
892
+ # @param hue [Number]
893
+ # @param saturation [Number]
894
+ # @param lightness [Number]
895
+ # @param alpha [Number]
896
+ # @return [Color]
897
+ # @raise [ArgumentError] if `color` is not a color,
898
+ # if any keyword argument is not a number,
899
+ # if any keyword argument is not in the legal range,
900
+ # if an unexpected keyword argument is given,
901
+ # or if both HSL and RGB properties are given.
902
+ def change_color(color, kwargs)
903
+ assert_type color, :Color
904
+ with = Sass::Util.map_hash(%w[red green blue hue saturation lightness alpha]) do |name, max|
905
+ next unless val = kwargs.delete(name)
906
+ assert_type val, :Number, name
907
+ [name.to_sym, val.value]
908
+ end
909
+
910
+ unless kwargs.empty?
911
+ name, val = kwargs.to_a.first
912
+ raise ArgumentError.new("Unknown argument $#{name} (#{val})")
913
+ end
914
+
915
+ color.with(with)
916
+ end
917
+ declare :change_color, [:color], :var_kwargs => true
918
+
919
+ # Mixes together two colors.
920
+ # Specifically, takes the average of each of the RGB components,
921
+ # optionally weighted by the given percentage.
922
+ # The opacity of the colors is also considered when weighting the components.
923
+ #
924
+ # The weight specifies the amount of the first color that should be included
925
+ # in the returned color.
926
+ # The default, 50%, means that half the first color
927
+ # and half the second color should be used.
928
+ # 25% means that a quarter of the first color
929
+ # and three quarters of the second color should be used.
930
+ #
931
+ # @example
932
+ # mix(#f00, #00f) => #7f007f
933
+ # mix(#f00, #00f, 25%) => #3f00bf
934
+ # mix(rgba(255, 0, 0, 0.5), #00f) => rgba(63, 0, 191, 0.75)
935
+ # @overload mix(color1, color2, weight: 50%)
936
+ # @param color1 [Color]
937
+ # @param color2 [Color]
938
+ # @param weight [Number] between 0% and 100%
939
+ # @return [Color]
940
+ # @raise [ArgumentError] if `color1` or `color2` aren't colors,
941
+ # or `weight` isn't a number between 0% and 100%
942
+ def mix(color1, color2, weight = Number.new(50))
943
+ assert_type color1, :Color
944
+ assert_type color2, :Color
945
+ assert_type weight, :Number
946
+
947
+ unless (0..100).include?(weight.value)
948
+ raise ArgumentError.new("Weight #{weight} must be between 0% and 100%")
949
+ end
950
+
951
+ # This algorithm factors in both the user-provided weight
952
+ # and the difference between the alpha values of the two colors
953
+ # to decide how to perform the weighted average of the two RGB values.
954
+ #
955
+ # It works by first normalizing both parameters to be within [-1, 1],
956
+ # where 1 indicates "only use color1", -1 indicates "only use color 0",
957
+ # and all values in between indicated a proportionately weighted average.
958
+ #
959
+ # Once we have the normalized variables w and a,
960
+ # we apply the formula (w + a)/(1 + w*a)
961
+ # to get the combined weight (in [-1, 1]) of color1.
962
+ # This formula has two especially nice properties:
963
+ #
964
+ # * When either w or a are -1 or 1, the combined weight is also that number
965
+ # (cases where w * a == -1 are undefined, and handled as a special case).
966
+ #
967
+ # * When a is 0, the combined weight is w, and vice versa
968
+ #
969
+ # Finally, the weight of color1 is renormalized to be within [0, 1]
970
+ # and the weight of color2 is given by 1 minus the weight of color1.
971
+ p = weight.value/100.0
972
+ w = p*2 - 1
973
+ a = color1.alpha - color2.alpha
974
+
975
+ w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0
976
+ w2 = 1 - w1
977
+
978
+ rgb = color1.rgb.zip(color2.rgb).map {|v1, v2| v1*w1 + v2*w2}
979
+ alpha = color1.alpha*p + color2.alpha*(1-p)
980
+ Color.new(rgb + [alpha])
981
+ end
982
+ declare :mix, [:color_1, :color_2]
983
+ declare :mix, [:color_1, :color_2, :weight]
984
+
985
+ # Converts a color to grayscale.
986
+ # This is identical to `desaturate(color, 100%)`.
987
+ #
988
+ # @param color [Color]
989
+ # @return [Color]
990
+ # @raise [ArgumentError] if `color` isn't a color
991
+ # @see #desaturate
992
+ def grayscale(color)
993
+ desaturate color, Number.new(100)
994
+ end
995
+ declare :grayscale, [:color]
996
+
997
+ # Returns the complement of a color.
998
+ # This is identical to `adjust-hue(color, 180deg)`.
999
+ #
1000
+ # @param color [Color]
1001
+ # @return [Color]
1002
+ # @raise [ArgumentError] if `color` isn't a color
1003
+ # @see #adjust_hue #adjust-hue
1004
+ def complement(color)
1005
+ adjust_hue color, Number.new(180)
1006
+ end
1007
+ declare :complement, [:color]
1008
+
1009
+ # Returns the inverse (negative) of a color.
1010
+ # The red, green, and blue values are inverted, while the opacity is left alone.
1011
+ #
1012
+ # @param color [Color]
1013
+ # @return [Color]
1014
+ # @raise [ArgumentError] if `color` isn't a color
1015
+ def invert(color)
1016
+ assert_type color, :Color
1017
+ color.with(
1018
+ :red => (255 - color.red),
1019
+ :green => (255 - color.green),
1020
+ :blue => (255 - color.blue))
1021
+ end
1022
+
1023
+ # Removes quotes from a string if the string is quoted,
1024
+ # or returns the same string if it's not.
1025
+ #
1026
+ # @param string [String]
1027
+ # @return [String]
1028
+ # @raise [ArgumentError] if `string` isn't a string
1029
+ # @see #quote
1030
+ # @example
1031
+ # unquote("foo") => foo
1032
+ # unquote(foo) => foo
1033
+ def unquote(string)
1034
+ if string.is_a?(Sass::Script::String)
1035
+ Sass::Script::String.new(string.value, :identifier)
1036
+ else
1037
+ string
1038
+ end
1039
+ end
1040
+ declare :unquote, [:string]
1041
+
1042
+ # Add quotes to a string if the string isn't quoted,
1043
+ # or returns the same string if it is.
1044
+ #
1045
+ # @param string [String]
1046
+ # @return [String]
1047
+ # @raise [ArgumentError] if `string` isn't a string
1048
+ # @see #unquote
1049
+ # @example
1050
+ # quote("foo") => "foo"
1051
+ # quote(foo) => "foo"
1052
+ def quote(string)
1053
+ assert_type string, :String
1054
+ Sass::Script::String.new(string.value, :string)
1055
+ end
1056
+ declare :quote, [:string]
1057
+
1058
+ # Inspects the type of the argument, returning it as an unquoted string.
1059
+ #
1060
+ # @example
1061
+ # type-of(100px) => number
1062
+ # type-of(asdf) => string
1063
+ # type-of("asdf") => string
1064
+ # type-of(true) => bool
1065
+ # type-of(#fff) => color
1066
+ # type-of(blue) => color
1067
+ # @param value [Literal] The object to inspect
1068
+ # @return [String] The unquoted string name of the literal's type
1069
+ def type_of(value)
1070
+ Sass::Script::String.new(value.class.name.gsub(/Sass::Script::/,'').downcase)
1071
+ end
1072
+ declare :type_of, [:value]
1073
+
1074
+ # Inspects the unit of the number, returning it as a quoted string.
1075
+ # Complex units are sorted in alphabetical order by numerator and denominator.
1076
+ #
1077
+ # @example
1078
+ # unit(100) => ""
1079
+ # unit(100px) => "px"
1080
+ # unit(3em) => "em"
1081
+ # unit(10px * 5em) => "em*px"
1082
+ # unit(10px * 5em / 30cm / 1rem) => "em*px/cm*rem"
1083
+ # @param number [Literal] The number to inspect
1084
+ # @return [String] The unit(s) of the number
1085
+ # @raise [ArgumentError] if `number` isn't a number
1086
+ def unit(number)
1087
+ assert_type number, :Number
1088
+ Sass::Script::String.new(number.unit_str, :string)
1089
+ end
1090
+ declare :unit, [:number]
1091
+
1092
+ # Inspects the unit of the number, returning a boolean indicating if it is unitless.
1093
+ #
1094
+ # @example
1095
+ # unitless(100) => true
1096
+ # unitless(100px) => false
1097
+ # @param number [Literal] The number to inspect
1098
+ # @return [Bool] Whether or not the number is unitless
1099
+ # @raise [ArgumentError] if `number` isn't a number
1100
+ def unitless(number)
1101
+ assert_type number, :Number
1102
+ Sass::Script::Bool.new(number.unitless?)
1103
+ end
1104
+ declare :unitless, [:number]
1105
+
1106
+ # Returns true if two numbers are similar enough to be added, subtracted, or compared.
1107
+ #
1108
+ # @example
1109
+ # comparable(2px, 1px) => true
1110
+ # comparable(100px, 3em) => false
1111
+ # comparable(10cm, 3mm) => true
1112
+ # @param number_1 [Number]
1113
+ # @param number_2 [Number]
1114
+ # @return [Bool] indicating if the numbers can be compared.
1115
+ # @raise [ArgumentError] if `number_1` or `number_2` aren't numbers
1116
+ def comparable(number_1, number_2)
1117
+ assert_type number_1, :Number
1118
+ assert_type number_2, :Number
1119
+ Sass::Script::Bool.new(number_1.comparable_to?(number_2))
1120
+ end
1121
+ declare :comparable, [:number_1, :number_2]
1122
+
1123
+ # Converts a decimal number to a percentage.
1124
+ #
1125
+ # @example
1126
+ # percentage(100px / 50px) => 200%
1127
+ # @param value [Number] The decimal number to convert to a percentage
1128
+ # @return [Number] The percentage
1129
+ # @raise [ArgumentError] If `value` isn't a unitless number
1130
+ def percentage(value)
1131
+ unless value.is_a?(Sass::Script::Number) && value.unitless?
1132
+ raise ArgumentError.new("#{value.inspect} is not a unitless number")
1133
+ end
1134
+ Sass::Script::Number.new(value.value * 100, ['%'])
1135
+ end
1136
+ declare :percentage, [:value]
1137
+
1138
+ # Rounds a number to the nearest whole number.
1139
+ #
1140
+ # @example
1141
+ # round(10.4px) => 10px
1142
+ # round(10.6px) => 11px
1143
+ # @param value [Number] The number
1144
+ # @return [Number] The rounded number
1145
+ # @raise [ArgumentError] if `value` isn't a number
1146
+ def round(value)
1147
+ numeric_transformation(value) {|n| n.round}
1148
+ end
1149
+ declare :round, [:value]
1150
+
1151
+ # Rounds a number up to the nearest whole number.
1152
+ #
1153
+ # @example
1154
+ # ciel(10.4px) => 11px
1155
+ # ciel(10.6px) => 11px
1156
+ # @param value [Number] The number
1157
+ # @return [Number] The rounded number
1158
+ # @raise [ArgumentError] if `value` isn't a number
1159
+ def ceil(value)
1160
+ numeric_transformation(value) {|n| n.ceil}
1161
+ end
1162
+ declare :ceil, [:value]
1163
+
1164
+ # Rounds down to the nearest whole number.
1165
+ #
1166
+ # @example
1167
+ # floor(10.4px) => 10px
1168
+ # floor(10.6px) => 10px
1169
+ # @param value [Number] The number
1170
+ # @return [Number] The rounded number
1171
+ # @raise [ArgumentError] if `value` isn't a number
1172
+ def floor(value)
1173
+ numeric_transformation(value) {|n| n.floor}
1174
+ end
1175
+ declare :floor, [:value]
1176
+
1177
+ # Finds the absolute value of a number.
1178
+ #
1179
+ # @example
1180
+ # abs(10px) => 10px
1181
+ # abs(-10px) => 10px
1182
+ # @param value [Number] The number
1183
+ # @return [Number] The absolute value
1184
+ # @raise [ArgumentError] if `value` isn't a number
1185
+ def abs(value)
1186
+ numeric_transformation(value) {|n| n.abs}
1187
+ end
1188
+ declare :abs, [:value]
1189
+
1190
+ # Return the length of a list.
1191
+ #
1192
+ # @example
1193
+ # length(10px) => 1
1194
+ # length(10px 20px 30px) => 3
1195
+ # @param list [Literal] The list
1196
+ # @return [Number] The length
1197
+ def length(list)
1198
+ Sass::Script::Number.new(list.to_a.size)
1199
+ end
1200
+ declare :length, [:list]
1201
+
1202
+ # Gets the nth item in a list.
1203
+ #
1204
+ # Note that unlike some languages, the first item in a Sass list is number 1,
1205
+ # the second number 2, and so forth.
1206
+ #
1207
+ # @example
1208
+ # nth(10px 20px 30px, 1) => 10px
1209
+ # nth((Helvetica, Arial, sans-serif), 3) => sans-serif
1210
+ # @param list [Literal] The list
1211
+ # @param n [Number] The index into the list
1212
+ # @return [Literal] The nth item in the list
1213
+ # @raise [ArgumentError] If `n` isn't an integer between 1 and the list's length.
1214
+ def nth(list, n)
1215
+ assert_type n, :Number
1216
+ if !n.int?
1217
+ raise ArgumentError.new("List index #{n} must be an integer")
1218
+ elsif n.to_i < 1
1219
+ raise ArgumentError.new("List index #{n} must be greater than or equal to 1")
1220
+ elsif list.to_a.size == 0
1221
+ raise ArgumentError.new("List index is #{n} but list has no items")
1222
+ elsif n.to_i > (size = list.to_a.size)
1223
+ raise ArgumentError.new("List index is #{n} but list is only #{size} item#{'s' if size != 1} long")
1224
+ end
1225
+
1226
+ list.to_a[n.to_i - 1]
1227
+ end
1228
+ declare :nth, [:list, :n]
1229
+
1230
+ # Joins together two lists into a new list.
1231
+ #
1232
+ # Unless the `$separator` argument is passed,
1233
+ # if one list is comma-separated and one is space-separated,
1234
+ # the first parameter's separator is used for the resulting list.
1235
+ # If the lists have only one item each, spaces are used for the resulting list.
1236
+ #
1237
+ # @example
1238
+ # join(10px 20px, 30px 40px) => 10px 20px 30px 40px
1239
+ # join((blue, red), (#abc, #def)) => blue, red, #abc, #def
1240
+ # join(10px, 20px) => 10px 20px
1241
+ # join(10px, 20px, comma) => 10px, 20px
1242
+ # join((blue, red), (#abc, #def), space) => blue red #abc #def
1243
+ # @overload join(list1, list2, separator: auto)
1244
+ # @param list1 [Literal] The first list to join
1245
+ # @param list2 [Literal] The second list to join
1246
+ # @param separator [String] How the list separator (comma or space) should be determined.
1247
+ # If this is `comma` or `space`, that is always the separator;
1248
+ # if this is `auto` (the default), the separator is determined as explained above.
1249
+ def join(list1, list2, separator = Sass::Script::String.new("auto"))
1250
+ assert_type separator, :String
1251
+ unless %w[auto space comma].include?(separator.value)
1252
+ raise ArgumentError.new("Separator name must be space, comma, or auto")
1253
+ end
1254
+ sep1 = list1.separator if list1.is_a?(Sass::Script::List) && !list1.value.empty?
1255
+ sep2 = list2.separator if list2.is_a?(Sass::Script::List) && !list2.value.empty?
1256
+ Sass::Script::List.new(
1257
+ list1.to_a + list2.to_a,
1258
+ if separator.value == 'auto'
1259
+ sep1 || sep2 || :space
1260
+ else
1261
+ separator.value.to_sym
1262
+ end)
1263
+ end
1264
+ declare :join, [:list1, :list2]
1265
+ declare :join, [:list1, :list2, :separator]
1266
+
1267
+ # Appends a single value onto the end of a list.
1268
+ #
1269
+ # Unless the `$separator` argument is passed,
1270
+ # if the list has only one item,
1271
+ # the resulting list will be space-separated.
1272
+ #
1273
+ # @example
1274
+ # append(10px 20px, 30px) => 10px 20px 30px
1275
+ # append((blue, red), green) => blue, red, green
1276
+ # append(10px 20px, 30px 40px) => 10px 20px (30px 40px)
1277
+ # join(10px, 20px, comma) => 10px, 20px
1278
+ # join((blue, red), green, space) => blue red green
1279
+ # @overload join(list, val, separator: auto)
1280
+ # @param list1 [Literal] The first list to join
1281
+ # @param list2 [Literal] The second list to join
1282
+ # @param separator [String] How the list separator (comma or space) should be determined.
1283
+ # If this is `comma` or `space`, that is always the separator;
1284
+ # if this is `auto` (the default), the separator is determined as explained above.
1285
+ def append(list, val, separator = Sass::Script::String.new("auto"))
1286
+ assert_type separator, :String
1287
+ unless %w[auto space comma].include?(separator.value)
1288
+ raise ArgumentError.new("Separator name must be space, comma, or auto")
1289
+ end
1290
+ sep = list.separator if list.is_a?(Sass::Script::List)
1291
+ Sass::Script::List.new(
1292
+ list.to_a + [val],
1293
+ if separator.value == 'auto'
1294
+ sep || :space
1295
+ else
1296
+ separator.value.to_sym
1297
+ end)
1298
+ end
1299
+ declare :append, [:list, :val]
1300
+ declare :append, [:list, :val, :separator]
1301
+
1302
+ # Returns one of two values based on the truth value of the first argument.
1303
+ #
1304
+ # @example
1305
+ # if(true, 1px, 2px) => 1px
1306
+ # if(false, 1px, 2px) => 2px
1307
+ # @param condition [Bool] Whether the first or second value will be returned.
1308
+ # @param if_true [Literal] The value that will be returned if `$condition` is true.
1309
+ # @param if_false [Literal] The value that will be returned if `$condition` is false.
1310
+ def if(condition, if_true, if_false)
1311
+ if condition.to_bool
1312
+ if_true
1313
+ else
1314
+ if_false
1315
+ end
1316
+ end
1317
+ declare :if, [:condition, :if_true, :if_false]
1318
+
1319
+ private
1320
+
1321
+ # This method implements the pattern of transforming a numeric value into
1322
+ # another numeric value with the same units.
1323
+ # It yields a number to a block to perform the operation and return a number
1324
+ def numeric_transformation(value)
1325
+ assert_type value, :Number
1326
+ Sass::Script::Number.new(yield(value.value), value.numerator_units, value.denominator_units)
1327
+ end
1328
+
1329
+ def _adjust(color, amount, attr, range, op, units = "")
1330
+ assert_type color, :Color
1331
+ assert_type amount, :Number
1332
+ unless range.include?(amount.value)
1333
+ raise ArgumentError.new("Amount #{amount} must be between #{range.first}#{units} and #{range.last}#{units}")
1334
+ end
1335
+
1336
+ # TODO: is it worth restricting here,
1337
+ # or should we do so in the Color constructor itself,
1338
+ # and allow clipping in rgb() et al?
1339
+ color.with(attr => Sass::Util.restrict(
1340
+ color.send(attr).send(op, amount.value), range))
1341
+ end
1342
+ end
1343
+ end