Class: Sass::Script::Color

Inherits:
Literal show all
Extended by:
Util
Defined in:
lib/sass/script/color.rb

Overview

A SassScript object representing a CSS color.

A color may be represented internally as RGBA, HSLA, or both. It's originally represented as whatever its input is; if it's created with RGB values, it's represented as RGBA, and if it's created with HSL values, it's represented as HSLA. Once a property is accessed that requires the other representation -- for example, #red for an HSL color -- that component is calculated and cached.

The alpha channel of a color is independent of its RGB or HSL representation. It's always stored, as 1 if nothing else is specified. If only the alpha channel is modified using #with, the cached RGB and HSL values are retained.

Constant Summary collapse

HTML4_COLORS =

A hash from color names to [red, green, blue] value arrays.

map_vals({
  'black'   => 0x000000,
  'silver'  => 0xc0c0c0,
  'gray'    => 0x808080,
  'white'   => 0xffffff,
  'maroon'  => 0x800000,
  'red'     => 0xff0000,
  'purple'  => 0x800080,
  'fuchsia' => 0xff00ff,
  'green'   => 0x008000,
  'lime'    => 0x00ff00,
  'olive'   => 0x808000,
  'yellow'  => 0xffff00,
  'navy'    => 0x000080,
  'blue'    => 0x0000ff,
  'teal'    => 0x008080,
  'aqua'    => 0x00ffff
}) {|color| (0..2).map {|n| color >> (n << 3) & 0xff}.reverse}
HTML4_COLORS_REVERSE =

A hash from [red, green, blue] value arrays to color names.

map_hash(HTML4_COLORS) {|k, v| [v, k]}

Constants included from Util

Util::CHARSET_REGEXPS, Util::ENCODINGS_TO_CHECK, Util::RUBY_ENGINE, Util::RUBY_VERSION

Instance Attribute Summary

Attributes inherited from Literal

#value

Attributes inherited from Node

#line, #options

Instance Method Summary collapse

Methods included from Util

abstract, ap_geq?, ap_geq_3?, av_template_class, caller_info, check_encoding, check_sass_encoding, enum_cons, enum_slice, enum_with_index, extract_values, flatten, has?, inject_values, inspect_obj, intersperse, ironruby?, lcs, map_hash, map_keys, map_vals, merge_adjacent_strings, ord, paths, powerset, rails_env, rails_root, restrict, ruby1_8?, ruby1_8_6?, sass_warn, scope, set_eql?, set_hash, silence_sass_warnings, silence_warnings, strip_string_array, substitute, to_hash, version_geq, version_gt, windows?, with_extracted_values

Methods inherited from Literal

#==, #_perform, #and, #assert_int!, #children, #comma, #deep_copy, #neq, #options, #or, #single_eq, #space, #to_a, #to_bool, #to_i, #unary_div, #unary_minus, #unary_not, #unary_plus

Methods inherited from Node

#_perform, #children, #dasherize, #deep_copy, #opts, #perform

Constructor Details

#initialize(attrs) ⇒ Color #initialize(rgba) ⇒ Color

Constructs an RGB or HSL color object, optionally with an alpha channel.

The RGB values must be between 0 and 255. The saturation and lightness values must be between 0 and 100. The alpha value must be between 0 and 1.

Overloads:

  • #initialize(attrs) ⇒ Color

    The attributes are specified as a hash. This hash must contain either :hue, :saturation, and :value keys, or :red, :green, and :blue keys. It cannot contain both HSL and RGB keys. It may also optionally contain an :alpha key.

    Parameters:

    • attrs ({Symbol => Numeric})

      A hash of color attributes to values

    Raises:

    • (ArgumentError)

      if not enough attributes are specified, or both RGB and HSL attributes are specified

  • #initialize(rgba) ⇒ Color

    The attributes are specified as an array. This overload only supports RGB or RGBA colors.

    Parameters:

    • rgba (Array<Numeric>)

      A three- or four-element array of the red, green, blue, and optionally alpha values (respectively) of the color

    Raises:

    • (ArgumentError)

      if not enough attributes are specified

Raises:



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/sass/script/color.rb', line 71

def initialize(attrs, allow_both_rgb_and_hsl = false)
  super(nil)

  if attrs.is_a?(Array)
    unless (3..4).include?(attrs.size)
      raise ArgumentError.new("Color.new(array) expects a three- or four-element array")
    end

    red, green, blue = attrs[0...3].map {|c| c.to_i}
    @attrs = {:red => red, :green => green, :blue => blue}
    @attrs[:alpha] = attrs[3] ? attrs[3].to_f : 1
  else
    attrs = attrs.reject {|k, v| v.nil?}
    hsl = [:hue, :saturation, :lightness] & attrs.keys
    rgb = [:red, :green, :blue] & attrs.keys
    if !allow_both_rgb_and_hsl && !hsl.empty? && !rgb.empty?
      raise ArgumentError.new("Color.new(hash) may not have both HSL and RGB keys specified")
    elsif hsl.empty? && rgb.empty?
      raise ArgumentError.new("Color.new(hash) must have either HSL or RGB keys specified")
    elsif !hsl.empty? && hsl.size != 3
      raise ArgumentError.new("Color.new(hash) must have all three HSL values specified")
    elsif !rgb.empty? && rgb.size != 3
      raise ArgumentError.new("Color.new(hash) must have all three RGB values specified")
    end

    @attrs = attrs
    @attrs[:hue] %= 360 if @attrs[:hue]
    @attrs[:alpha] ||= 1
  end

  [:red, :green, :blue].each do |k|
    next if @attrs[k].nil?
    @attrs[k] = @attrs[k].to_i
    next if (0..255).include?(@attrs[k])
    raise ArgumentError.new("#{k.to_s.capitalize} value must be between 0 and 255")
  end

  [:saturation, :lightness].each do |k|
    next if @attrs[k].nil?
    @attrs[k] = 0 if @attrs[k] < 0.00001 && @attrs[k] > -0.00001
    @attrs[k] = 100 if @attrs[k] - 100 < 0.00001 && @attrs[k] - 100 > -0.00001
    next if (0..100).include?(@attrs[k])
    raise ArgumentError.new("#{k.to_s.capitalize} must be between 0 and 100")
  end

  unless (0..1).include?(@attrs[:alpha])
    raise ArgumentError.new("Alpha channel must be between 0 and 1")
  end
end

Instance Method Details

#alphaFixnum

The alpha channel (opacity) of the color. This is 1 unless otherwise defined.

Returns:

  • (Fixnum)


173
174
175
# File 'lib/sass/script/color.rb', line 173

def alpha
  @attrs[:alpha]
end

#alpha?Boolean

Returns whether this color object is translucent; that is, whether the alpha channel is non-1.

Returns:

  • (Boolean)


181
182
183
# File 'lib/sass/script/color.rb', line 181

def alpha?
  alpha < 1
end

#blueFixnum

The blue component of the color.

Returns:

  • (Fixnum)


140
141
142
143
# File 'lib/sass/script/color.rb', line 140

def blue
  hsl_to_rgb!
  @attrs[:blue]
end

#div(other) ⇒ Color

The SassScript / operation. Its functionality depends on the type of its argument:

Number : Divides each of the RGB color channels by the number.

Sass::Script::Color : Divides each of this color's RGB color channels by the other color's.

Literal : See Literal#div.

Parameters:

  • other (Literal)

    The right-hand side of the operator

Returns:

  • (Color)

    The resulting color

Raises:



335
336
337
338
339
340
341
# File 'lib/sass/script/color.rb', line 335

def div(other)
  if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
    piecewise(other, :/)
  else
    super
  end
end

#eq(other) ⇒ Bool

The SassScript == operation. Note that this returns a Bool object, not a Ruby boolean.

Parameters:

  • other (Literal)

    The right-hand side of the operator

Returns:

  • (Bool)

    True if this literal is the same as the other, false otherwise



208
209
210
211
# File 'lib/sass/script/color.rb', line 208

def eq(other)
  Sass::Script::Bool.new(
    other.is_a?(Color) && rgb == other.rgb && alpha == other.alpha)
end

#greenFixnum

The green component of the color.

Returns:

  • (Fixnum)


132
133
134
135
# File 'lib/sass/script/color.rb', line 132

def green
  hsl_to_rgb!
  @attrs[:green]
end

#hslArray<Fixnum>

Returns the hue, saturation, and lightness components of the color.

Returns:

  • (Array<Fixnum>)

    A frozen three-element array of the hue, saturation, and lightness values (respectively) of the color



197
198
199
# File 'lib/sass/script/color.rb', line 197

def hsl
  [hue, saturation, lightness].freeze
end

#hueNumeric

The hue component of the color.

Returns:

  • (Numeric)


148
149
150
151
# File 'lib/sass/script/color.rb', line 148

def hue
  rgb_to_hsl!
  @attrs[:hue]
end

#inspectString

Returns a string representation of the color.

Returns:



379
380
381
# File 'lib/sass/script/color.rb', line 379

def inspect
  alpha? ? rgba_str : hex_str
end

#lightnessNumeric

The lightness component of the color.

Returns:

  • (Numeric)


164
165
166
167
# File 'lib/sass/script/color.rb', line 164

def lightness
  rgb_to_hsl!
  @attrs[:lightness]
end

#minus(other) ⇒ Color

The SassScript - operation. Its functionality depends on the type of its argument:

Number : Subtracts the number from each of the RGB color channels.

Sass::Script::Color : Subtracts each of the other color's RGB color channels from this color's.

Literal : See Literal#minus.

Parameters:

  • other (Literal)

    The right-hand side of the operator

Returns:

  • (Color)

    The resulting color

Raises:



292
293
294
295
296
297
298
# File 'lib/sass/script/color.rb', line 292

def minus(other)
  if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
    piecewise(other, :-)
  else
    super
  end
end

#mod(other) ⇒ Color

The SassScript % operation. Its functionality depends on the type of its argument:

Number : Takes each of the RGB color channels module the number.

Sass::Script::Color : Takes each of this color's RGB color channels modulo the other color's.

Parameters:

  • other (Number, Color)

    The right-hand side of the operator

Returns:

  • (Color)

    The resulting color

Raises:



355
356
357
358
359
360
361
# File 'lib/sass/script/color.rb', line 355

def mod(other)
  if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
    piecewise(other, :%)
  else
    raise NoMethodError.new(nil, :mod)
  end
end

#plus(other) ⇒ Color

The SassScript + operation. Its functionality depends on the type of its argument:

Number : Adds the number to each of the RGB color channels.

Sass::Script::Color : Adds each of the RGB color channels together.

Literal : See Literal#plus.

Parameters:

  • other (Literal)

    The right-hand side of the operator

Returns:

  • (Color)

    The resulting color

Raises:



269
270
271
272
273
274
275
# File 'lib/sass/script/color.rb', line 269

def plus(other)
  if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
    piecewise(other, :+)
  else
    super
  end
end

#redFixnum

The red component of the color.

Returns:

  • (Fixnum)


124
125
126
127
# File 'lib/sass/script/color.rb', line 124

def red
  hsl_to_rgb!
  @attrs[:red]
end

#rgbArray<Fixnum>

Returns the red, green, and blue components of the color.

Returns:

  • (Array<Fixnum>)

    A frozen three-element array of the red, green, and blue values (respectively) of the color



189
190
191
# File 'lib/sass/script/color.rb', line 189

def rgb
  [red, green, blue].freeze
end

#saturationNumeric

The saturation component of the color.

Returns:

  • (Numeric)


156
157
158
159
# File 'lib/sass/script/color.rb', line 156

def saturation
  rgb_to_hsl!
  @attrs[:saturation]
end

#times(other) ⇒ Color

The SassScript * operation. Its functionality depends on the type of its argument:

Number : Multiplies the number by each of the RGB color channels.

Sass::Script::Color : Multiplies each of the RGB color channels together.

Parameters:

  • other (Number, Color)

    The right-hand side of the operator

Returns:

  • (Color)

    The resulting color

Raises:



312
313
314
315
316
317
318
# File 'lib/sass/script/color.rb', line 312

def times(other)
  if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
    piecewise(other, :*)
  else
    raise NoMethodError.new(nil, :times)
  end
end

#to_s(opts = {}) ⇒ String Also known as: to_sass

Returns a string representation of the color. This is usually the color's hex value, but if the color has a name that's used instead.

Returns:

  • (String)

    The string representation



368
369
370
371
372
373
# File 'lib/sass/script/color.rb', line 368

def to_s(opts = {})
  return rgba_str if alpha?
  return smallest if options[:style] == :compressed
  return HTML4_COLORS_REVERSE[rgb] if HTML4_COLORS_REVERSE[rgb]
  hex_str
end

#with(attrs) ⇒ Color

Returns a copy of this color with one or more channels changed. RGB or HSL colors may be changed, but not both at once.

For example:

Color.new([10, 20, 30]).with(:blue => 40)
  #=> rgb(10, 40, 30)
Color.new([126, 126, 126]).with(:red => 0, :green => 255)
  #=> rgb(0, 255, 126)
Color.new([255, 0, 127]).with(:saturation => 60)
  #=> rgb(204, 51, 127)
Color.new([1, 2, 3]).with(:alpha => 0.4)
  #=> rgba(1, 2, 3, 0.4)

Parameters:

  • attrs ({Symbol => Numeric})

    A map of channel names (:red, :green, :blue, :hue, :saturation, :lightness, or :alpha) to values

Returns:

  • (Color)

    The new Color object

Raises:

  • (ArgumentError)

    if both RGB and HSL keys are specified



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/sass/script/color.rb', line 232

def with(attrs)
  attrs = attrs.reject {|k, v| v.nil?}
  hsl = !([:hue, :saturation, :lightness] & attrs.keys).empty?
  rgb = !([:red, :green, :blue] & attrs.keys).empty?
  if hsl && rgb
    raise ArgumentError.new("Cannot specify HSL and RGB values for a color at the same time")
  end

  if hsl
    [:hue, :saturation, :lightness].each {|k| attrs[k] ||= send(k)}
  elsif rgb
    [:red, :green, :blue].each {|k| attrs[k] ||= send(k)}
  else
    # If we're just changing the alpha channel,
    # keep all the HSL/RGB stuff we've calculated
    attrs = @attrs.merge(attrs)
  end
  attrs[:alpha] ||= alpha

  Color.new(attrs, :allow_both_rgb_and_hsl)
end