class Sass::Script::Number

These cannot be inputted directly in Sass code at the moment.
Numbers can also have more complex units, such as ‘1px*em/in`.
are all valid values.
For example, `12`, `1px`, and `10.45em`
and can also have units.
SassScript numbers can have decimal values,
A SassScript object representing a number.

def self.round(num)

Other tags:
    Private: -
def self.round(num)
  if num.is_a?(Float) && (num.infinite? || num.nan?)
    num
  elsif num % 1 == 0.0
    num.to_i
  else
    (num * PRECISION).round / PRECISION
  end
end

def coerce(num_units, den_units)

Raises:
  • (Sass::UnitConversionError) - if the given units are incompatible with the number's

Returns:
  • (Number) - The number with the new units

Parameters:
  • den_units (Array) -- The denominator units to coerce this number into.
  • num_units (Array) -- The numerator units to coerce this number into.
def coerce(num_units, den_units)
  Number.new(if unitless?
               self.value
             else
               self.value * coercion_factor(self.numerator_units, num_units) /
                 coercion_factor(self.denominator_units, den_units)
             end, num_units, den_units)
end

def coercion_factor(from_units, to_units)

def coercion_factor(from_units, to_units)
  # get a list of unmatched units
  from_units, to_units = sans_common_units(from_units, to_units)
  if from_units.size != to_units.size || !convertable?(from_units | to_units)
    raise Sass::UnitConversionError.new("Incompatible units: '#{from_units.join('*')}' and '#{to_units.join('*')}'.")
  end
  from_units.zip(to_units).inject(1) {|m,p| m * conversion_factor(p[0], p[1]) }
end

def comparable_to?(other)

Returns:
  • (Boolean) - Whether or not this number can be compared with the other.

Parameters:
  • other (Number) -- A number to decide if it can be compared with this number.
def comparable_to?(other)
  begin
    operate(other, :+)
    true
  rescue Sass::UnitConversionError
    false
  end
end

def compute_units(this, other, operation)

def compute_units(this, other, operation)
  case operation
  when :*
    [this.numerator_units + other.numerator_units, this.denominator_units + other.denominator_units]
  when :/
    [this.numerator_units + other.denominator_units, this.denominator_units + other.numerator_units]
  else  
    [this.numerator_units, this.denominator_units]
  end
end

def conversion_factor(from_unit, to_unit)

def conversion_factor(from_unit, to_unit)
  res = CONVERSION_TABLE[CONVERTABLE_UNITS[from_unit]][CONVERTABLE_UNITS[to_unit]]
  return 1.0 / conversion_factor(to_unit, from_unit) if res.nil?
  res
end

def convertable?(units)

def convertable?(units)
  Array(units).all?(&CONVERTABLE_UNITS.method(:include?))
end

def div(other)

Returns:
  • (Literal) - The result of the operation

Parameters:
  • other (Literal) -- The right-hand side of the operator
def div(other)
  if other.is_a? Number
    res = operate(other, :/)
    if self.original && other.original && context != :equals
      res.original = "#{self.original}/#{other.original}"
    end
    res
  else
    super
  end
end

def eq(other)

Returns:
  • (Boolean) - Whether this number is equal to the other object

Parameters:
  • other (Literal) -- The right-hand side of the operator
def eq(other)
  return Sass::Script::Bool.new(false) unless other.is_a?(Sass::Script::Number)
  this = self
  begin
    if unitless?
      this = this.coerce(other.numerator_units, other.denominator_units)
    else
      other = other.coerce(numerator_units, denominator_units)
    end
  rescue Sass::UnitConversionError
    return Sass::Script::Bool.new(false)
  end
  Sass::Script::Bool.new(this.value == other.value)
end

def gt(other)

Raises:
  • (NoMethodError) - if `other` is an invalid type

Returns:
  • (Boolean) - Whether this number is greater than the other

Parameters:
  • other (Number) -- The right-hand side of the operator
def gt(other)
  raise NoMethodError.new(nil, :gt) unless other.is_a?(Number)
  operate(other, :>)
end

def gte(other)

Raises:
  • (NoMethodError) - if `other` is an invalid type

Returns:
  • (Boolean) - Whether this number is greater than or equal to the other

Parameters:
  • other (Number) -- The right-hand side of the operator
def gte(other)
  raise NoMethodError.new(nil, :gte) unless other.is_a?(Number)
  operate(other, :>=)
end

def initialize(value, numerator_units = [], denominator_units = [])

Parameters:
  • denominator_units (Array) -- See \{#denominator\_units}
  • numerator_units (Array) -- See \{#numerator\_units}
  • value (Numeric) -- The value of the number
def initialize(value, numerator_units = [], denominator_units = [])
  super(value)
  @numerator_units = numerator_units
  @denominator_units = denominator_units
  normalize!
end

def inspect(opts = {})

Returns:
  • (String) - The representation
def inspect(opts = {})
  "#{self.class.round(self.value)}#{unit_str}"
end

def int?

Returns:
  • (Boolean) - Whether or not this number is an integer.
def int?
  value % 1 == 0.0
end

def legal_units?

Returns:
  • (Boolean) - Whether or not this number has units that can be represented in CSS
def legal_units?
  (numerator_units.empty? || numerator_units.size == 1) && denominator_units.empty?
end

def lt(other)

Raises:
  • (NoMethodError) - if `other` is an invalid type

Returns:
  • (Boolean) - Whether this number is less than the other

Parameters:
  • other (Number) -- The right-hand side of the operator
def lt(other)
  raise NoMethodError.new(nil, :lt) unless other.is_a?(Number)
  operate(other, :<)
end

def lte(other)

Raises:
  • (NoMethodError) - if `other` is an invalid type

Returns:
  • (Boolean) - Whether this number is less than or equal to the other

Parameters:
  • other (Number) -- The right-hand side of the operator
def lte(other)
  raise NoMethodError.new(nil, :lte) unless other.is_a?(Number)
  operate(other, :<=)
end

def minus(other)

Raises:
  • (Sass::UnitConversionError) - if `other` is a number with incompatible units

Returns:
  • (Literal) - The result of the operation

Parameters:
  • other (Literal) -- The right-hand side of the operator
def minus(other)
  if other.is_a? Number
    operate(other, :-)
  else
    super
  end
end

def mod(other)

Raises:
  • (Sass::UnitConversionError) - if `other` has any units
  • (NoMethodError) - if `other` is an invalid type

Returns:
  • (Number) - This number modulo the other

Parameters:
  • other (Number) -- The right-hand side of the operator
def mod(other)
  if other.is_a?(Number)
    unless other.unitless?
      raise Sass::UnitConversionError.new("Cannot modulo by a number with units: #{other.inspect}.")
    end
    operate(other, :%)
  else
    raise NoMethodError.new(nil, :mod)
  end
end

def normalize!

def normalize!
  return if unitless?
  @numerator_units, @denominator_units = sans_common_units(numerator_units, denominator_units)
  @denominator_units.each_with_index do |d, i|
    if convertable?(d) && (u = @numerator_units.detect(&method(:convertable?)))
      @value /= conversion_factor(d, u)
      @denominator_units.delete_at(i)
      @numerator_units.delete_at(@numerator_units.index(u))
    end
  end
end

def operate(other, operation)

def operate(other, operation)
  this = self
  if [:+, :-, :<=, :<, :>, :>=].include?(operation)
    if unitless?
      this = this.coerce(other.numerator_units, other.denominator_units)
    else
      other = other.coerce(numerator_units, denominator_units)
    end
  end
  # avoid integer division
  value = (:/ == operation) ? this.value.to_f : this.value
  result = value.send(operation, other.value)
  if result.is_a?(Numeric)
    Number.new(result, *compute_units(this, other, operation))
  else # Boolean op
    Bool.new(result)
  end
end

def plus(other)

Raises:
  • (Sass::UnitConversionError) - if `other` is a number with incompatible units

Returns:
  • (Literal) - The result of the operation

Parameters:
  • other (Literal) -- The right-hand side of the operator
def plus(other)
  if other.is_a? Number
    operate(other, :+)
  elsif other.is_a?(Color)
    other.plus(self)
  else
    super
  end
end

def sans_common_units(units1, units2)

def sans_common_units(units1, units2)
  units2 = units2.dup
  # Can't just use -, because we want px*px to coerce properly to px*mm
  return units1.map do |u|
    next u unless j = units2.index(u)
    units2.delete_at(j)
    nil
  end.compact, units2
end

def times(other)

Raises:
  • (NoMethodError) - if `other` is an invalid type

Returns:
  • (Number, Color) - The result of the operation

Parameters:
  • other (Number, Color) -- The right-hand side of the operator
def times(other)
  if other.is_a? Number
    operate(other, :*)
  elsif other.is_a? Color
    other.times(self)
  else
    raise NoMethodError.new(nil, :times)
  end
end

def to_i

Raises:
  • (Sass::SyntaxError) - if the number isn't an integer

Returns:
  • (Fixnum) - The integer value of the number
def to_i
  super unless int?
  return value
end

def to_s

Raises:
  • (Sass::SyntaxError) - if this number has units that can't be used in CSS

Returns:
  • (String) - The CSS representation of this number
def to_s
  return original if original
  raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.") unless legal_units?
  inspect
end

def unary_minus

Returns:
  • (Number) - The negative value of this number
def unary_minus
  Number.new(-value, numerator_units, denominator_units)
end

def unary_plus

Returns:
  • (Number) - The value of this number
def unary_plus
  self
end

def unit_str

Returns:
  • (String) - a string that represents the units in this number
def unit_str
  rv = numerator_units.sort.join("*")
  if denominator_units.any?
    rv << "/"
    rv << denominator_units.sort.join("*")
  end
  rv
end

def unitless?

Returns:
  • (Boolean) - Whether or not this number has no units.
def unitless?
  numerator_units.empty? && denominator_units.empty?
end