aliddle-sass 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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