module Sass::Script::Functions

def abs(value)

Raises:
  • (Sass::SyntaxError) - if `value` isn't a number

Returns:
  • (Number) - The absolute value

Parameters:
  • value (Number) -- The number
def abs(value)
  numeric_transformation(value) {|n| n.abs}
end

def adjust(color, amount, attr, range, op, units = "")

def adjust(color, amount, attr, range, op, units = "")
  assert_type color, :Color
  assert_type amount, :Number
  unless range.include?(amount.value)
    raise ArgumentError.new("Amount #{amount} must be between #{range.first}#{units} and #{range.last}#{units}")
  end
  # TODO: is it worth restricting here,
  # or should we do so in the Color constructor itself,
  # and allow clipping in rgb() et al?
  color.with(attr => Haml::Util.restrict(
      color.send(attr).send(op, amount.value), range))
end

def adjust_hue(color, degrees)

Raises:
  • (ArgumentError) - If `color` isn't a color, or `number` isn't a number

Returns:
  • (Color) -

Parameters:
  • amount (Number) --
  • color (Color) --
def adjust_hue(color, degrees)
  assert_type color, :Color
  assert_type degrees, :Number
  color.with(:hue => color.hue + degrees.value)
end

def alpha(*args)

Raises:
  • (ArgumentError) - If `color` isn't a color

Other tags:
    See: #transparentize -
    See: #opacify -

Returns:
  • (Number) -

Parameters:
  • color (Color) --

Overloads:
  • def alpha(color)
def alpha(*args)
  if args.all? do |a|
      a.is_a?(Sass::Script::String) && a.type == :identifier &&
        a.value =~ /^[a-zA-Z]+\s*=/
    end
    # Support the proprietary MS alpha() function
    return Sass::Script::String.new("alpha(#{args.map {|a| a.to_s}.join(", ")})")
  end
  opacity(*args)
end

def blue(color)

Raises:
  • (ArgumentError) - If `color` isn't a color

Returns:
  • (Number) -

Parameters:
  • color (Color) --
def blue(color)
  assert_type color, :Color
  Sass::Script::Number.new(color.blue)
end

def ceil(value)

Raises:
  • (Sass::SyntaxError) - if `value` isn't a number

Returns:
  • (Number) - The rounded number

Parameters:
  • value (Number) -- The number
def ceil(value)
  numeric_transformation(value) {|n| n.ceil}
end

def comparable(number1, number2)

Raises:
  • (ArgumentError) - if `number1` or `number2` aren't numbers

Returns:
  • (Bool) - indicating if the numbers can be compared.

Parameters:
  • number2 (Number) --
  • number1 (Number) --
def comparable(number1, number2)
  assert_type number1, :Number
  assert_type number2, :Number
  Sass::Script::Bool.new(number1.comparable_to?(number2))
end

def complement(color)

Other tags:
    See: #adjust_hue - #adjust-hue

Raises:
  • (ArgumentError) - if `color` isn't a color

Returns:
  • (Color) -

Parameters:
  • color (Color) --
def complement(color)
  adjust_hue color, Number.new(180)
end

def darken(color, amount)

Raises:
  • (ArgumentError) - If `color` isn't a color,

Other tags:
    See: #lighten -

Returns:
  • (Color) -

Parameters:
  • amount (Number) --
  • color (Color) --
def darken(color, amount)
  adjust(color, amount, :lightness, 0..100, :-, "%")
end

def desaturate(color, amount)

Raises:
  • (ArgumentError) - If `color` isn't a color,

Other tags:
    See: #saturate -

Returns:
  • (Color) -

Parameters:
  • amount (Number) --
  • color (Color) --
def desaturate(color, amount)
  adjust(color, amount, :saturation, 0..100, :-, "%")
end

def floor(value)

Raises:
  • (Sass::SyntaxError) - if `value` isn't a number

Returns:
  • (Number) - The rounded number

Parameters:
  • value (Number) -- The number
def floor(value)
  numeric_transformation(value) {|n| n.floor}
end

def grayscale(color)

Other tags:
    See: #desaturate -

Raises:
  • (ArgumentError) - if `color` isn't a color

Returns:
  • (Color) -

Parameters:
  • color (Color) --
def grayscale(color)
  desaturate color, Number.new(100)
end

def green(color)

Raises:
  • (ArgumentError) - If `color` isn't a color

Returns:
  • (Number) -

Parameters:
  • color (Color) --
def green(color)
  assert_type color, :Color
  Sass::Script::Number.new(color.green)
end

def hsl(hue, saturation, lightness)

Raises:
  • (ArgumentError) - if `saturation` or `lightness` are out of bounds

Other tags:
    See: #hsla -

Returns:
  • (Color) - The resulting color

Parameters:
  • lightness (Number) -- The lightness of the color.
  • saturation (Number) -- The saturation of the color.
  • hue (Number) -- The hue of the color.
def hsl(hue, saturation, lightness)
  hsla(hue, saturation, lightness, Number.new(1))
end

def hsla(hue, saturation, lightness, alpha)

Raises:
  • (ArgumentError) - if `saturation`, `lightness`, or `alpha` are out of bounds

Other tags:
    See: #hsl -

Returns:
  • (Color) - The resulting color

Parameters:
  • alpha (Number) -- The opacity of the color.
  • lightness (Number) -- The lightness of the color.
  • saturation (Number) -- The saturation of the color.
  • hue (Number) -- The hue of the color.
def hsla(hue, saturation, lightness, alpha)
  assert_type hue, :Number
  assert_type saturation, :Number
  assert_type lightness, :Number
  assert_type alpha, :Number
  unless (0..1).include?(alpha.value)
    raise ArgumentError.new("Alpha channel #{alpha.value} must be between 0 and 1")
  end
  original_s = saturation
  original_l = lightness
  # This algorithm is from http://www.w3.org/TR/css3-color#hsl-color
  h, s, l = [hue, saturation, lightness].map { |a| a.value }
  raise ArgumentError.new("Saturation #{s} must be between 0% and 100%") unless (0..100).include?(s)
  raise ArgumentError.new("Lightness #{l} must be between 0% and 100%") unless (0..100).include?(l)
  Color.new(:hue => h, :saturation => s, :lightness => l, :alpha => alpha.value)
end

def hue(color)

Raises:
  • (ArgumentError) - if `color` isn't a color

Other tags:
    See: #adjust_hue -

Returns:
  • (Number) - between 0deg and 360deg

Parameters:
  • color (Color) --
def hue(color)
  assert_type color, :Color
  Sass::Script::Number.new(color.hue, ["deg"])
end

def lighten(color, amount)

Raises:
  • (ArgumentError) - If `color` isn't a color,

Other tags:
    See: #darken -

Returns:
  • (Color) -

Parameters:
  • amount (Number) --
  • color (Color) --
def lighten(color, amount)
  adjust(color, amount, :lightness, 0..100, :+, "%")
end

def lightness(color)

Raises:
  • (ArgumentError) - if `color` isn't a color

Other tags:
    See: #darken -
    See: #lighten -

Returns:
  • (Number) - between 0% and 100%

Parameters:
  • color (Color) --
def lightness(color)
  assert_type color, :Color
  Sass::Script::Number.new(color.lightness, ["%"])
end

def mix(color1, color2, weight = Number.new(50))

Raises:
  • (ArgumentError) - if `color1` or `color2` aren't colors,

Returns:
  • (Color) -

Parameters:
  • weight (Number) -- between 0% and 100%
  • color2 (Color) --
  • color1 (Color) --

Overloads:
  • mix(color1, color2, weight = 50%)
def mix(color1, color2, weight = Number.new(50))
  assert_type color1, :Color
  assert_type color2, :Color
  assert_type weight, :Number
  unless (0..100).include?(weight.value)
    raise ArgumentError.new("Weight #{weight} must be between 0% and 100%")
  end
  # This algorithm factors in both the user-provided weight
  # and the difference between the alpha values of the two colors
  # to decide how to perform the weighted average of the two RGB values.
  #
  # It works by first normalizing both parameters to be within [-1, 1],
  # where 1 indicates "only use color1", -1 indicates "only use color 0",
  # and all values in between indicated a proportionately weighted average.
  #
  # Once we have the normalized variables w and a,
  # we apply the formula (w + a)/(1 + w*a)
  # to get the combined weight (in [-1, 1]) of color1.
  # This formula has two especially nice properties:
  #
  #   * When either w or a are -1 or 1, the combined weight is also that number
  #     (cases where w * a == -1 are undefined, and handled as a special case).
  #
  #   * When a is 0, the combined weight is w, and vice versa
  #
  # Finally, the weight of color1 is renormalized to be within [0, 1]
  # and the weight of color2 is given by 1 minus the weight of color1.
  p = weight.value/100.0
  w = p*2 - 1
  a = color1.alpha - color2.alpha
  w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0
  w2 = 1 - w1
  rgb = color1.rgb.zip(color2.rgb).map {|v1, v2| v1*w1 + v2*w2}
  alpha = color1.alpha*p + color2.alpha*(1-p)
  Color.new(rgb + [alpha])
end

def numeric_transformation(value)

It yields a number to a block to perform the operation and return a number
another numeric value with the same units.
This method implements the pattern of transforming a numeric value into
def numeric_transformation(value)
  assert_type value, :Number
  Sass::Script::Number.new(yield(value.value), value.numerator_units, value.denominator_units)
end

def opacify(color, amount)

Raises:
  • (ArgumentError) - If `color` isn't a color,

Other tags:
    See: #transparentize -

Returns:
  • (Color) -

Parameters:
  • amount (Number) --
  • color (Color) --
def opacify(color, amount)
  adjust(color, amount, :alpha, 0..1, :+)
end

def opacity(color)

Raises:
  • (ArgumentError) - If `color` isn't a color

Other tags:
    See: #transparentize -
    See: #opacify -

Returns:
  • (Number) -

Parameters:
  • color (Color) --
def opacity(color)
  assert_type color, :Color
  Sass::Script::Number.new(color.alpha)
end

def percentage(value)

Raises:
  • (ArgumentError) - If `value` isn't a unitless number

Returns:
  • (Number) - The percentage

Parameters:
  • value (Number) -- The decimal number to convert to a percentage
def percentage(value)
  unless value.is_a?(Sass::Script::Number) && value.unitless?
    raise ArgumentError.new("#{value.inspect} is not a unitless number")
  end
  Sass::Script::Number.new(value.value * 100, ['%'])
end

def quote(str)

Other tags:
    See: #unquote -

Raises:
  • (ArgumentError) - if `str` isn't a string

Returns:
  • (String) -

Parameters:
  • str (String) --
def quote(str)
  assert_type str, :String
  Sass::Script::String.new(str.value, :string)
end

def red(color)

Raises:
  • (ArgumentError) - If `color` isn't a color

Returns:
  • (Number) -

Parameters:
  • color (Color) --
def red(color)
  assert_type color, :Color
  Sass::Script::Number.new(color.red)
end

def rgb(red, green, blue)

Returns:
  • (Color) -

Other tags:
    See: #rgba -

Parameters:
  • blue (Number) --
  • green (Number) --
  • red (Number) --
def rgb(red, green, blue)
  assert_type red, :Number
  assert_type green, :Number
  assert_type blue, :Number
  Color.new([red, green, blue].map do |c|
      v = c.value
      if c.numerator_units == ["%"] && c.denominator_units.empty?
        next v * 255 / 100.0 if (0..100).include?(v)
        raise ArgumentError.new("Color value #{c} must be between 0% and 100% inclusive")
      else
        next v if (0..255).include?(v)
        raise ArgumentError.new("Color value #{v} must be between 0 and 255 inclusive")
      end
    end)
end

def rgba(*args)

Returns:
  • (Color) -
  • (Color) -

Parameters:
  • alpha (Number) --
  • color (Color) --
  • alpha (Number) --
  • blue (Number) --
  • green (Number) --
  • red (Number) --

Overloads:
  • rgba(color, alpha)
  • rgba(red, green, blue, alpha)

Other tags:
    See: #rgb -
def rgba(*args)
  case args.size
  when 2
    color, alpha = args
    assert_type color, :Color
    assert_type alpha, :Number
    unless (0..1).include?(alpha.value)
      raise ArgumentError.new("Alpha channel #{alpha.value} must be between 0 and 1 inclusive")
    end
    color.with(:alpha => alpha.value)
  when 4
    red, green, blue, alpha = args
    rgba(rgb(red, green, blue), alpha)
  else
    raise ArgumentError.new("wrong number of arguments (#{args.size} for 4)")
  end
end

def round(value)

Raises:
  • (Sass::SyntaxError) - if `value` isn't a number

Returns:
  • (Number) - The rounded number

Parameters:
  • value (Number) -- The number
def round(value)
  numeric_transformation(value) {|n| n.round}
end

def saturate(color, amount)

Raises:
  • (ArgumentError) - If `color` isn't a color,

Other tags:
    See: #desaturate -

Returns:
  • (Color) -

Parameters:
  • amount (Number) --
  • color (Color) --
def saturate(color, amount)
  adjust(color, amount, :saturation, 0..100, :+, "%")
end

def saturation(color)

Raises:
  • (ArgumentError) - if `color` isn't a color

Other tags:
    See: #desaturate -
    See: #saturate -

Returns:
  • (Number) - between 0% and 100%

Parameters:
  • color (Color) --
def saturation(color)
  assert_type color, :Color
  Sass::Script::Number.new(color.saturation, ["%"])
end

def transparentize(color, amount)

Raises:
  • (ArgumentError) - If `color` isn't a color,

Other tags:
    See: #opacify -

Returns:
  • (Color) -

Parameters:
  • amount (Number) --
  • color (Color) --
def transparentize(color, amount)
  adjust(color, amount, :alpha, 0..1, :-)
end

def type_of(obj)

Returns:
  • (String) - The unquoted string name of the literal's type

Parameters:
  • obj (Literal) -- The object to inspect
def type_of(obj)
  Sass::Script::String.new(obj.class.name.gsub(/Sass::Script::/,'').downcase)
end

def unit(number)

Raises:
  • (ArgumentError) - if `number` isn't a number

Returns:
  • (String) - The unit(s) of the number

Parameters:
  • number (Literal) -- The number to inspect
def unit(number)
  assert_type number, :Number
  Sass::Script::String.new(number.unit_str, :string)
end

def unitless(number)

Raises:
  • (ArgumentError) - if `number` isn't a number

Returns:
  • (Bool) - Whether or not the number is unitless

Parameters:
  • number (Literal) -- The number to inspect
def unitless(number)
  assert_type number, :Number
  Sass::Script::Bool.new(number.unitless?)
end

def unquote(str)

Other tags:
    See: #quote -

Raises:
  • (ArgumentError) - if `str` isn't a string

Returns:
  • (String) -

Parameters:
  • str (String) --
def unquote(str)
  assert_type str, :String
  Sass::Script::String.new(str.value, :identifier)
end