oreorenasass 3.4.4 → 3.4.5

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 (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