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.const_missing(const)
Handles the deprecation warning for the PRECISION constant
def self.const_missing(const) if const == :PRECISION Sass::Util.sass_warn("Sass::Script::Number::PRECISION is deprecated and will be removed in a future release. Use Sass::Script::Number.precision_factor instead.") const_set(:PRECISION, self.precision_factor) else super end end
def self.precision
def self.precision @precision ||= 3 end
def self.precision=(digits)
For example, if this is `3`,
Sets the number of digits of precision
def self.precision=(digits) @precision = digits.round @precision_factor = 10.0**@precision end
def self.precision_factor
the precision factor used in numeric output
def self.precision_factor @precision_factor ||= 10.0**precision end
def self.round(num)
- 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 * self.precision_factor).round / self.precision_factor).to_f end end
def coerce(num_units, den_units)
-
(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(@numerator_units, num_units) / coercion_factor(@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)
-
(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? {|u| CONVERTABLE_UNITS.include?(u)} end
def div(other)
-
(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 res.original = "#{self.original}/#{other.original}" end res else super end end
def eq(other)
-
(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)
-
(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)
-
(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 = NO_UNITS, denominator_units = NO_UNITS)
-
denominator_units
(Array
) -- See \{#denominator\_units} -
numerator_units
(Array
) -- See \{#numerator\_units} -
value
(Numeric
) -- The value of the number
def initialize(value, numerator_units = NO_UNITS, denominator_units = NO_UNITS) super(value) @numerator_units = numerator_units @denominator_units = denominator_units normalize! end
def inspect(opts = {})
-
(String)
- The representation
def inspect(opts = {}) value = self.class.round(self.value) unitless? ? value.to_s : "#{value}#{unit_str}" end
def int?
-
(Boolean)
- Whether or not this number is an integer.
def int? value % 1 == 0.0 end
def legal_units?
-
(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)
-
(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)
-
(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)
-
(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)
-
(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 OPERATIONS.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)
-
(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)
-
(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
-
(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(opts = {})
-
(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(opts = {}) return original if original raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.") unless legal_units? inspect end
def unary_minus
-
(Number)
- The negative value of this number
def unary_minus Number.new(-value, @numerator_units, @denominator_units) end
def unary_plus
-
(Number)
- The value of this number
def unary_plus self end
def unit_str
-
(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?
-
(Boolean)
- Whether or not this number has no units.
def unitless? @numerator_units.empty? && @denominator_units.empty? end