aliddle-sass 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (238) hide show
  1. data/.yardopts +11 -0
  2. data/CONTRIBUTING +3 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +201 -0
  5. data/Rakefile +347 -0
  6. data/VERSION +1 -0
  7. data/VERSION_NAME +1 -0
  8. data/bin/sass +9 -0
  9. data/bin/sass-convert +8 -0
  10. data/bin/scss +9 -0
  11. data/extra/update_watch.rb +13 -0
  12. data/init.rb +18 -0
  13. data/lib/sass.rb +95 -0
  14. data/lib/sass/cache_stores.rb +15 -0
  15. data/lib/sass/cache_stores/base.rb +88 -0
  16. data/lib/sass/cache_stores/chain.rb +33 -0
  17. data/lib/sass/cache_stores/filesystem.rb +60 -0
  18. data/lib/sass/cache_stores/memory.rb +47 -0
  19. data/lib/sass/cache_stores/null.rb +25 -0
  20. data/lib/sass/callbacks.rb +66 -0
  21. data/lib/sass/css.rb +409 -0
  22. data/lib/sass/engine.rb +928 -0
  23. data/lib/sass/environment.rb +101 -0
  24. data/lib/sass/error.rb +201 -0
  25. data/lib/sass/exec.rb +707 -0
  26. data/lib/sass/importers.rb +22 -0
  27. data/lib/sass/importers/base.rb +139 -0
  28. data/lib/sass/importers/filesystem.rb +190 -0
  29. data/lib/sass/logger.rb +15 -0
  30. data/lib/sass/logger/base.rb +32 -0
  31. data/lib/sass/logger/log_level.rb +49 -0
  32. data/lib/sass/media.rb +213 -0
  33. data/lib/sass/plugin.rb +132 -0
  34. data/lib/sass/plugin/compiler.rb +406 -0
  35. data/lib/sass/plugin/configuration.rb +123 -0
  36. data/lib/sass/plugin/generic.rb +15 -0
  37. data/lib/sass/plugin/merb.rb +48 -0
  38. data/lib/sass/plugin/rack.rb +60 -0
  39. data/lib/sass/plugin/rails.rb +47 -0
  40. data/lib/sass/plugin/staleness_checker.rb +183 -0
  41. data/lib/sass/railtie.rb +9 -0
  42. data/lib/sass/repl.rb +57 -0
  43. data/lib/sass/root.rb +7 -0
  44. data/lib/sass/script.rb +39 -0
  45. data/lib/sass/script/arg_list.rb +52 -0
  46. data/lib/sass/script/bool.rb +18 -0
  47. data/lib/sass/script/color.rb +606 -0
  48. data/lib/sass/script/css_lexer.rb +29 -0
  49. data/lib/sass/script/css_parser.rb +31 -0
  50. data/lib/sass/script/funcall.rb +237 -0
  51. data/lib/sass/script/functions.rb +1543 -0
  52. data/lib/sass/script/interpolation.rb +79 -0
  53. data/lib/sass/script/lexer.rb +348 -0
  54. data/lib/sass/script/list.rb +85 -0
  55. data/lib/sass/script/literal.rb +221 -0
  56. data/lib/sass/script/node.rb +99 -0
  57. data/lib/sass/script/null.rb +37 -0
  58. data/lib/sass/script/number.rb +453 -0
  59. data/lib/sass/script/operation.rb +110 -0
  60. data/lib/sass/script/parser.rb +495 -0
  61. data/lib/sass/script/string.rb +51 -0
  62. data/lib/sass/script/string_interpolation.rb +103 -0
  63. data/lib/sass/script/unary_operation.rb +69 -0
  64. data/lib/sass/script/variable.rb +58 -0
  65. data/lib/sass/scss.rb +16 -0
  66. data/lib/sass/scss/css_parser.rb +36 -0
  67. data/lib/sass/scss/parser.rb +1179 -0
  68. data/lib/sass/scss/rx.rb +133 -0
  69. data/lib/sass/scss/script_lexer.rb +15 -0
  70. data/lib/sass/scss/script_parser.rb +25 -0
  71. data/lib/sass/scss/static_parser.rb +54 -0
  72. data/lib/sass/selector.rb +452 -0
  73. data/lib/sass/selector/abstract_sequence.rb +94 -0
  74. data/lib/sass/selector/comma_sequence.rb +92 -0
  75. data/lib/sass/selector/sequence.rb +507 -0
  76. data/lib/sass/selector/simple.rb +119 -0
  77. data/lib/sass/selector/simple_sequence.rb +212 -0
  78. data/lib/sass/shared.rb +76 -0
  79. data/lib/sass/supports.rb +229 -0
  80. data/lib/sass/tree/charset_node.rb +22 -0
  81. data/lib/sass/tree/comment_node.rb +82 -0
  82. data/lib/sass/tree/content_node.rb +9 -0
  83. data/lib/sass/tree/css_import_node.rb +60 -0
  84. data/lib/sass/tree/debug_node.rb +18 -0
  85. data/lib/sass/tree/directive_node.rb +42 -0
  86. data/lib/sass/tree/each_node.rb +24 -0
  87. data/lib/sass/tree/extend_node.rb +36 -0
  88. data/lib/sass/tree/for_node.rb +36 -0
  89. data/lib/sass/tree/function_node.rb +34 -0
  90. data/lib/sass/tree/if_node.rb +52 -0
  91. data/lib/sass/tree/import_node.rb +75 -0
  92. data/lib/sass/tree/media_node.rb +58 -0
  93. data/lib/sass/tree/mixin_def_node.rb +38 -0
  94. data/lib/sass/tree/mixin_node.rb +39 -0
  95. data/lib/sass/tree/node.rb +196 -0
  96. data/lib/sass/tree/prop_node.rb +152 -0
  97. data/lib/sass/tree/return_node.rb +18 -0
  98. data/lib/sass/tree/root_node.rb +28 -0
  99. data/lib/sass/tree/rule_node.rb +132 -0
  100. data/lib/sass/tree/supports_node.rb +51 -0
  101. data/lib/sass/tree/trace_node.rb +32 -0
  102. data/lib/sass/tree/variable_node.rb +30 -0
  103. data/lib/sass/tree/visitors/base.rb +75 -0
  104. data/lib/sass/tree/visitors/check_nesting.rb +147 -0
  105. data/lib/sass/tree/visitors/convert.rb +316 -0
  106. data/lib/sass/tree/visitors/cssize.rb +229 -0
  107. data/lib/sass/tree/visitors/deep_copy.rb +102 -0
  108. data/lib/sass/tree/visitors/extend.rb +68 -0
  109. data/lib/sass/tree/visitors/perform.rb +446 -0
  110. data/lib/sass/tree/visitors/set_options.rb +125 -0
  111. data/lib/sass/tree/visitors/to_css.rb +230 -0
  112. data/lib/sass/tree/warn_node.rb +18 -0
  113. data/lib/sass/tree/while_node.rb +18 -0
  114. data/lib/sass/util.rb +906 -0
  115. data/lib/sass/util/multibyte_string_scanner.rb +155 -0
  116. data/lib/sass/util/subset_map.rb +109 -0
  117. data/lib/sass/util/test.rb +10 -0
  118. data/lib/sass/version.rb +126 -0
  119. data/rails/init.rb +1 -0
  120. data/test/Gemfile +3 -0
  121. data/test/Gemfile.lock +10 -0
  122. data/test/sass/cache_test.rb +89 -0
  123. data/test/sass/callbacks_test.rb +61 -0
  124. data/test/sass/conversion_test.rb +1760 -0
  125. data/test/sass/css2sass_test.rb +439 -0
  126. data/test/sass/data/hsl-rgb.txt +319 -0
  127. data/test/sass/engine_test.rb +3243 -0
  128. data/test/sass/exec_test.rb +86 -0
  129. data/test/sass/extend_test.rb +1461 -0
  130. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  131. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  132. data/test/sass/functions_test.rb +1139 -0
  133. data/test/sass/importer_test.rb +192 -0
  134. data/test/sass/logger_test.rb +58 -0
  135. data/test/sass/mock_importer.rb +49 -0
  136. data/test/sass/more_results/more1.css +9 -0
  137. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  138. data/test/sass/more_results/more_import.css +29 -0
  139. data/test/sass/more_templates/_more_partial.sass +2 -0
  140. data/test/sass/more_templates/more1.sass +23 -0
  141. data/test/sass/more_templates/more_import.sass +11 -0
  142. data/test/sass/plugin_test.rb +550 -0
  143. data/test/sass/results/alt.css +4 -0
  144. data/test/sass/results/basic.css +9 -0
  145. data/test/sass/results/cached_import_option.css +3 -0
  146. data/test/sass/results/compact.css +5 -0
  147. data/test/sass/results/complex.css +86 -0
  148. data/test/sass/results/compressed.css +1 -0
  149. data/test/sass/results/expanded.css +19 -0
  150. data/test/sass/results/filename_fn.css +3 -0
  151. data/test/sass/results/if.css +3 -0
  152. data/test/sass/results/import.css +31 -0
  153. data/test/sass/results/import_charset.css +5 -0
  154. data/test/sass/results/import_charset_1_8.css +5 -0
  155. data/test/sass/results/import_charset_ibm866.css +5 -0
  156. data/test/sass/results/import_content.css +1 -0
  157. data/test/sass/results/line_numbers.css +49 -0
  158. data/test/sass/results/mixins.css +95 -0
  159. data/test/sass/results/multiline.css +24 -0
  160. data/test/sass/results/nested.css +22 -0
  161. data/test/sass/results/options.css +1 -0
  162. data/test/sass/results/parent_ref.css +13 -0
  163. data/test/sass/results/script.css +16 -0
  164. data/test/sass/results/scss_import.css +31 -0
  165. data/test/sass/results/scss_importee.css +2 -0
  166. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  167. data/test/sass/results/subdir/subdir.css +3 -0
  168. data/test/sass/results/units.css +11 -0
  169. data/test/sass/results/warn.css +0 -0
  170. data/test/sass/results/warn_imported.css +0 -0
  171. data/test/sass/script_conversion_test.rb +299 -0
  172. data/test/sass/script_test.rb +591 -0
  173. data/test/sass/scss/css_test.rb +1093 -0
  174. data/test/sass/scss/rx_test.rb +156 -0
  175. data/test/sass/scss/scss_test.rb +2043 -0
  176. data/test/sass/scss/test_helper.rb +37 -0
  177. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  178. data/test/sass/templates/_double_import_loop2.sass +1 -0
  179. data/test/sass/templates/_filename_fn_import.scss +11 -0
  180. data/test/sass/templates/_imported_charset_ibm866.sass +4 -0
  181. data/test/sass/templates/_imported_charset_utf8.sass +4 -0
  182. data/test/sass/templates/_imported_content.sass +3 -0
  183. data/test/sass/templates/_partial.sass +2 -0
  184. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  185. data/test/sass/templates/alt.sass +16 -0
  186. data/test/sass/templates/basic.sass +23 -0
  187. data/test/sass/templates/bork1.sass +2 -0
  188. data/test/sass/templates/bork2.sass +2 -0
  189. data/test/sass/templates/bork3.sass +2 -0
  190. data/test/sass/templates/bork4.sass +2 -0
  191. data/test/sass/templates/bork5.sass +3 -0
  192. data/test/sass/templates/cached_import_option.scss +3 -0
  193. data/test/sass/templates/compact.sass +17 -0
  194. data/test/sass/templates/complex.sass +305 -0
  195. data/test/sass/templates/compressed.sass +15 -0
  196. data/test/sass/templates/double_import_loop1.sass +1 -0
  197. data/test/sass/templates/expanded.sass +17 -0
  198. data/test/sass/templates/filename_fn.scss +18 -0
  199. data/test/sass/templates/if.sass +11 -0
  200. data/test/sass/templates/import.sass +12 -0
  201. data/test/sass/templates/import_charset.sass +9 -0
  202. data/test/sass/templates/import_charset_1_8.sass +6 -0
  203. data/test/sass/templates/import_charset_ibm866.sass +11 -0
  204. data/test/sass/templates/import_content.sass +4 -0
  205. data/test/sass/templates/importee.less +2 -0
  206. data/test/sass/templates/importee.sass +19 -0
  207. data/test/sass/templates/line_numbers.sass +13 -0
  208. data/test/sass/templates/mixin_bork.sass +5 -0
  209. data/test/sass/templates/mixins.sass +76 -0
  210. data/test/sass/templates/multiline.sass +20 -0
  211. data/test/sass/templates/nested.sass +25 -0
  212. data/test/sass/templates/nested_bork1.sass +2 -0
  213. data/test/sass/templates/nested_bork2.sass +2 -0
  214. data/test/sass/templates/nested_bork3.sass +2 -0
  215. data/test/sass/templates/nested_bork4.sass +2 -0
  216. data/test/sass/templates/nested_import.sass +2 -0
  217. data/test/sass/templates/nested_mixin_bork.sass +6 -0
  218. data/test/sass/templates/options.sass +2 -0
  219. data/test/sass/templates/parent_ref.sass +25 -0
  220. data/test/sass/templates/same_name_different_ext.sass +2 -0
  221. data/test/sass/templates/same_name_different_ext.scss +1 -0
  222. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  223. data/test/sass/templates/script.sass +101 -0
  224. data/test/sass/templates/scss_import.scss +11 -0
  225. data/test/sass/templates/scss_importee.scss +1 -0
  226. data/test/sass/templates/single_import_loop.sass +1 -0
  227. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  228. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  229. data/test/sass/templates/subdir/subdir.sass +6 -0
  230. data/test/sass/templates/units.sass +11 -0
  231. data/test/sass/templates/warn.sass +3 -0
  232. data/test/sass/templates/warn_imported.sass +4 -0
  233. data/test/sass/test_helper.rb +8 -0
  234. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  235. data/test/sass/util/subset_map_test.rb +91 -0
  236. data/test/sass/util_test.rb +313 -0
  237. data/test/test_helper.rb +80 -0
  238. metadata +348 -0
@@ -0,0 +1,9 @@
1
+ # Rails 3.0.0.beta.2+, < 3.1
2
+ if defined?(ActiveSupport) && Sass::Util.has?(:public_method, ActiveSupport, :on_load) &&
3
+ !Sass::Util.ap_geq?('3.1.0.beta')
4
+ require 'sass/plugin/configuration'
5
+ ActiveSupport.on_load(:before_configuration) do
6
+ require 'sass'
7
+ require 'sass/plugin'
8
+ end
9
+ end
data/lib/sass/repl.rb ADDED
@@ -0,0 +1,57 @@
1
+ require 'readline'
2
+
3
+ module Sass
4
+ # Runs a SassScript read-eval-print loop.
5
+ # It presents a prompt on the terminal,
6
+ # reads in SassScript expressions,
7
+ # evaluates them,
8
+ # and prints the result.
9
+ class Repl
10
+ # @param options [{Symbol => Object}] An options hash.
11
+ def initialize(options = {})
12
+ @options = options
13
+ end
14
+
15
+ # Starts the read-eval-print loop.
16
+ def run
17
+ environment = Environment.new
18
+ @line = 0
19
+ loop do
20
+ @line += 1
21
+ unless text = Readline.readline('>> ')
22
+ puts
23
+ return
24
+ end
25
+
26
+ Readline::HISTORY << text
27
+ parse_input(environment, text)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def parse_input(environment, text)
34
+ case text
35
+ when Script::MATCH
36
+ name = $1
37
+ guarded = !!$3
38
+ val = Script::Parser.parse($2, @line, text.size - ($3 || '').size - $2.size)
39
+
40
+ unless guarded && environment.var(name)
41
+ environment.set_var(name, val.perform(environment))
42
+ end
43
+
44
+ p environment.var(name)
45
+ else
46
+ p Script::Parser.parse(text, @line, 0).perform(environment)
47
+ end
48
+ rescue Sass::SyntaxError => e
49
+ puts "SyntaxError: #{e.message}"
50
+ if @options[:trace]
51
+ e.backtrace.each do |e|
52
+ puts "\tfrom #{e}"
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
data/lib/sass/root.rb ADDED
@@ -0,0 +1,7 @@
1
+ module Sass
2
+ # The root directory of the Sass source tree.
3
+ # This may be overridden by the package manager
4
+ # if the lib directory is separated from the main source tree.
5
+ # @api public
6
+ ROOT_DIR = File.expand_path(File.join(__FILE__, "../../.."))
7
+ end
@@ -0,0 +1,39 @@
1
+ require 'sass/script/node'
2
+ require 'sass/script/variable'
3
+ require 'sass/script/funcall'
4
+ require 'sass/script/operation'
5
+ require 'sass/script/literal'
6
+ require 'sass/script/parser'
7
+
8
+ module Sass
9
+ # SassScript is code that's embedded in Sass documents
10
+ # to allow for property values to be computed from variables.
11
+ #
12
+ # This module contains code that handles the parsing and evaluation of SassScript.
13
+ module Script
14
+ # The regular expression used to parse variables.
15
+ MATCH = /^\$(#{Sass::SCSS::RX::IDENT})\s*:\s*(.+?)(!(?i:default))?$/
16
+
17
+ # The regular expression used to validate variables without matching.
18
+ VALIDATE = /^\$#{Sass::SCSS::RX::IDENT}$/
19
+
20
+ # Parses a string of SassScript
21
+ #
22
+ # @param value [String] The SassScript
23
+ # @param line [Fixnum] The number of the line on which the SassScript appeared.
24
+ # Used for error reporting
25
+ # @param offset [Fixnum] The number of characters in on `line` that the SassScript started.
26
+ # Used for error reporting
27
+ # @param options [{Symbol => Object}] An options hash;
28
+ # see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
29
+ # @return [Script::Node] The root node of the parse tree
30
+ def self.parse(value, line, offset, options = {})
31
+ Parser.parse(value, line, offset, options)
32
+ rescue Sass::SyntaxError => e
33
+ e.message << ": #{value.inspect}." if e.message == "SassScript error"
34
+ e.modify_backtrace(:line => line, :filename => options[:filename])
35
+ raise e
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,52 @@
1
+ module Sass::Script
2
+ # A SassScript object representing a variable argument list. This works just
3
+ # like a normal list, but can also contain keyword arguments.
4
+ #
5
+ # The keyword arguments attached to this list are unused except when this is
6
+ # passed as a glob argument to a function or mixin.
7
+ class ArgList < List
8
+ # Whether \{#keywords} has been accessed. If so, we assume that all keywords
9
+ # were valid for the function that created this ArgList.
10
+ #
11
+ # @return [Boolean]
12
+ attr_accessor :keywords_accessed
13
+
14
+ # Creates a new argument list.
15
+ #
16
+ # @param value [Array<Literal>] See \{List#value}.
17
+ # @param keywords [Hash<String, Literal>] See \{#keywords}
18
+ # @param separator [String] See \{List#separator}.
19
+ def initialize(value, keywords, separator)
20
+ super(value, separator)
21
+ @keywords = keywords
22
+ end
23
+
24
+ # The keyword arguments attached to this list.
25
+ #
26
+ # @return [Hash<String, Literal>]
27
+ def keywords
28
+ @keywords_accessed = true
29
+ @keywords
30
+ end
31
+
32
+ # @see Node#children
33
+ def children
34
+ super + @keywords.values
35
+ end
36
+
37
+ # @see Node#deep_copy
38
+ def deep_copy
39
+ node = super
40
+ node.instance_variable_set('@keywords',
41
+ Sass::Util.map_hash(@keywords) {|k, v| [k, v.deep_copy]})
42
+ node
43
+ end
44
+
45
+ protected
46
+
47
+ # @see Node#_perform
48
+ def _perform(environment)
49
+ self
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,18 @@
1
+ require 'sass/script/literal'
2
+
3
+ module Sass::Script
4
+ # A SassScript object representing a boolean (true or false) value.
5
+ class Bool < Literal
6
+ # The Ruby value of the boolean.
7
+ #
8
+ # @return [Boolean]
9
+ attr_reader :value
10
+ alias_method :to_bool, :value
11
+
12
+ # @return [String] "true" or "false"
13
+ def to_s(opts = {})
14
+ @value.to_s
15
+ end
16
+ alias_method :to_sass, :to_s
17
+ end
18
+ end
@@ -0,0 +1,606 @@
1
+ require 'sass/script/literal'
2
+
3
+ module Sass::Script
4
+ # A SassScript object representing a CSS color.
5
+ #
6
+ # A color may be represented internally as RGBA, HSLA, or both.
7
+ # It's originally represented as whatever its input is;
8
+ # if it's created with RGB values, it's represented as RGBA,
9
+ # and if it's created with HSL values, it's represented as HSLA.
10
+ # Once a property is accessed that requires the other representation --
11
+ # for example, \{#red} for an HSL color --
12
+ # that component is calculated and cached.
13
+ #
14
+ # The alpha channel of a color is independent of its RGB or HSL representation.
15
+ # It's always stored, as 1 if nothing else is specified.
16
+ # If only the alpha channel is modified using \{#with},
17
+ # the cached RGB and HSL values are retained.
18
+ class Color < Literal
19
+ class << self; include Sass::Util; end
20
+
21
+ # A hash from color names to `[red, green, blue]` value arrays.
22
+ COLOR_NAMES = map_vals({
23
+ 'aliceblue' => 0xf0f8ff,
24
+ 'antiquewhite' => 0xfaebd7,
25
+ 'aqua' => 0x00ffff,
26
+ 'aquamarine' => 0x7fffd4,
27
+ 'azure' => 0xf0ffff,
28
+ 'beige' => 0xf5f5dc,
29
+ 'bisque' => 0xffe4c4,
30
+ 'black' => 0x000000,
31
+ 'blanchedalmond' => 0xffebcd,
32
+ 'blue' => 0x0000ff,
33
+ 'blueviolet' => 0x8a2be2,
34
+ 'brown' => 0xa52a2a,
35
+ 'burlywood' => 0xdeb887,
36
+ 'cadetblue' => 0x5f9ea0,
37
+ 'chartreuse' => 0x7fff00,
38
+ 'chocolate' => 0xd2691e,
39
+ 'coral' => 0xff7f50,
40
+ 'cornflowerblue' => 0x6495ed,
41
+ 'cornsilk' => 0xfff8dc,
42
+ 'crimson' => 0xdc143c,
43
+ 'cyan' => 0x00ffff,
44
+ 'darkblue' => 0x00008b,
45
+ 'darkcyan' => 0x008b8b,
46
+ 'darkgoldenrod' => 0xb8860b,
47
+ 'darkgray' => 0xa9a9a9,
48
+ 'darkgrey' => 0xa9a9a9,
49
+ 'darkgreen' => 0x006400,
50
+ 'darkkhaki' => 0xbdb76b,
51
+ 'darkmagenta' => 0x8b008b,
52
+ 'darkolivegreen' => 0x556b2f,
53
+ 'darkorange' => 0xff8c00,
54
+ 'darkorchid' => 0x9932cc,
55
+ 'darkred' => 0x8b0000,
56
+ 'darksalmon' => 0xe9967a,
57
+ 'darkseagreen' => 0x8fbc8f,
58
+ 'darkslateblue' => 0x483d8b,
59
+ 'darkslategray' => 0x2f4f4f,
60
+ 'darkslategrey' => 0x2f4f4f,
61
+ 'darkturquoise' => 0x00ced1,
62
+ 'darkviolet' => 0x9400d3,
63
+ 'deeppink' => 0xff1493,
64
+ 'deepskyblue' => 0x00bfff,
65
+ 'dimgray' => 0x696969,
66
+ 'dimgrey' => 0x696969,
67
+ 'dodgerblue' => 0x1e90ff,
68
+ 'firebrick' => 0xb22222,
69
+ 'floralwhite' => 0xfffaf0,
70
+ 'forestgreen' => 0x228b22,
71
+ 'fuchsia' => 0xff00ff,
72
+ 'gainsboro' => 0xdcdcdc,
73
+ 'ghostwhite' => 0xf8f8ff,
74
+ 'gold' => 0xffd700,
75
+ 'goldenrod' => 0xdaa520,
76
+ 'gray' => 0x808080,
77
+ 'green' => 0x008000,
78
+ 'greenyellow' => 0xadff2f,
79
+ 'honeydew' => 0xf0fff0,
80
+ 'hotpink' => 0xff69b4,
81
+ 'indianred' => 0xcd5c5c,
82
+ 'indigo' => 0x4b0082,
83
+ 'ivory' => 0xfffff0,
84
+ 'khaki' => 0xf0e68c,
85
+ 'lavender' => 0xe6e6fa,
86
+ 'lavenderblush' => 0xfff0f5,
87
+ 'lawngreen' => 0x7cfc00,
88
+ 'lemonchiffon' => 0xfffacd,
89
+ 'lightblue' => 0xadd8e6,
90
+ 'lightcoral' => 0xf08080,
91
+ 'lightcyan' => 0xe0ffff,
92
+ 'lightgoldenrodyellow' => 0xfafad2,
93
+ 'lightgreen' => 0x90ee90,
94
+ 'lightgray' => 0xd3d3d3,
95
+ 'lightgrey' => 0xd3d3d3,
96
+ 'lightpink' => 0xffb6c1,
97
+ 'lightsalmon' => 0xffa07a,
98
+ 'lightseagreen' => 0x20b2aa,
99
+ 'lightskyblue' => 0x87cefa,
100
+ 'lightslategray' => 0x778899,
101
+ 'lightslategrey' => 0x778899,
102
+ 'lightsteelblue' => 0xb0c4de,
103
+ 'lightyellow' => 0xffffe0,
104
+ 'lime' => 0x00ff00,
105
+ 'limegreen' => 0x32cd32,
106
+ 'linen' => 0xfaf0e6,
107
+ 'magenta' => 0xff00ff,
108
+ 'maroon' => 0x800000,
109
+ 'mediumaquamarine' => 0x66cdaa,
110
+ 'mediumblue' => 0x0000cd,
111
+ 'mediumorchid' => 0xba55d3,
112
+ 'mediumpurple' => 0x9370db,
113
+ 'mediumseagreen' => 0x3cb371,
114
+ 'mediumslateblue' => 0x7b68ee,
115
+ 'mediumspringgreen' => 0x00fa9a,
116
+ 'mediumturquoise' => 0x48d1cc,
117
+ 'mediumvioletred' => 0xc71585,
118
+ 'midnightblue' => 0x191970,
119
+ 'mintcream' => 0xf5fffa,
120
+ 'mistyrose' => 0xffe4e1,
121
+ 'moccasin' => 0xffe4b5,
122
+ 'navajowhite' => 0xffdead,
123
+ 'navy' => 0x000080,
124
+ 'oldlace' => 0xfdf5e6,
125
+ 'olive' => 0x808000,
126
+ 'olivedrab' => 0x6b8e23,
127
+ 'orange' => 0xffa500,
128
+ 'orangered' => 0xff4500,
129
+ 'orchid' => 0xda70d6,
130
+ 'palegoldenrod' => 0xeee8aa,
131
+ 'palegreen' => 0x98fb98,
132
+ 'paleturquoise' => 0xafeeee,
133
+ 'palevioletred' => 0xdb7093,
134
+ 'papayawhip' => 0xffefd5,
135
+ 'peachpuff' => 0xffdab9,
136
+ 'peru' => 0xcd853f,
137
+ 'pink' => 0xffc0cb,
138
+ 'plum' => 0xdda0dd,
139
+ 'powderblue' => 0xb0e0e6,
140
+ 'purple' => 0x800080,
141
+ 'red' => 0xff0000,
142
+ 'rosybrown' => 0xbc8f8f,
143
+ 'royalblue' => 0x4169e1,
144
+ 'saddlebrown' => 0x8b4513,
145
+ 'salmon' => 0xfa8072,
146
+ 'sandybrown' => 0xf4a460,
147
+ 'seagreen' => 0x2e8b57,
148
+ 'seashell' => 0xfff5ee,
149
+ 'sienna' => 0xa0522d,
150
+ 'silver' => 0xc0c0c0,
151
+ 'skyblue' => 0x87ceeb,
152
+ 'slateblue' => 0x6a5acd,
153
+ 'slategray' => 0x708090,
154
+ 'slategrey' => 0x708090,
155
+ 'snow' => 0xfffafa,
156
+ 'springgreen' => 0x00ff7f,
157
+ 'steelblue' => 0x4682b4,
158
+ 'tan' => 0xd2b48c,
159
+ 'teal' => 0x008080,
160
+ 'thistle' => 0xd8bfd8,
161
+ 'tomato' => 0xff6347,
162
+ 'turquoise' => 0x40e0d0,
163
+ 'violet' => 0xee82ee,
164
+ 'wheat' => 0xf5deb3,
165
+ 'white' => 0xffffff,
166
+ 'whitesmoke' => 0xf5f5f5,
167
+ 'yellow' => 0xffff00,
168
+ 'yellowgreen' => 0x9acd32
169
+ }) {|color| (0..2).map {|n| color >> (n << 3) & 0xff}.reverse}
170
+
171
+ # A hash from `[red, green, blue]` value arrays to color names.
172
+ COLOR_NAMES_REVERSE = map_hash(hash_to_a(COLOR_NAMES)) {|k, v| [v, k]}
173
+
174
+ # Constructs an RGB or HSL color object,
175
+ # optionally with an alpha channel.
176
+ #
177
+ # The RGB values must be between 0 and 255.
178
+ # The saturation and lightness values must be between 0 and 100.
179
+ # The alpha value must be between 0 and 1.
180
+ #
181
+ # @raise [Sass::SyntaxError] if any color value isn't in the specified range
182
+ #
183
+ # @overload initialize(attrs)
184
+ # The attributes are specified as a hash.
185
+ # This hash must contain either `:hue`, `:saturation`, and `:value` keys,
186
+ # or `:red`, `:green`, and `:blue` keys.
187
+ # It cannot contain both HSL and RGB keys.
188
+ # It may also optionally contain an `:alpha` key.
189
+ #
190
+ # @param attrs [{Symbol => Numeric}] A hash of color attributes to values
191
+ # @raise [ArgumentError] if not enough attributes are specified,
192
+ # or both RGB and HSL attributes are specified
193
+ #
194
+ # @overload initialize(rgba)
195
+ # The attributes are specified as an array.
196
+ # This overload only supports RGB or RGBA colors.
197
+ #
198
+ # @param rgba [Array<Numeric>] A three- or four-element array
199
+ # of the red, green, blue, and optionally alpha values (respectively)
200
+ # of the color
201
+ # @raise [ArgumentError] if not enough attributes are specified
202
+ def initialize(attrs, allow_both_rgb_and_hsl = false)
203
+ super(nil)
204
+
205
+ if attrs.is_a?(Array)
206
+ unless (3..4).include?(attrs.size)
207
+ raise ArgumentError.new("Color.new(array) expects a three- or four-element array")
208
+ end
209
+
210
+ red, green, blue = attrs[0...3].map {|c| c.to_i}
211
+ @attrs = {:red => red, :green => green, :blue => blue}
212
+ @attrs[:alpha] = attrs[3] ? attrs[3].to_f : 1
213
+ else
214
+ attrs = attrs.reject {|k, v| v.nil?}
215
+ hsl = [:hue, :saturation, :lightness] & attrs.keys
216
+ rgb = [:red, :green, :blue] & attrs.keys
217
+ if !allow_both_rgb_and_hsl && !hsl.empty? && !rgb.empty?
218
+ raise ArgumentError.new("Color.new(hash) may not have both HSL and RGB keys specified")
219
+ elsif hsl.empty? && rgb.empty?
220
+ raise ArgumentError.new("Color.new(hash) must have either HSL or RGB keys specified")
221
+ elsif !hsl.empty? && hsl.size != 3
222
+ raise ArgumentError.new("Color.new(hash) must have all three HSL values specified")
223
+ elsif !rgb.empty? && rgb.size != 3
224
+ raise ArgumentError.new("Color.new(hash) must have all three RGB values specified")
225
+ end
226
+
227
+ @attrs = attrs
228
+ @attrs[:hue] %= 360 if @attrs[:hue]
229
+ @attrs[:alpha] ||= 1
230
+ end
231
+
232
+ [:red, :green, :blue].each do |k|
233
+ next if @attrs[k].nil?
234
+ @attrs[k] = @attrs[k].to_i
235
+ Sass::Util.check_range("#{k.to_s.capitalize} value", 0..255, @attrs[k])
236
+ end
237
+
238
+ [:saturation, :lightness].each do |k|
239
+ next if @attrs[k].nil?
240
+ value = Number.new(@attrs[k], ['%']) # Get correct unit for error messages
241
+ @attrs[k] = Sass::Util.check_range("#{k.to_s.capitalize}", 0..100, value, '%')
242
+ end
243
+
244
+ @attrs[:alpha] = Sass::Util.check_range("Alpha channel", 0..1, @attrs[:alpha])
245
+ end
246
+
247
+ # The red component of the color.
248
+ #
249
+ # @return [Fixnum]
250
+ def red
251
+ hsl_to_rgb!
252
+ @attrs[:red]
253
+ end
254
+
255
+ # The green component of the color.
256
+ #
257
+ # @return [Fixnum]
258
+ def green
259
+ hsl_to_rgb!
260
+ @attrs[:green]
261
+ end
262
+
263
+ # The blue component of the color.
264
+ #
265
+ # @return [Fixnum]
266
+ def blue
267
+ hsl_to_rgb!
268
+ @attrs[:blue]
269
+ end
270
+
271
+ # The hue component of the color.
272
+ #
273
+ # @return [Numeric]
274
+ def hue
275
+ rgb_to_hsl!
276
+ @attrs[:hue]
277
+ end
278
+
279
+ # The saturation component of the color.
280
+ #
281
+ # @return [Numeric]
282
+ def saturation
283
+ rgb_to_hsl!
284
+ @attrs[:saturation]
285
+ end
286
+
287
+ # The lightness component of the color.
288
+ #
289
+ # @return [Numeric]
290
+ def lightness
291
+ rgb_to_hsl!
292
+ @attrs[:lightness]
293
+ end
294
+
295
+ # The alpha channel (opacity) of the color.
296
+ # This is 1 unless otherwise defined.
297
+ #
298
+ # @return [Fixnum]
299
+ def alpha
300
+ @attrs[:alpha]
301
+ end
302
+
303
+ # Returns whether this color object is translucent;
304
+ # that is, whether the alpha channel is non-1.
305
+ #
306
+ # @return [Boolean]
307
+ def alpha?
308
+ alpha < 1
309
+ end
310
+
311
+ # Returns the red, green, and blue components of the color.
312
+ #
313
+ # @return [Array<Fixnum>] A frozen three-element array of the red, green, and blue
314
+ # values (respectively) of the color
315
+ def rgb
316
+ [red, green, blue].freeze
317
+ end
318
+
319
+ # Returns the hue, saturation, and lightness components of the color.
320
+ #
321
+ # @return [Array<Fixnum>] A frozen three-element array of the
322
+ # hue, saturation, and lightness values (respectively) of the color
323
+ def hsl
324
+ [hue, saturation, lightness].freeze
325
+ end
326
+
327
+ # The SassScript `==` operation.
328
+ # **Note that this returns a {Sass::Script::Bool} object,
329
+ # not a Ruby boolean**.
330
+ #
331
+ # @param other [Literal] The right-hand side of the operator
332
+ # @return [Bool] True if this literal is the same as the other,
333
+ # false otherwise
334
+ def eq(other)
335
+ Sass::Script::Bool.new(
336
+ other.is_a?(Color) && rgb == other.rgb && alpha == other.alpha)
337
+ end
338
+
339
+ # Returns a copy of this color with one or more channels changed.
340
+ # RGB or HSL colors may be changed, but not both at once.
341
+ #
342
+ # For example:
343
+ #
344
+ # Color.new([10, 20, 30]).with(:blue => 40)
345
+ # #=> rgb(10, 40, 30)
346
+ # Color.new([126, 126, 126]).with(:red => 0, :green => 255)
347
+ # #=> rgb(0, 255, 126)
348
+ # Color.new([255, 0, 127]).with(:saturation => 60)
349
+ # #=> rgb(204, 51, 127)
350
+ # Color.new([1, 2, 3]).with(:alpha => 0.4)
351
+ # #=> rgba(1, 2, 3, 0.4)
352
+ #
353
+ # @param attrs [{Symbol => Numeric}]
354
+ # A map of channel names (`:red`, `:green`, `:blue`,
355
+ # `:hue`, `:saturation`, `:lightness`, or `:alpha`) to values
356
+ # @return [Color] The new Color object
357
+ # @raise [ArgumentError] if both RGB and HSL keys are specified
358
+ def with(attrs)
359
+ attrs = attrs.reject {|k, v| v.nil?}
360
+ hsl = !([:hue, :saturation, :lightness] & attrs.keys).empty?
361
+ rgb = !([:red, :green, :blue] & attrs.keys).empty?
362
+ if hsl && rgb
363
+ raise ArgumentError.new("Cannot specify HSL and RGB values for a color at the same time")
364
+ end
365
+
366
+ if hsl
367
+ [:hue, :saturation, :lightness].each {|k| attrs[k] ||= send(k)}
368
+ elsif rgb
369
+ [:red, :green, :blue].each {|k| attrs[k] ||= send(k)}
370
+ else
371
+ # If we're just changing the alpha channel,
372
+ # keep all the HSL/RGB stuff we've calculated
373
+ attrs = @attrs.merge(attrs)
374
+ end
375
+ attrs[:alpha] ||= alpha
376
+
377
+ Color.new(attrs, :allow_both_rgb_and_hsl)
378
+ end
379
+
380
+ # The SassScript `+` operation.
381
+ # Its functionality depends on the type of its argument:
382
+ #
383
+ # {Number}
384
+ # : Adds the number to each of the RGB color channels.
385
+ #
386
+ # {Color}
387
+ # : Adds each of the RGB color channels together.
388
+ #
389
+ # {Literal}
390
+ # : See {Literal#plus}.
391
+ #
392
+ # @param other [Literal] The right-hand side of the operator
393
+ # @return [Color] The resulting color
394
+ # @raise [Sass::SyntaxError] if `other` is a number with units
395
+ def plus(other)
396
+ if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
397
+ piecewise(other, :+)
398
+ else
399
+ super
400
+ end
401
+ end
402
+
403
+ # The SassScript `-` operation.
404
+ # Its functionality depends on the type of its argument:
405
+ #
406
+ # {Number}
407
+ # : Subtracts the number from each of the RGB color channels.
408
+ #
409
+ # {Color}
410
+ # : Subtracts each of the other color's RGB color channels from this color's.
411
+ #
412
+ # {Literal}
413
+ # : See {Literal#minus}.
414
+ #
415
+ # @param other [Literal] The right-hand side of the operator
416
+ # @return [Color] The resulting color
417
+ # @raise [Sass::SyntaxError] if `other` is a number with units
418
+ def minus(other)
419
+ if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
420
+ piecewise(other, :-)
421
+ else
422
+ super
423
+ end
424
+ end
425
+
426
+ # The SassScript `*` operation.
427
+ # Its functionality depends on the type of its argument:
428
+ #
429
+ # {Number}
430
+ # : Multiplies the number by each of the RGB color channels.
431
+ #
432
+ # {Color}
433
+ # : Multiplies each of the RGB color channels together.
434
+ #
435
+ # @param other [Number, Color] The right-hand side of the operator
436
+ # @return [Color] The resulting color
437
+ # @raise [Sass::SyntaxError] if `other` is a number with units
438
+ def times(other)
439
+ if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
440
+ piecewise(other, :*)
441
+ else
442
+ raise NoMethodError.new(nil, :times)
443
+ end
444
+ end
445
+
446
+ # The SassScript `/` operation.
447
+ # Its functionality depends on the type of its argument:
448
+ #
449
+ # {Number}
450
+ # : Divides each of the RGB color channels by the number.
451
+ #
452
+ # {Color}
453
+ # : Divides each of this color's RGB color channels by the other color's.
454
+ #
455
+ # {Literal}
456
+ # : See {Literal#div}.
457
+ #
458
+ # @param other [Literal] The right-hand side of the operator
459
+ # @return [Color] The resulting color
460
+ # @raise [Sass::SyntaxError] if `other` is a number with units
461
+ def div(other)
462
+ if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
463
+ piecewise(other, :/)
464
+ else
465
+ super
466
+ end
467
+ end
468
+
469
+ # The SassScript `%` operation.
470
+ # Its functionality depends on the type of its argument:
471
+ #
472
+ # {Number}
473
+ # : Takes each of the RGB color channels module the number.
474
+ #
475
+ # {Color}
476
+ # : Takes each of this color's RGB color channels modulo the other color's.
477
+ #
478
+ # @param other [Number, Color] The right-hand side of the operator
479
+ # @return [Color] The resulting color
480
+ # @raise [Sass::SyntaxError] if `other` is a number with units
481
+ def mod(other)
482
+ if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
483
+ piecewise(other, :%)
484
+ else
485
+ raise NoMethodError.new(nil, :mod)
486
+ end
487
+ end
488
+
489
+ # Returns a string representation of the color.
490
+ # This is usually the color's hex value,
491
+ # but if the color has a name that's used instead.
492
+ #
493
+ # @return [String] The string representation
494
+ def to_s(opts = {})
495
+ return rgba_str if alpha?
496
+ return smallest if options[:style] == :compressed
497
+ return COLOR_NAMES_REVERSE[rgb] if COLOR_NAMES_REVERSE[rgb]
498
+ hex_str
499
+ end
500
+ alias_method :to_sass, :to_s
501
+
502
+ # Returns a string representation of the color.
503
+ #
504
+ # @return [String] The hex value
505
+ def inspect
506
+ alpha? ? rgba_str : hex_str
507
+ end
508
+
509
+ private
510
+
511
+ def smallest
512
+ small_hex_str = hex_str.gsub(/^#(.)\1(.)\2(.)\3$/, '#\1\2\3')
513
+ return small_hex_str unless (color = COLOR_NAMES_REVERSE[rgb]) &&
514
+ color.size <= small_hex_str.size
515
+ return color
516
+ end
517
+
518
+ def rgba_str
519
+ split = options[:style] == :compressed ? ',' : ', '
520
+ "rgba(#{rgb.join(split)}#{split}#{Number.round(alpha)})"
521
+ end
522
+
523
+ def hex_str
524
+ red, green, blue = rgb.map { |num| num.to_s(16).rjust(2, '0') }
525
+ "##{red}#{green}#{blue}"
526
+ end
527
+
528
+ def piecewise(other, operation)
529
+ other_num = other.is_a? Number
530
+ if other_num && !other.unitless?
531
+ raise Sass::SyntaxError.new("Cannot add a number with units (#{other}) to a color (#{self}).")
532
+ end
533
+
534
+ result = []
535
+ for i in (0...3)
536
+ res = rgb[i].send(operation, other_num ? other.value : other.rgb[i])
537
+ result[i] = [ [res, 255].min, 0 ].max
538
+ end
539
+
540
+ if !other_num && other.alpha != alpha
541
+ raise Sass::SyntaxError.new("Alpha channels must be equal: #{self} #{operation} #{other}")
542
+ end
543
+
544
+ with(:red => result[0], :green => result[1], :blue => result[2])
545
+ end
546
+
547
+ def hsl_to_rgb!
548
+ return if @attrs[:red] && @attrs[:blue] && @attrs[:green]
549
+
550
+ h = @attrs[:hue] / 360.0
551
+ s = @attrs[:saturation] / 100.0
552
+ l = @attrs[:lightness] / 100.0
553
+
554
+ # Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
555
+ m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s
556
+ m1 = l * 2 - m2
557
+ @attrs[:red], @attrs[:green], @attrs[:blue] = [
558
+ hue_to_rgb(m1, m2, h + 1.0/3),
559
+ hue_to_rgb(m1, m2, h),
560
+ hue_to_rgb(m1, m2, h - 1.0/3)
561
+ ].map {|c| (c * 0xff).round}
562
+ end
563
+
564
+ def hue_to_rgb(m1, m2, h)
565
+ h += 1 if h < 0
566
+ h -= 1 if h > 1
567
+ return m1 + (m2 - m1) * h * 6 if h * 6 < 1
568
+ return m2 if h * 2 < 1
569
+ return m1 + (m2 - m1) * (2.0/3 - h) * 6 if h * 3 < 2
570
+ return m1
571
+ end
572
+
573
+ def rgb_to_hsl!
574
+ return if @attrs[:hue] && @attrs[:saturation] && @attrs[:lightness]
575
+ r, g, b = [:red, :green, :blue].map {|k| @attrs[k] / 255.0}
576
+
577
+ # Algorithm from http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
578
+ max = [r, g, b].max
579
+ min = [r, g, b].min
580
+ d = max - min
581
+
582
+ h =
583
+ case max
584
+ when min; 0
585
+ when r; 60 * (g-b)/d
586
+ when g; 60 * (b-r)/d + 120
587
+ when b; 60 * (r-g)/d + 240
588
+ end
589
+
590
+ l = (max + min)/2.0
591
+
592
+ s =
593
+ if max == min
594
+ 0
595
+ elsif l < 0.5
596
+ d/(2*l)
597
+ else
598
+ d/(2 - 2*l)
599
+ end
600
+
601
+ @attrs[:hue] = h % 360
602
+ @attrs[:saturation] = s * 100
603
+ @attrs[:lightness] = l * 100
604
+ end
605
+ end
606
+ end