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,35 +0,0 @@
1
- module Sass::Script::Value
2
- # A SassScript object representing a boolean (true or false) value.
3
- class Bool < Base
4
- # The true value in SassScript.
5
- #
6
- # This is assigned before new is overridden below so that we use the default implementation.
7
- TRUE = new(true)
8
-
9
- # The false value in SassScript.
10
- #
11
- # This is assigned before new is overridden below so that we use the default implementation.
12
- FALSE = new(false)
13
-
14
- # We override object creation so that users of the core API
15
- # will not need to know that booleans are specific constants.
16
- #
17
- # @param value A ruby value that will be tested for truthiness.
18
- # @return [Bool] TRUE if value is truthy, FALSE if value is falsey
19
- def self.new(value)
20
- value ? TRUE : FALSE
21
- end
22
-
23
- # The Ruby value of the boolean.
24
- #
25
- # @return [Boolean]
26
- attr_reader :value
27
- alias_method :to_bool, :value
28
-
29
- # @return [String] "true" or "false"
30
- def to_s(opts = {})
31
- @value.to_s
32
- end
33
- alias_method :to_sass, :to_s
34
- end
35
- end
@@ -1,680 +0,0 @@
1
- module Sass::Script::Value
2
- # A SassScript object representing a CSS color.
3
- #
4
- # A color may be represented internally as RGBA, HSLA, or both.
5
- # It's originally represented as whatever its input is;
6
- # if it's created with RGB values, it's represented as RGBA,
7
- # and if it's created with HSL values, it's represented as HSLA.
8
- # Once a property is accessed that requires the other representation --
9
- # for example, \{#red} for an HSL color --
10
- # that component is calculated and cached.
11
- #
12
- # The alpha channel of a color is independent of its RGB or HSL representation.
13
- # It's always stored, as 1 if nothing else is specified.
14
- # If only the alpha channel is modified using \{#with},
15
- # the cached RGB and HSL values are retained.
16
- class Color < Base
17
- # @private
18
- #
19
- # Convert a ruby integer to a rgba components
20
- # @param color [Fixnum]
21
- # @return [Array<Fixnum>] Array of 4 numbers representing r,g,b and alpha
22
- def self.int_to_rgba(color)
23
- rgba = (0..3).map {|n| color >> (n << 3) & 0xff}.reverse
24
- rgba[-1] = rgba[-1] / 255.0
25
- rgba
26
- end
27
-
28
- ALTERNATE_COLOR_NAMES = Sass::Util.map_vals({
29
- 'aqua' => 0x00FFFFFF,
30
- 'darkgrey' => 0xA9A9A9FF,
31
- 'darkslategrey' => 0x2F4F4FFF,
32
- 'dimgrey' => 0x696969FF,
33
- 'fuchsia' => 0xFF00FFFF,
34
- 'grey' => 0x808080FF,
35
- 'lightgrey' => 0xD3D3D3FF,
36
- 'lightslategrey' => 0x778899FF,
37
- 'slategrey' => 0x708090FF,
38
- }, &method(:int_to_rgba))
39
-
40
- # A hash from color names to `[red, green, blue]` value arrays.
41
- COLOR_NAMES = Sass::Util.map_vals({
42
- 'aliceblue' => 0xF0F8FFFF,
43
- 'antiquewhite' => 0xFAEBD7FF,
44
- 'aquamarine' => 0x7FFFD4FF,
45
- 'azure' => 0xF0FFFFFF,
46
- 'beige' => 0xF5F5DCFF,
47
- 'bisque' => 0xFFE4C4FF,
48
- 'black' => 0x000000FF,
49
- 'blanchedalmond' => 0xFFEBCDFF,
50
- 'blue' => 0x0000FFFF,
51
- 'blueviolet' => 0x8A2BE2FF,
52
- 'brown' => 0xA52A2AFF,
53
- 'burlywood' => 0xDEB887FF,
54
- 'cadetblue' => 0x5F9EA0FF,
55
- 'chartreuse' => 0x7FFF00FF,
56
- 'chocolate' => 0xD2691EFF,
57
- 'coral' => 0xFF7F50FF,
58
- 'cornflowerblue' => 0x6495EDFF,
59
- 'cornsilk' => 0xFFF8DCFF,
60
- 'crimson' => 0xDC143CFF,
61
- 'cyan' => 0x00FFFFFF,
62
- 'darkblue' => 0x00008BFF,
63
- 'darkcyan' => 0x008B8BFF,
64
- 'darkgoldenrod' => 0xB8860BFF,
65
- 'darkgray' => 0xA9A9A9FF,
66
- 'darkgreen' => 0x006400FF,
67
- 'darkkhaki' => 0xBDB76BFF,
68
- 'darkmagenta' => 0x8B008BFF,
69
- 'darkolivegreen' => 0x556B2FFF,
70
- 'darkorange' => 0xFF8C00FF,
71
- 'darkorchid' => 0x9932CCFF,
72
- 'darkred' => 0x8B0000FF,
73
- 'darksalmon' => 0xE9967AFF,
74
- 'darkseagreen' => 0x8FBC8FFF,
75
- 'darkslateblue' => 0x483D8BFF,
76
- 'darkslategray' => 0x2F4F4FFF,
77
- 'darkturquoise' => 0x00CED1FF,
78
- 'darkviolet' => 0x9400D3FF,
79
- 'deeppink' => 0xFF1493FF,
80
- 'deepskyblue' => 0x00BFFFFF,
81
- 'dimgray' => 0x696969FF,
82
- 'dodgerblue' => 0x1E90FFFF,
83
- 'firebrick' => 0xB22222FF,
84
- 'floralwhite' => 0xFFFAF0FF,
85
- 'forestgreen' => 0x228B22FF,
86
- 'gainsboro' => 0xDCDCDCFF,
87
- 'ghostwhite' => 0xF8F8FFFF,
88
- 'gold' => 0xFFD700FF,
89
- 'goldenrod' => 0xDAA520FF,
90
- 'gray' => 0x808080FF,
91
- 'green' => 0x008000FF,
92
- 'greenyellow' => 0xADFF2FFF,
93
- 'honeydew' => 0xF0FFF0FF,
94
- 'hotpink' => 0xFF69B4FF,
95
- 'indianred' => 0xCD5C5CFF,
96
- 'indigo' => 0x4B0082FF,
97
- 'ivory' => 0xFFFFF0FF,
98
- 'khaki' => 0xF0E68CFF,
99
- 'lavender' => 0xE6E6FAFF,
100
- 'lavenderblush' => 0xFFF0F5FF,
101
- 'lawngreen' => 0x7CFC00FF,
102
- 'lemonchiffon' => 0xFFFACDFF,
103
- 'lightblue' => 0xADD8E6FF,
104
- 'lightcoral' => 0xF08080FF,
105
- 'lightcyan' => 0xE0FFFFFF,
106
- 'lightgoldenrodyellow' => 0xFAFAD2FF,
107
- 'lightgreen' => 0x90EE90FF,
108
- 'lightgray' => 0xD3D3D3FF,
109
- 'lightpink' => 0xFFB6C1FF,
110
- 'lightsalmon' => 0xFFA07AFF,
111
- 'lightseagreen' => 0x20B2AAFF,
112
- 'lightskyblue' => 0x87CEFAFF,
113
- 'lightslategray' => 0x778899FF,
114
- 'lightsteelblue' => 0xB0C4DEFF,
115
- 'lightyellow' => 0xFFFFE0FF,
116
- 'lime' => 0x00FF00FF,
117
- 'limegreen' => 0x32CD32FF,
118
- 'linen' => 0xFAF0E6FF,
119
- 'magenta' => 0xFF00FFFF,
120
- 'maroon' => 0x800000FF,
121
- 'mediumaquamarine' => 0x66CDAAFF,
122
- 'mediumblue' => 0x0000CDFF,
123
- 'mediumorchid' => 0xBA55D3FF,
124
- 'mediumpurple' => 0x9370DBFF,
125
- 'mediumseagreen' => 0x3CB371FF,
126
- 'mediumslateblue' => 0x7B68EEFF,
127
- 'mediumspringgreen' => 0x00FA9AFF,
128
- 'mediumturquoise' => 0x48D1CCFF,
129
- 'mediumvioletred' => 0xC71585FF,
130
- 'midnightblue' => 0x191970FF,
131
- 'mintcream' => 0xF5FFFAFF,
132
- 'mistyrose' => 0xFFE4E1FF,
133
- 'moccasin' => 0xFFE4B5FF,
134
- 'navajowhite' => 0xFFDEADFF,
135
- 'navy' => 0x000080FF,
136
- 'oldlace' => 0xFDF5E6FF,
137
- 'olive' => 0x808000FF,
138
- 'olivedrab' => 0x6B8E23FF,
139
- 'orange' => 0xFFA500FF,
140
- 'orangered' => 0xFF4500FF,
141
- 'orchid' => 0xDA70D6FF,
142
- 'palegoldenrod' => 0xEEE8AAFF,
143
- 'palegreen' => 0x98FB98FF,
144
- 'paleturquoise' => 0xAFEEEEFF,
145
- 'palevioletred' => 0xDB7093FF,
146
- 'papayawhip' => 0xFFEFD5FF,
147
- 'peachpuff' => 0xFFDAB9FF,
148
- 'peru' => 0xCD853FFF,
149
- 'pink' => 0xFFC0CBFF,
150
- 'plum' => 0xDDA0DDFF,
151
- 'powderblue' => 0xB0E0E6FF,
152
- 'purple' => 0x800080FF,
153
- 'red' => 0xFF0000FF,
154
- 'rebeccapurple' => 0x663399FF,
155
- 'rosybrown' => 0xBC8F8FFF,
156
- 'royalblue' => 0x4169E1FF,
157
- 'saddlebrown' => 0x8B4513FF,
158
- 'salmon' => 0xFA8072FF,
159
- 'sandybrown' => 0xF4A460FF,
160
- 'seagreen' => 0x2E8B57FF,
161
- 'seashell' => 0xFFF5EEFF,
162
- 'sienna' => 0xA0522DFF,
163
- 'silver' => 0xC0C0C0FF,
164
- 'skyblue' => 0x87CEEBFF,
165
- 'slateblue' => 0x6A5ACDFF,
166
- 'slategray' => 0x708090FF,
167
- 'snow' => 0xFFFAFAFF,
168
- 'springgreen' => 0x00FF7FFF,
169
- 'steelblue' => 0x4682B4FF,
170
- 'tan' => 0xD2B48CFF,
171
- 'teal' => 0x008080FF,
172
- 'thistle' => 0xD8BFD8FF,
173
- 'tomato' => 0xFF6347FF,
174
- 'transparent' => 0x00000000,
175
- 'turquoise' => 0x40E0D0FF,
176
- 'violet' => 0xEE82EEFF,
177
- 'wheat' => 0xF5DEB3FF,
178
- 'white' => 0xFFFFFFFF,
179
- 'whitesmoke' => 0xF5F5F5FF,
180
- 'yellow' => 0xFFFF00FF,
181
- 'yellowgreen' => 0x9ACD32FF
182
- }, &method(:int_to_rgba))
183
-
184
- # A hash from `[red, green, blue, alpha]` value arrays to color names.
185
- COLOR_NAMES_REVERSE = COLOR_NAMES.invert.freeze
186
-
187
- # We add the alternate color names after inverting because
188
- # different ruby implementations and versions vary on the ordering of the result of invert.
189
- COLOR_NAMES.update(ALTERNATE_COLOR_NAMES).freeze
190
-
191
- # The user's original representation of the color.
192
- #
193
- # @return [String]
194
- attr_reader :representation
195
-
196
- # Constructs an RGB or HSL color object,
197
- # optionally with an alpha channel.
198
- #
199
- # RGB values are clipped within 0 and 255.
200
- # Saturation and lightness values are clipped within 0 and 100.
201
- # The alpha value is clipped within 0 and 1.
202
- #
203
- # @raise [Sass::SyntaxError] if any color value isn't in the specified range
204
- #
205
- # @overload initialize(attrs)
206
- # The attributes are specified as a hash. This hash must contain either
207
- # `:hue`, `:saturation`, and `:value` keys, or `:red`, `:green`, and
208
- # `:blue` keys. It cannot contain both HSL and RGB keys. It may also
209
- # optionally contain an `:alpha` key, and a `:representation` key
210
- # indicating the original representation of the color that the user wrote
211
- # in their stylesheet.
212
- #
213
- # @param attrs [{Symbol => Numeric}] A hash of color attributes to values
214
- # @raise [ArgumentError] if not enough attributes are specified,
215
- # or both RGB and HSL attributes are specified
216
- #
217
- # @overload initialize(rgba, [representation])
218
- # The attributes are specified as an array.
219
- # This overload only supports RGB or RGBA colors.
220
- #
221
- # @param rgba [Array<Numeric>] A three- or four-element array
222
- # of the red, green, blue, and optionally alpha values (respectively)
223
- # of the color
224
- # @param representation [String] The original representation of the color
225
- # that the user wrote in their stylesheet.
226
- # @raise [ArgumentError] if not enough attributes are specified
227
- def initialize(attrs, representation = nil, allow_both_rgb_and_hsl = false)
228
- super(nil)
229
-
230
- if attrs.is_a?(Array)
231
- unless (3..4).include?(attrs.size)
232
- raise ArgumentError.new("Color.new(array) expects a three- or four-element array")
233
- end
234
-
235
- red, green, blue = attrs[0...3].map {|c| c.to_i}
236
- @attrs = {:red => red, :green => green, :blue => blue}
237
- @attrs[:alpha] = attrs[3] ? attrs[3].to_f : 1
238
- @representation = representation
239
- else
240
- attrs = attrs.reject {|k, v| v.nil?}
241
- hsl = [:hue, :saturation, :lightness] & attrs.keys
242
- rgb = [:red, :green, :blue] & attrs.keys
243
- if !allow_both_rgb_and_hsl && !hsl.empty? && !rgb.empty?
244
- raise ArgumentError.new("Color.new(hash) may not have both HSL and RGB keys specified")
245
- elsif hsl.empty? && rgb.empty?
246
- raise ArgumentError.new("Color.new(hash) must have either HSL or RGB keys specified")
247
- elsif !hsl.empty? && hsl.size != 3
248
- raise ArgumentError.new("Color.new(hash) must have all three HSL values specified")
249
- elsif !rgb.empty? && rgb.size != 3
250
- raise ArgumentError.new("Color.new(hash) must have all three RGB values specified")
251
- end
252
-
253
- @attrs = attrs
254
- @attrs[:hue] %= 360 if @attrs[:hue]
255
- @attrs[:alpha] ||= 1
256
- @representation = @attrs.delete(:representation)
257
- end
258
-
259
- [:red, :green, :blue].each do |k|
260
- next if @attrs[k].nil?
261
- @attrs[k] = Sass::Util.restrict(@attrs[k].to_i, 0..255)
262
- end
263
-
264
- [:saturation, :lightness].each do |k|
265
- next if @attrs[k].nil?
266
- @attrs[k] = Sass::Util.restrict(@attrs[k], 0..100)
267
- end
268
-
269
- @attrs[:alpha] = Sass::Util.restrict(@attrs[:alpha], 0..1)
270
- end
271
-
272
- # Create a new color from a valid CSS hex string.
273
- #
274
- # The leading hash is optional.
275
- #
276
- # @return [Color]
277
- def self.from_hex(hex_string, alpha = nil)
278
- unless hex_string =~ /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i ||
279
- hex_string =~ /^#?([0-9a-f])([0-9a-f])([0-9a-f])$/i
280
- raise ArgumentError.new("#{hex_string.inspect} is not a valid hex color.")
281
- end
282
- red = $1.ljust(2, $1).to_i(16)
283
- green = $2.ljust(2, $2).to_i(16)
284
- blue = $3.ljust(2, $3).to_i(16)
285
-
286
- hex_string = '##{hex_string}' unless hex_string[0] == ?#
287
- attrs = {:red => red, :green => green, :blue => blue, :representation => hex_string}
288
- attrs[:alpha] = alpha if alpha
289
- new(attrs)
290
- end
291
-
292
- # The red component of the color.
293
- #
294
- # @return [Fixnum]
295
- def red
296
- hsl_to_rgb!
297
- @attrs[:red]
298
- end
299
-
300
- # The green component of the color.
301
- #
302
- # @return [Fixnum]
303
- def green
304
- hsl_to_rgb!
305
- @attrs[:green]
306
- end
307
-
308
- # The blue component of the color.
309
- #
310
- # @return [Fixnum]
311
- def blue
312
- hsl_to_rgb!
313
- @attrs[:blue]
314
- end
315
-
316
- # The hue component of the color.
317
- #
318
- # @return [Numeric]
319
- def hue
320
- rgb_to_hsl!
321
- @attrs[:hue]
322
- end
323
-
324
- # The saturation component of the color.
325
- #
326
- # @return [Numeric]
327
- def saturation
328
- rgb_to_hsl!
329
- @attrs[:saturation]
330
- end
331
-
332
- # The lightness component of the color.
333
- #
334
- # @return [Numeric]
335
- def lightness
336
- rgb_to_hsl!
337
- @attrs[:lightness]
338
- end
339
-
340
- # The alpha channel (opacity) of the color.
341
- # This is 1 unless otherwise defined.
342
- #
343
- # @return [Fixnum]
344
- def alpha
345
- @attrs[:alpha].to_f
346
- end
347
-
348
- # Returns whether this color object is translucent;
349
- # that is, whether the alpha channel is non-1.
350
- #
351
- # @return [Boolean]
352
- def alpha?
353
- alpha < 1
354
- end
355
-
356
- # Returns the red, green, and blue components of the color.
357
- #
358
- # @return [Array<Fixnum>] A frozen three-element array of the red, green, and blue
359
- # values (respectively) of the color
360
- def rgb
361
- [red, green, blue].freeze
362
- end
363
-
364
- # Returns the red, green, blue, and alpha components of the color.
365
- #
366
- # @return [Array<Fixnum>] A frozen four-element array of the red, green,
367
- # blue, and alpha values (respectively) of the color
368
- def rgba
369
- [red, green, blue, alpha].freeze
370
- end
371
-
372
- # Returns the hue, saturation, and lightness components of the color.
373
- #
374
- # @return [Array<Fixnum>] A frozen three-element array of the
375
- # hue, saturation, and lightness values (respectively) of the color
376
- def hsl
377
- [hue, saturation, lightness].freeze
378
- end
379
-
380
- # Returns the hue, saturation, lightness, and alpha components of the color.
381
- #
382
- # @return [Array<Fixnum>] A frozen four-element array of the hue,
383
- # saturation, lightness, and alpha values (respectively) of the color
384
- def hsla
385
- [hue, saturation, lightness].freeze
386
- end
387
-
388
- # The SassScript `==` operation.
389
- # **Note that this returns a {Sass::Script::Value::Bool} object,
390
- # not a Ruby boolean**.
391
- #
392
- # @param other [Value] The right-hand side of the operator
393
- # @return [Bool] True if this value is the same as the other,
394
- # false otherwise
395
- def eq(other)
396
- Sass::Script::Value::Bool.new(
397
- other.is_a?(Color) && rgb == other.rgb && alpha == other.alpha)
398
- end
399
-
400
- def hash
401
- [rgb, alpha].hash
402
- end
403
-
404
- # Returns a copy of this color with one or more channels changed.
405
- # RGB or HSL colors may be changed, but not both at once.
406
- #
407
- # For example:
408
- #
409
- # Color.new([10, 20, 30]).with(:blue => 40)
410
- # #=> rgb(10, 40, 30)
411
- # Color.new([126, 126, 126]).with(:red => 0, :green => 255)
412
- # #=> rgb(0, 255, 126)
413
- # Color.new([255, 0, 127]).with(:saturation => 60)
414
- # #=> rgb(204, 51, 127)
415
- # Color.new([1, 2, 3]).with(:alpha => 0.4)
416
- # #=> rgba(1, 2, 3, 0.4)
417
- #
418
- # @param attrs [{Symbol => Numeric}]
419
- # A map of channel names (`:red`, `:green`, `:blue`,
420
- # `:hue`, `:saturation`, `:lightness`, or `:alpha`) to values
421
- # @return [Color] The new Color object
422
- # @raise [ArgumentError] if both RGB and HSL keys are specified
423
- def with(attrs)
424
- attrs = attrs.reject {|k, v| v.nil?}
425
- hsl = !([:hue, :saturation, :lightness] & attrs.keys).empty?
426
- rgb = !([:red, :green, :blue] & attrs.keys).empty?
427
- if hsl && rgb
428
- raise ArgumentError.new("Cannot specify HSL and RGB values for a color at the same time")
429
- end
430
-
431
- if hsl
432
- [:hue, :saturation, :lightness].each {|k| attrs[k] ||= send(k)}
433
- elsif rgb
434
- [:red, :green, :blue].each {|k| attrs[k] ||= send(k)}
435
- else
436
- # If we're just changing the alpha channel,
437
- # keep all the HSL/RGB stuff we've calculated
438
- attrs = @attrs.merge(attrs)
439
- end
440
- attrs[:alpha] ||= alpha
441
-
442
- Color.new(attrs, nil, :allow_both_rgb_and_hsl)
443
- end
444
-
445
- # The SassScript `+` operation.
446
- # Its functionality depends on the type of its argument:
447
- #
448
- # {Number}
449
- # : Adds the number to each of the RGB color channels.
450
- #
451
- # {Color}
452
- # : Adds each of the RGB color channels together.
453
- #
454
- # {Value}
455
- # : See {Value::Base#plus}.
456
- #
457
- # @param other [Value] The right-hand side of the operator
458
- # @return [Color] The resulting color
459
- # @raise [Sass::SyntaxError] if `other` is a number with units
460
- def plus(other)
461
- if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color)
462
- piecewise(other, :+)
463
- else
464
- super
465
- end
466
- end
467
-
468
- # The SassScript `-` operation.
469
- # Its functionality depends on the type of its argument:
470
- #
471
- # {Number}
472
- # : Subtracts the number from each of the RGB color channels.
473
- #
474
- # {Color}
475
- # : Subtracts each of the other color's RGB color channels from this color's.
476
- #
477
- # {Value}
478
- # : See {Value::Base#minus}.
479
- #
480
- # @param other [Value] The right-hand side of the operator
481
- # @return [Color] The resulting color
482
- # @raise [Sass::SyntaxError] if `other` is a number with units
483
- def minus(other)
484
- if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color)
485
- piecewise(other, :-)
486
- else
487
- super
488
- end
489
- end
490
-
491
- # The SassScript `*` operation.
492
- # Its functionality depends on the type of its argument:
493
- #
494
- # {Number}
495
- # : Multiplies the number by each of the RGB color channels.
496
- #
497
- # {Color}
498
- # : Multiplies each of the RGB color channels together.
499
- #
500
- # @param other [Number, Color] The right-hand side of the operator
501
- # @return [Color] The resulting color
502
- # @raise [Sass::SyntaxError] if `other` is a number with units
503
- def times(other)
504
- if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color)
505
- piecewise(other, :*)
506
- else
507
- raise NoMethodError.new(nil, :times)
508
- end
509
- end
510
-
511
- # The SassScript `/` operation.
512
- # Its functionality depends on the type of its argument:
513
- #
514
- # {Number}
515
- # : Divides each of the RGB color channels by the number.
516
- #
517
- # {Color}
518
- # : Divides each of this color's RGB color channels by the other color's.
519
- #
520
- # {Value}
521
- # : See {Value::Base#div}.
522
- #
523
- # @param other [Value] The right-hand side of the operator
524
- # @return [Color] The resulting color
525
- # @raise [Sass::SyntaxError] if `other` is a number with units
526
- def div(other)
527
- if other.is_a?(Sass::Script::Value::Number) ||
528
- other.is_a?(Sass::Script::Value::Color)
529
- piecewise(other, :/)
530
- else
531
- super
532
- end
533
- end
534
-
535
- # The SassScript `%` operation.
536
- # Its functionality depends on the type of its argument:
537
- #
538
- # {Number}
539
- # : Takes each of the RGB color channels module the number.
540
- #
541
- # {Color}
542
- # : Takes each of this color's RGB color channels modulo the other color's.
543
- #
544
- # @param other [Number, Color] The right-hand side of the operator
545
- # @return [Color] The resulting color
546
- # @raise [Sass::SyntaxError] if `other` is a number with units
547
- def mod(other)
548
- if other.is_a?(Sass::Script::Value::Number) ||
549
- other.is_a?(Sass::Script::Value::Color)
550
- piecewise(other, :%)
551
- else
552
- raise NoMethodError.new(nil, :mod)
553
- end
554
- end
555
-
556
- # Returns a string representation of the color.
557
- # This is usually the color's hex value,
558
- # but if the color has a name that's used instead.
559
- #
560
- # @return [String] The string representation
561
- def to_s(opts = {})
562
- return smallest if options[:style] == :compressed
563
- return representation if representation
564
- return name if name
565
- alpha? ? rgba_str : hex_str
566
- end
567
- alias_method :to_sass, :to_s
568
-
569
- # Returns a string representation of the color.
570
- #
571
- # @return [String] The hex value
572
- def inspect
573
- alpha? ? rgba_str : hex_str
574
- end
575
-
576
- # Returns the color's name, if it has one.
577
- #
578
- # @return [String, nil]
579
- def name
580
- COLOR_NAMES_REVERSE[rgba]
581
- end
582
-
583
- private
584
-
585
- def smallest
586
- small_explicit_str = alpha? ? rgba_str : hex_str.gsub(/^#(.)\1(.)\2(.)\3$/, '#\1\2\3')
587
- [representation, COLOR_NAMES_REVERSE[rgba], small_explicit_str].
588
- compact.min_by {|str| str.size}
589
- end
590
-
591
- def rgba_str
592
- split = options[:style] == :compressed ? ',' : ', '
593
- "rgba(#{rgb.join(split)}#{split}#{Number.round(alpha)})"
594
- end
595
-
596
- def hex_str
597
- red, green, blue = rgb.map {|num| num.to_s(16).rjust(2, '0')}
598
- "##{red}#{green}#{blue}"
599
- end
600
-
601
- def piecewise(other, operation)
602
- other_num = other.is_a? Number
603
- if other_num && !other.unitless?
604
- raise Sass::SyntaxError.new(
605
- "Cannot add a number with units (#{other}) to a color (#{self}).")
606
- end
607
-
608
- result = []
609
- (0...3).each do |i|
610
- res = rgb[i].send(operation, other_num ? other.value : other.rgb[i])
611
- result[i] = [[res, 255].min, 0].max
612
- end
613
-
614
- if !other_num && other.alpha != alpha
615
- raise Sass::SyntaxError.new("Alpha channels must be equal: #{self} #{operation} #{other}")
616
- end
617
-
618
- with(:red => result[0], :green => result[1], :blue => result[2])
619
- end
620
-
621
- def hsl_to_rgb!
622
- return if @attrs[:red] && @attrs[:blue] && @attrs[:green]
623
-
624
- h = @attrs[:hue] / 360.0
625
- s = @attrs[:saturation] / 100.0
626
- l = @attrs[:lightness] / 100.0
627
-
628
- # Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
629
- m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s
630
- m1 = l * 2 - m2
631
- @attrs[:red], @attrs[:green], @attrs[:blue] = [
632
- hue_to_rgb(m1, m2, h + 1.0 / 3),
633
- hue_to_rgb(m1, m2, h),
634
- hue_to_rgb(m1, m2, h - 1.0 / 3)
635
- ].map {|c| (c * 0xff).round}
636
- end
637
-
638
- def hue_to_rgb(m1, m2, h)
639
- h += 1 if h < 0
640
- h -= 1 if h > 1
641
- return m1 + (m2 - m1) * h * 6 if h * 6 < 1
642
- return m2 if h * 2 < 1
643
- return m1 + (m2 - m1) * (2.0 / 3 - h) * 6 if h * 3 < 2
644
- m1
645
- end
646
-
647
- def rgb_to_hsl!
648
- return if @attrs[:hue] && @attrs[:saturation] && @attrs[:lightness]
649
- r, g, b = [:red, :green, :blue].map {|k| @attrs[k] / 255.0}
650
-
651
- # Algorithm from http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
652
- max = [r, g, b].max
653
- min = [r, g, b].min
654
- d = max - min
655
-
656
- h =
657
- case max
658
- when min; 0
659
- when r; 60 * (g - b) / d
660
- when g; 60 * (b - r) / d + 120
661
- when b; 60 * (r - g) / d + 240
662
- end
663
-
664
- l = (max + min) / 2.0
665
-
666
- s =
667
- if max == min
668
- 0
669
- elsif l < 0.5
670
- d / (2 * l)
671
- else
672
- d / (2 - 2 * l)
673
- end
674
-
675
- @attrs[:hue] = h % 360
676
- @attrs[:saturation] = s * 100
677
- @attrs[:lightness] = l * 100
678
- end
679
- end
680
- end