oreorenasass 3.4.4 → 3.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +50 -70
  4. data/Rakefile +5 -26
  5. data/VERSION +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/bin/sass +1 -1
  8. data/bin/scss +1 -1
  9. data/lib/sass.rb +12 -19
  10. data/lib/sass/cache_stores/base.rb +2 -2
  11. data/lib/sass/cache_stores/chain.rb +1 -2
  12. data/lib/sass/cache_stores/filesystem.rb +5 -1
  13. data/lib/sass/cache_stores/memory.rb +1 -1
  14. data/lib/sass/cache_stores/null.rb +2 -2
  15. data/lib/sass/callbacks.rb +0 -1
  16. data/lib/sass/css.rb +13 -11
  17. data/lib/sass/engine.rb +173 -424
  18. data/lib/sass/environment.rb +58 -148
  19. data/lib/sass/error.rb +14 -11
  20. data/lib/sass/exec.rb +703 -5
  21. data/lib/sass/importers/base.rb +6 -49
  22. data/lib/sass/importers/filesystem.rb +19 -44
  23. data/lib/sass/logger.rb +4 -1
  24. data/lib/sass/logger/base.rb +4 -2
  25. data/lib/sass/logger/log_level.rb +7 -3
  26. data/lib/sass/media.rb +23 -20
  27. data/lib/sass/plugin.rb +7 -7
  28. data/lib/sass/plugin/compiler.rb +145 -304
  29. data/lib/sass/plugin/configuration.rb +23 -18
  30. data/lib/sass/plugin/merb.rb +1 -1
  31. data/lib/sass/plugin/staleness_checker.rb +3 -3
  32. data/lib/sass/repl.rb +3 -3
  33. data/lib/sass/script.rb +8 -35
  34. data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
  35. data/lib/sass/script/bool.rb +18 -0
  36. data/lib/sass/script/color.rb +606 -0
  37. data/lib/sass/script/css_lexer.rb +4 -8
  38. data/lib/sass/script/css_parser.rb +2 -5
  39. data/lib/sass/script/funcall.rb +245 -0
  40. data/lib/sass/script/functions.rb +408 -1491
  41. data/lib/sass/script/interpolation.rb +79 -0
  42. data/lib/sass/script/lexer.rb +68 -172
  43. data/lib/sass/script/list.rb +85 -0
  44. data/lib/sass/script/literal.rb +221 -0
  45. data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
  46. data/lib/sass/script/{value/null.rb → null.rb} +7 -14
  47. data/lib/sass/script/{value/number.rb → number.rb} +75 -152
  48. data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
  49. data/lib/sass/script/parser.rb +110 -245
  50. data/lib/sass/script/string.rb +51 -0
  51. data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
  52. data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
  53. data/lib/sass/script/variable.rb +58 -0
  54. data/lib/sass/scss/css_parser.rb +3 -9
  55. data/lib/sass/scss/parser.rb +421 -450
  56. data/lib/sass/scss/rx.rb +11 -19
  57. data/lib/sass/scss/static_parser.rb +7 -321
  58. data/lib/sass/selector.rb +194 -68
  59. data/lib/sass/selector/abstract_sequence.rb +14 -29
  60. data/lib/sass/selector/comma_sequence.rb +25 -108
  61. data/lib/sass/selector/sequence.rb +66 -159
  62. data/lib/sass/selector/simple.rb +25 -23
  63. data/lib/sass/selector/simple_sequence.rb +63 -173
  64. data/lib/sass/shared.rb +1 -1
  65. data/lib/sass/supports.rb +15 -13
  66. data/lib/sass/tree/charset_node.rb +1 -1
  67. data/lib/sass/tree/comment_node.rb +3 -3
  68. data/lib/sass/tree/css_import_node.rb +11 -11
  69. data/lib/sass/tree/debug_node.rb +2 -2
  70. data/lib/sass/tree/directive_node.rb +4 -21
  71. data/lib/sass/tree/each_node.rb +8 -8
  72. data/lib/sass/tree/extend_node.rb +7 -14
  73. data/lib/sass/tree/for_node.rb +4 -4
  74. data/lib/sass/tree/function_node.rb +4 -9
  75. data/lib/sass/tree/if_node.rb +1 -1
  76. data/lib/sass/tree/import_node.rb +5 -4
  77. data/lib/sass/tree/media_node.rb +14 -4
  78. data/lib/sass/tree/mixin_def_node.rb +4 -4
  79. data/lib/sass/tree/mixin_node.rb +8 -21
  80. data/lib/sass/tree/node.rb +12 -54
  81. data/lib/sass/tree/prop_node.rb +20 -39
  82. data/lib/sass/tree/return_node.rb +2 -3
  83. data/lib/sass/tree/root_node.rb +3 -19
  84. data/lib/sass/tree/rule_node.rb +22 -35
  85. data/lib/sass/tree/supports_node.rb +13 -0
  86. data/lib/sass/tree/trace_node.rb +1 -2
  87. data/lib/sass/tree/variable_node.rb +3 -9
  88. data/lib/sass/tree/visitors/base.rb +8 -5
  89. data/lib/sass/tree/visitors/check_nesting.rb +19 -49
  90. data/lib/sass/tree/visitors/convert.rb +56 -74
  91. data/lib/sass/tree/visitors/cssize.rb +74 -202
  92. data/lib/sass/tree/visitors/deep_copy.rb +5 -10
  93. data/lib/sass/tree/visitors/extend.rb +7 -7
  94. data/lib/sass/tree/visitors/perform.rb +185 -278
  95. data/lib/sass/tree/visitors/set_options.rb +6 -20
  96. data/lib/sass/tree/visitors/to_css.rb +81 -234
  97. data/lib/sass/tree/warn_node.rb +2 -2
  98. data/lib/sass/tree/while_node.rb +2 -2
  99. data/lib/sass/util.rb +152 -522
  100. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  101. data/lib/sass/util/subset_map.rb +3 -4
  102. data/lib/sass/util/test.rb +1 -0
  103. data/lib/sass/version.rb +22 -20
  104. data/test/Gemfile +3 -0
  105. data/test/Gemfile.lock +10 -0
  106. data/test/sass/cache_test.rb +20 -62
  107. data/test/sass/callbacks_test.rb +1 -1
  108. data/test/sass/conversion_test.rb +2 -296
  109. data/test/sass/css2sass_test.rb +4 -23
  110. data/test/sass/engine_test.rb +354 -411
  111. data/test/sass/exec_test.rb +2 -2
  112. data/test/sass/extend_test.rb +145 -324
  113. data/test/sass/functions_test.rb +86 -873
  114. data/test/sass/importer_test.rb +21 -241
  115. data/test/sass/logger_test.rb +1 -1
  116. data/test/sass/more_results/more_import.css +1 -1
  117. data/test/sass/plugin_test.rb +26 -16
  118. data/test/sass/results/compact.css +1 -1
  119. data/test/sass/results/complex.css +4 -4
  120. data/test/sass/results/expanded.css +1 -1
  121. data/test/sass/results/import.css +1 -1
  122. data/test/sass/results/import_charset_ibm866.css +2 -2
  123. data/test/sass/results/mixins.css +17 -17
  124. data/test/sass/results/nested.css +1 -1
  125. data/test/sass/results/parent_ref.css +2 -2
  126. data/test/sass/results/script.css +3 -3
  127. data/test/sass/results/scss_import.css +1 -1
  128. data/test/sass/script_conversion_test.rb +7 -36
  129. data/test/sass/script_test.rb +53 -485
  130. data/test/sass/scss/css_test.rb +28 -143
  131. data/test/sass/scss/rx_test.rb +4 -4
  132. data/test/sass/scss/scss_test.rb +325 -2119
  133. data/test/sass/templates/scss_import.scss +1 -2
  134. data/test/sass/test_helper.rb +1 -1
  135. data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
  136. data/test/sass/util/subset_map_test.rb +2 -2
  137. data/test/sass/util_test.rb +1 -86
  138. data/test/test_helper.rb +8 -37
  139. metadata +19 -66
  140. data/lib/sass/exec/base.rb +0 -187
  141. data/lib/sass/exec/sass_convert.rb +0 -264
  142. data/lib/sass/exec/sass_scss.rb +0 -424
  143. data/lib/sass/features.rb +0 -47
  144. data/lib/sass/script/tree.rb +0 -16
  145. data/lib/sass/script/tree/funcall.rb +0 -306
  146. data/lib/sass/script/tree/interpolation.rb +0 -118
  147. data/lib/sass/script/tree/list_literal.rb +0 -77
  148. data/lib/sass/script/tree/literal.rb +0 -45
  149. data/lib/sass/script/tree/map_literal.rb +0 -64
  150. data/lib/sass/script/tree/selector.rb +0 -26
  151. data/lib/sass/script/tree/variable.rb +0 -57
  152. data/lib/sass/script/value.rb +0 -11
  153. data/lib/sass/script/value/base.rb +0 -240
  154. data/lib/sass/script/value/bool.rb +0 -35
  155. data/lib/sass/script/value/color.rb +0 -680
  156. data/lib/sass/script/value/helpers.rb +0 -262
  157. data/lib/sass/script/value/list.rb +0 -113
  158. data/lib/sass/script/value/map.rb +0 -70
  159. data/lib/sass/script/value/string.rb +0 -97
  160. data/lib/sass/selector/pseudo.rb +0 -256
  161. data/lib/sass/source/map.rb +0 -210
  162. data/lib/sass/source/position.rb +0 -39
  163. data/lib/sass/source/range.rb +0 -41
  164. data/lib/sass/stack.rb +0 -120
  165. data/lib/sass/tree/at_root_node.rb +0 -83
  166. data/lib/sass/tree/error_node.rb +0 -18
  167. data/lib/sass/tree/keyframe_rule_node.rb +0 -15
  168. data/lib/sass/util/cross_platform_random.rb +0 -19
  169. data/lib/sass/util/normalized_map.rb +0 -130
  170. data/lib/sass/util/ordered_hash.rb +0 -192
  171. data/test/sass/compiler_test.rb +0 -232
  172. data/test/sass/encoding_test.rb +0 -219
  173. data/test/sass/source_map_test.rb +0 -977
  174. data/test/sass/superselector_test.rb +0 -191
  175. data/test/sass/util/normalized_map_test.rb +0 -51
  176. data/test/sass/value_helpers_test.rb +0 -179
@@ -1,9 +1,11 @@
1
+ # We keep configuration in its own self-contained file
2
+ # so that we can load it independently in Rails 3,
3
+ # where the full plugin stuff is lazy-loaded.
4
+
1
5
  module Sass
2
6
  module Plugin
3
- # We keep configuration in its own self-contained file
4
- # so that we can load it independently in Rails 3,
5
- # where the full plugin stuff is lazy-loaded.
6
7
  module Configuration
8
+
7
9
  # Returns the default options for a {Sass::Plugin::Compiler}.
8
10
  #
9
11
  # @return [{Symbol => Object}]
@@ -17,8 +19,7 @@ module Sass
17
19
  }.freeze
18
20
  end
19
21
 
20
- # Resets the options and
21
- # {Sass::Callbacks::InstanceMethods#clear_callbacks! clears all callbacks}.
22
+ # Resets the options and {Sass::Callbacks::InstanceMethods#clear_callbacks! clears all callbacks}.
22
23
  def reset!
23
24
  @options = nil
24
25
  clear_callbacks!
@@ -32,12 +33,22 @@ module Sass
32
33
  @options ||= default_options.dup
33
34
  end
34
35
 
36
+ # Sets the options hash.
37
+ # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
38
+ # See {Sass::Plugin::Configuration#reset!}
39
+ # @deprecated Instead, modify the options hash in-place.
40
+ # @param value [{Symbol => Object}] The options hash
41
+ def options=(value)
42
+ Sass::Util.sass_warn("Setting Sass::Plugin.options is deprecated " +
43
+ "and will be removed in a future release.")
44
+ options.merge!(value)
45
+ end
46
+
35
47
  # Adds a new template-location/css-location mapping.
36
48
  # This means that Sass/SCSS files in `template_location`
37
49
  # will be compiled to CSS files in `css_location`.
38
50
  #
39
- # This is preferred over manually manipulating the
40
- # {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
51
+ # This is preferred over manually manipulating the {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
41
52
  # since the option can be in multiple formats.
42
53
  #
43
54
  # Note that this method will change `options[:template_location]`
@@ -57,8 +68,7 @@ module Sass
57
68
  # This means that Sass/SCSS files in `template_location`
58
69
  # will no longer be compiled to CSS files in `css_location`.
59
70
  #
60
- # This is preferred over manually manipulating the
61
- # {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
71
+ # This is preferred over manually manipulating the {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
62
72
  # since the option can be in multiple formats.
63
73
  #
64
74
  # Note that this method will change `options[:template_location]`
@@ -102,15 +112,10 @@ module Sass
102
112
  options[:template_location] =
103
113
  case options[:template_location]
104
114
  when nil
105
- if options[:css_location]
106
- [[File.join(options[:css_location], 'sass'), options[:css_location]]]
107
- else
108
- []
109
- end
110
- when String
111
- [[options[:template_location], options[:css_location]]]
112
- else
113
- options[:template_location].to_a
115
+ options[:css_location] ?
116
+ [[File.join(options[:css_location], 'sass'), options[:css_location]]] : []
117
+ when String; [[options[:template_location], options[:css_location]]]
118
+ else; options[:template_location].to_a
114
119
  end
115
120
  end
116
121
  end
@@ -5,7 +5,7 @@ unless defined?(Sass::MERB_LOADED)
5
5
  # Different default options in a m envirionment.
6
6
  def default_options
7
7
  @default_options ||= begin
8
- version = Merb::VERSION.split('.').map {|n| n.to_i}
8
+ version = Merb::VERSION.split('.').map { |n| n.to_i }
9
9
  if version[0] <= 0 && version[1] < 5
10
10
  root = MERB_ROOT
11
11
  env = MERB_ENV
@@ -46,8 +46,8 @@ module Sass
46
46
  @actively_checking = Set.new
47
47
 
48
48
  # Entries in the following instance-level caches are never explicitly expired.
49
- # Instead they are supposed to automatically go out of scope when a series of staleness
50
- # checks (this instance of StalenessChecker was created for) is finished.
49
+ # Instead they are supposed to automaticaly go out of scope when a series of staleness checks
50
+ # (this instance of StalenessChecker was created for) is finished.
51
51
  @mtimes, @dependencies_stale, @parse_trees = {}, {}, {}
52
52
  @options = Sass::Engine.normalize_options(options)
53
53
  end
@@ -156,7 +156,7 @@ module Sass
156
156
  end
157
157
 
158
158
  def dependency_updated?(css_mtime)
159
- proc do |uri, importer|
159
+ Proc.new do |uri, importer|
160
160
  next true if @actively_checking.include?(uri)
161
161
  begin
162
162
  @actively_checking << uri
data/lib/sass/repl.rb CHANGED
@@ -18,7 +18,7 @@ module Sass
18
18
  @line = 0
19
19
  loop do
20
20
  @line += 1
21
- unless (text = Readline.readline('>> '))
21
+ unless text = Readline.readline('>> ')
22
22
  puts
23
23
  return
24
24
  end
@@ -48,8 +48,8 @@ module Sass
48
48
  rescue Sass::SyntaxError => e
49
49
  puts "SyntaxError: #{e.message}"
50
50
  if @options[:trace]
51
- e.backtrace.each do |line|
52
- puts "\tfrom #{line}"
51
+ e.backtrace.each do |e|
52
+ puts "\tfrom #{e}"
53
53
  end
54
54
  end
55
55
  end
data/lib/sass/script.rb CHANGED
@@ -1,4 +1,9 @@
1
- require 'sass/scss/rx'
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'
2
7
 
3
8
  module Sass
4
9
  # SassScript is code that's embedded in Sass documents
@@ -7,8 +12,7 @@ module Sass
7
12
  # This module contains code that handles the parsing and evaluation of SassScript.
8
13
  module Script
9
14
  # The regular expression used to parse variables.
10
- MATCH = /^\$(#{Sass::SCSS::RX::IDENT})\s*:\s*(.+?)
11
- (!#{Sass::SCSS::RX::IDENT}(?:\s+!#{Sass::SCSS::RX::IDENT})*)?$/x
15
+ MATCH = /^\$(#{Sass::SCSS::RX::IDENT})\s*:\s*(.+?)(!(?i:default))?$/
12
16
 
13
17
  # The regular expression used to validate variables without matching.
14
18
  VALIDATE = /^\$#{Sass::SCSS::RX::IDENT}$/
@@ -22,7 +26,7 @@ module Sass
22
26
  # Used for error reporting
23
27
  # @param options [{Symbol => Object}] An options hash;
24
28
  # see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
25
- # @return [Script::Tree::Node] The root node of the parse tree
29
+ # @return [Script::Node] The root node of the parse tree
26
30
  def self.parse(value, line, offset, options = {})
27
31
  Parser.parse(value, line, offset, options)
28
32
  rescue Sass::SyntaxError => e
@@ -31,36 +35,5 @@ module Sass
31
35
  raise e
32
36
  end
33
37
 
34
- require 'sass/script/functions'
35
- require 'sass/script/parser'
36
- require 'sass/script/tree'
37
- require 'sass/script/value'
38
-
39
- # @private
40
- CONST_RENAMES = {
41
- :Literal => Sass::Script::Value::Base,
42
- :ArgList => Sass::Script::Value::ArgList,
43
- :Bool => Sass::Script::Value::Bool,
44
- :Color => Sass::Script::Value::Color,
45
- :List => Sass::Script::Value::List,
46
- :Null => Sass::Script::Value::Null,
47
- :Number => Sass::Script::Value::Number,
48
- :String => Sass::Script::Value::String,
49
- :Node => Sass::Script::Tree::Node,
50
- :Funcall => Sass::Script::Tree::Funcall,
51
- :Interpolation => Sass::Script::Tree::Interpolation,
52
- :Operation => Sass::Script::Tree::Operation,
53
- :StringInterpolation => Sass::Script::Tree::StringInterpolation,
54
- :UnaryOperation => Sass::Script::Tree::UnaryOperation,
55
- :Variable => Sass::Script::Tree::Variable,
56
- }
57
-
58
- # @private
59
- def self.const_missing(name)
60
- klass = CONST_RENAMES[name]
61
- super unless klass
62
- CONST_RENAMES.each {|n, k| const_set(n, k)}
63
- klass
64
- end
65
38
  end
66
39
  end
@@ -1,4 +1,4 @@
1
- module Sass::Script::Value
1
+ module Sass::Script
2
2
  # A SassScript object representing a variable argument list. This works just
3
3
  # like a normal list, but can also contain keyword arguments.
4
4
  #
@@ -13,24 +13,40 @@ module Sass::Script::Value
13
13
 
14
14
  # Creates a new argument list.
15
15
  #
16
- # @param value [Array<Value>] See \{List#value}.
17
- # @param keywords [Hash<String, Value>, NormalizedMap<Value>] See \{#keywords}
16
+ # @param value [Array<Literal>] See \{List#value}.
17
+ # @param keywords [Hash<String, Literal>] See \{#keywords}
18
18
  # @param separator [String] See \{List#separator}.
19
19
  def initialize(value, keywords, separator)
20
20
  super(value, separator)
21
- if keywords.is_a?(Sass::Util::NormalizedMap)
22
- @keywords = keywords
23
- else
24
- @keywords = Sass::Util::NormalizedMap.new(keywords)
25
- end
21
+ @keywords = keywords
26
22
  end
27
23
 
28
24
  # The keyword arguments attached to this list.
29
25
  #
30
- # @return [NormalizedMap<Value>]
26
+ # @return [Hash<String, Literal>]
31
27
  def keywords
32
28
  @keywords_accessed = true
33
29
  @keywords
34
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
35
51
  end
36
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