Class Sass::Script::Number
In: lib/sass/script/number.rb
Parent: Literal
Haml::Util Engine Color SyntaxError UnitConversionError StandardError AbstractSequence CommaSequence Sequence SimpleSequence Simple Parent Universal Class SelectorPseudoClass Id Pseudo Attribute Interpolation Element Node Operation Literal UnaryOperation StringInterpolation Funcall Interpolation Variable Lexer CssLexer Number Bool String Parser Parser CssParser EvaluationContext StaticParser SassParser CssParser Node DebugNode IfNode CommentNode ForNode PropNode MixinNode CharsetNode DirectiveNode VariableNode WarnNode ExtendNode RootNode WhileNode MixinDefNode RuleNode Enumerable ImportNode Merb::BootLoader MerbBootLoader Repl CSS Environment Rack StalenessChecker lib/sass/repl.rb lib/sass/css.rb lib/sass/environment.rb lib/sass/error.rb lib/sass/engine.rb lib/sass/selector/simple_sequence.rb lib/sass/selector/abstract_sequence.rb lib/sass/selector/sequence.rb lib/sass/selector/comma_sequence.rb lib/sass/selector/simple.rb lib/sass/selector.rb Selector lib/sass/script/css_parser.rb lib/sass/script/lexer.rb lib/sass/script/color.rb lib/sass/script/string.rb lib/sass/script/unary_operation.rb lib/sass/script/variable.rb lib/sass/script/funcall.rb lib/sass/script/string_interpolation.rb lib/sass/script/operation.rb lib/sass/script/bool.rb lib/sass/script/parser.rb lib/sass/script/node.rb lib/sass/script/literal.rb lib/sass/script/interpolation.rb lib/sass/script/css_lexer.rb lib/sass/script/number.rb lib/sass/script/functions.rb Functions Script lib/sass/scss/sass_parser.rb lib/sass/scss/static_parser.rb lib/sass/scss/parser.rb lib/sass/scss/css_parser.rb ScriptLexer ScriptParser RX SCSS Callbacks Files lib/sass/tree/while_node.rb lib/sass/tree/if_node.rb lib/sass/tree/mixin_def_node.rb lib/sass/tree/debug_node.rb lib/sass/tree/root_node.rb lib/sass/tree/for_node.rb lib/sass/tree/import_node.rb lib/sass/tree/prop_node.rb lib/sass/tree/node.rb lib/sass/tree/comment_node.rb lib/sass/tree/extend_node.rb lib/sass/tree/charset_node.rb lib/sass/tree/mixin_node.rb lib/sass/tree/warn_node.rb lib/sass/tree/directive_node.rb lib/sass/tree/rule_node.rb lib/sass/tree/variable_node.rb Tree lib/sass/plugin/rack.rb lib/sass/plugin/staleness_checker.rb lib/sass/plugin/merb.rb Plugin Sass dot/m_86_0.png

A SassScript object representing a number. SassScript numbers can have decimal values, and can also have units. For example, `12`, `1px`, and `10.45em` are all valid values.

Numbers can also have more complex units, such as `1px*em/in`. These cannot be inputted directly in Sass code at the moment.

Methods

coerce   coercion_factor   comparable_to?   compute_units   conversion_factor   convertable?   div   eq   gt   gte   inspect   int?   legal_units?   lt   lte   minus   mod   new   normalize!   operate   plus   round   sans_common_units   times   to_i   to_s   to_sass   unary_minus   unary_plus   unit_str   unitless?  

Constants

PRECISION = 1000.0   The precision with which numbers will be printed to CSS files. For example, if this is `1000.0`, `3.1415926` will be printed as `3.142`. @api public
CONVERTABLE_UNITS = {"in" => 0, "cm" => 1, "pc" => 2, "mm" => 3, "pt" => 4}   A hash of unit names to their index in the conversion table
CONVERSION_TABLE = [[ 1, 2.54, 6, 25.4, 72 ], # in [ nil, 1, 2.36220473, 10, 28.3464567], # cm [ nil, nil, 1, 4.23333333, 12 ], # pc [ nil, nil, nil, 1, 2.83464567], # mm [ nil, nil, nil, nil, 1 ]]

Attributes

denominator_units  [R]  A list of units in the denominator of the number. For example, `1px*em/in*cm` would return `["in", "cm"]` @return [Array<String>]
numerator_units  [R]  A list of units in the numerator of the number. For example, `1px*em/in*cm` would return `["px", "em"]` @return [Array<String>]
original  [RW]  The original representation of this number. For example, although the result of `1px/2px` is `0.5`, the value of `original` is `"1px/2px"`.

This is only non-nil when the original value should be used as the CSS value, as in `font: 1px/2px`.

@return [Boolean, nil]

value  [R]  The Ruby value of the number.

@return [Numeric]

Public Class methods

@param value [Numeric] The value of the number @param numerator_units [Array<String>] See \{numerator_units} @param denominator_units [Array<String>] See \{denominator_units}

[Source]

    # File lib/sass/script/number.rb, line 47
47:     def initialize(value, numerator_units = [], denominator_units = [])
48:       super(value)
49:       @numerator_units = numerator_units
50:       @denominator_units = denominator_units
51:       normalize!
52:     end

Private Class methods

@private

[Source]

     # File lib/sass/script/number.rb, line 330
330:     def self.round(num)
331:       if num.is_a?(Float) && (num.infinite? || num.nan?)
332:         num
333:       elsif num % 1 == 0.0
334:         num.to_i
335:       else
336:         (num * PRECISION).round / PRECISION
337:       end
338:     end

Public Instance methods

Returns this number converted to other units. The conversion takes into account the relationship between e.g. mm and cm, as well as between e.g. in and cm.

If this number has no units, it will simply return itself with the given units.

An incompatible coercion, e.g. between px and cm, will raise an error.

@param num_units [Array<String>] The numerator units to coerce this number into.

  See {\#numerator\_units}

@param den_units [Array<String>] The denominator units to coerce this number into.

  See {\#denominator\_units}

@return [Number] The number with the new units @raise [Sass::UnitConversionError] if the given units are incompatible with the number‘s

  current units

[Source]

     # File lib/sass/script/number.rb, line 294
294:     def coerce(num_units, den_units)
295:       Number.new(if unitless?
296:                    self.value
297:                  else
298:                    self.value * coercion_factor(self.numerator_units, num_units) /
299:                      coercion_factor(self.denominator_units, den_units)
300:                  end, num_units, den_units)
301:     end

@param other [Number] A number to decide if it can be compared with this number. @return [Boolean] Whether or not this number can be compared with the other.

[Source]

     # File lib/sass/script/number.rb, line 305
305:     def comparable_to?(other)
306:       begin
307:         operate(other, :+)
308:         true
309:       rescue Sass::UnitConversionError
310:         false
311:       end
312:     end

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

{Number} : Divides this number by the other, converting units appropriately.

{Literal} : See {Literal#div}.

@param other [Literal] The right-hand side of the operator @return [Literal] The result of the operation

[Source]

     # File lib/sass/script/number.rb, line 146
146:     def div(other)
147:       if other.is_a? Number
148:         res = operate(other, :/)
149:         if self.original && other.original && context != :equals
150:           res.original = "#{self.original}/#{other.original}"
151:         end
152:         res
153:       else
154:         super
155:       end
156:     end

The SassScript `==` operation.

@param other [Literal] The right-hand side of the operator @return [Boolean] Whether this number is equal to the other object

[Source]

     # File lib/sass/script/number.rb, line 179
179:     def eq(other)
180:       return Sass::Script::Bool.new(false) unless other.is_a?(Sass::Script::Number)
181:       this = self
182:       begin
183:         if unitless?
184:           this = this.coerce(other.numerator_units, other.denominator_units)
185:         else
186:           other = other.coerce(numerator_units, denominator_units)
187:         end
188:       rescue Sass::UnitConversionError
189:         return Sass::Script::Bool.new(false)
190:       end
191: 
192:       Sass::Script::Bool.new(this.value == other.value)
193:     end

The SassScript `>` operation.

@param other [Number] The right-hand side of the operator @return [Boolean] Whether this number is greater than the other @raise [NoMethodError] if `other` is an invalid type

[Source]

     # File lib/sass/script/number.rb, line 200
200:     def gt(other)
201:       raise NoMethodError.new(nil, :gt) unless other.is_a?(Number)
202:       operate(other, :>)
203:     end

The SassScript `>=` operation.

@param other [Number] The right-hand side of the operator @return [Boolean] Whether this number is greater than or equal to the other @raise [NoMethodError] if `other` is an invalid type

[Source]

     # File lib/sass/script/number.rb, line 210
210:     def gte(other)
211:       raise NoMethodError.new(nil, :gte) unless other.is_a?(Number)
212:       operate(other, :>=)
213:     end

Returns a readable representation of this number.

This representation is valid CSS (and valid SassScript) as long as there is only one unit.

@return [String] The representation

[Source]

     # File lib/sass/script/number.rb, line 250
250:     def inspect(opts = {})
251:       "#{self.class.round(self.value)}#{unit_str}"
252:     end

@return [Boolean] Whether or not this number is an integer.

[Source]

     # File lib/sass/script/number.rb, line 263
263:     def int?
264:       value % 1 == 0.0
265:     end

@return [Boolean] Whether or not this number has units that can be represented in CSS

  (that is, zero or one \{#numerator\_units}).

[Source]

     # File lib/sass/script/number.rb, line 274
274:     def legal_units?
275:       (numerator_units.empty? || numerator_units.size == 1) && denominator_units.empty?
276:     end

The SassScript `<` operation.

@param other [Number] The right-hand side of the operator @return [Boolean] Whether this number is less than the other @raise [NoMethodError] if `other` is an invalid type

[Source]

     # File lib/sass/script/number.rb, line 220
220:     def lt(other)
221:       raise NoMethodError.new(nil, :lt) unless other.is_a?(Number)
222:       operate(other, :<)
223:     end

The SassScript `<=` operation.

@param other [Number] The right-hand side of the operator @return [Boolean] Whether this number is less than or equal to the other @raise [NoMethodError] if `other` is an invalid type

[Source]

     # File lib/sass/script/number.rb, line 230
230:     def lte(other)
231:       raise NoMethodError.new(nil, :lte) unless other.is_a?(Number)
232:       operate(other, :<=)
233:     end

The SassScript binary `-` operation (e.g. `$a - $b`). Its functionality depends on the type of its argument:

{Number} : Subtracts this number from the other, converting units if possible.

{Literal} : See {Literal#minus}.

@param other [Literal] The right-hand side of the operator @return [Literal] The result of the operation @raise [Sass::UnitConversionError] if `other` is a number with incompatible units

[Source]

    # File lib/sass/script/number.rb, line 91
91:     def minus(other)
92:       if other.is_a? Number
93:         operate(other, :-)
94:       else
95:         super
96:       end
97:     end

The SassScript `%` operation.

@param other [Number] The right-hand side of the operator @return [Number] This number modulo the other @raise [NoMethodError] if `other` is an invalid type @raise [Sass::UnitConversionError] if `other` has any units

[Source]

     # File lib/sass/script/number.rb, line 164
164:     def mod(other)
165:       if other.is_a?(Number)
166:         unless other.unitless?
167:           raise Sass::UnitConversionError.new("Cannot modulo by a number with units: #{other.inspect}.")
168:         end
169:         operate(other, :%)
170:       else
171:         raise NoMethodError.new(nil, :mod)
172:       end
173:     end

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

{Number} : Adds the two numbers together, converting units if possible.

{Color} : Adds this number to each of the RGB color channels.

{Literal} : See {Literal#plus}.

@param other [Literal] The right-hand side of the operator @return [Literal] The result of the operation @raise [Sass::UnitConversionError] if `other` is a number with incompatible units

[Source]

    # File lib/sass/script/number.rb, line 69
69:     def plus(other)
70:       if other.is_a? Number
71:         operate(other, :+)
72:       elsif other.is_a?(Color)
73:         other.plus(self)
74:       else
75:         super
76:       end
77:     end

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

{Number} : Multiplies the two numbers together, converting units appropriately.

{Color} : Multiplies each of the RGB color channels by this number.

@param other [Number, Color] The right-hand side of the operator @return [Number, Color] The result of the operation @raise [NoMethodError] if `other` is an invalid type

[Source]

     # File lib/sass/script/number.rb, line 125
125:     def times(other)
126:       if other.is_a? Number
127:         operate(other, :*)
128:       elsif other.is_a? Color
129:         other.times(self)
130:       else
131:         raise NoMethodError.new(nil, :times)
132:       end
133:     end

@return [Fixnum] The integer value of the number @raise [Sass::SyntaxError] if the number isn‘t an integer

[Source]

     # File lib/sass/script/number.rb, line 257
257:     def to_i
258:       super unless int?
259:       return value
260:     end

@return [String] The CSS representation of this number @raise [Sass::SyntaxError] if this number has units that can‘t be used in CSS

  (e.g. `px*in`)

[Source]

     # File lib/sass/script/number.rb, line 238
238:     def to_s
239:       return original if original
240:       raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.") unless legal_units?
241:       inspect
242:     end
to_sass(opts = {})

Alias for inspect

The SassScript unary `-` operation (e.g. `-$a`).

@return [Number] The negative value of this number

[Source]

     # File lib/sass/script/number.rb, line 109
109:     def unary_minus
110:       Number.new(-value, numerator_units, denominator_units)
111:     end

The SassScript unary `+` operation (e.g. `+$a`).

@return [Number] The value of this number

[Source]

     # File lib/sass/script/number.rb, line 102
102:     def unary_plus
103:       self
104:     end

Returns a human readable representation of the units in this number. For complex units this takes the form of: numerator_unit1 * numerator_unit2 / denominator_unit1 * denominator_unit2 @return [String] a string that represents the units in this number

[Source]

     # File lib/sass/script/number.rb, line 318
318:     def unit_str
319:       rv = numerator_units.sort.join("*")
320:       if denominator_units.any?
321:         rv << "/"
322:         rv << denominator_units.sort.join("*")
323:       end
324:       rv
325:     end

@return [Boolean] Whether or not this number has no units.

[Source]

     # File lib/sass/script/number.rb, line 268
268:     def unitless?
269:       numerator_units.empty? && denominator_units.empty?
270:     end

Private Instance methods

[Source]

     # File lib/sass/script/number.rb, line 360
360:     def coercion_factor(from_units, to_units)
361:       # get a list of unmatched units
362:       from_units, to_units = sans_common_units(from_units, to_units)
363: 
364:       if from_units.size != to_units.size || !convertable?(from_units | to_units)
365:         raise Sass::UnitConversionError.new("Incompatible units: '#{from_units.join('*')}' and '#{to_units.join('*')}'.")
366:       end
367: 
368:       from_units.zip(to_units).inject(1) {|m,p| m * conversion_factor(p[0], p[1]) }
369:     end

[Source]

     # File lib/sass/script/number.rb, line 371
371:     def compute_units(this, other, operation)
372:       case operation
373:       when :*
374:         [this.numerator_units + other.numerator_units, this.denominator_units + other.denominator_units]
375:       when :/
376:         [this.numerator_units + other.denominator_units, this.denominator_units + other.numerator_units]
377:       else  
378:         [this.numerator_units, this.denominator_units]
379:       end
380:     end

[Source]

     # File lib/sass/script/number.rb, line 403
403:     def conversion_factor(from_unit, to_unit)
404:       res = CONVERSION_TABLE[CONVERTABLE_UNITS[from_unit]][CONVERTABLE_UNITS[to_unit]]
405:       return 1.0 / conversion_factor(to_unit, from_unit) if res.nil?
406:       res
407:     end

[Source]

     # File lib/sass/script/number.rb, line 409
409:     def convertable?(units)
410:       Array(units).all?(&CONVERTABLE_UNITS.method(:include?))
411:     end

[Source]

     # File lib/sass/script/number.rb, line 382
382:     def normalize!
383:       return if unitless?
384:       @numerator_units, @denominator_units = sans_common_units(numerator_units, denominator_units)
385: 
386:       @denominator_units.each_with_index do |d, i|
387:         if convertable?(d) && (u = @numerator_units.detect(&method(:convertable?)))
388:           @value /= conversion_factor(d, u)
389:           @denominator_units.delete_at(i)
390:           @numerator_units.delete_at(@numerator_units.index(u))
391:         end
392:       end
393:     end

[Source]

     # File lib/sass/script/number.rb, line 340
340:     def operate(other, operation)
341:       this = self
342:       if [:+, :-, :<=, :<, :>, :>=].include?(operation)
343:         if unitless?
344:           this = this.coerce(other.numerator_units, other.denominator_units)
345:         else
346:           other = other.coerce(numerator_units, denominator_units)
347:         end
348:       end
349:       # avoid integer division
350:       value = (:/ == operation) ? this.value.to_f : this.value
351:       result = value.send(operation, other.value)
352: 
353:       if result.is_a?(Numeric)
354:         Number.new(result, *compute_units(this, other, operation))
355:       else # Boolean op
356:         Bool.new(result)
357:       end
358:     end

[Source]

     # File lib/sass/script/number.rb, line 413
413:     def sans_common_units(units1, units2)
414:       units2 = units2.dup
415:       # Can't just use -, because we want px*px to coerce properly to px*mm
416:       return units1.map do |u|
417:         next u unless j = units2.index(u)
418:         units2.delete_at(j)
419:         nil
420:       end.compact, units2
421:     end

[Validate]