class SassNumber in Sassy 7
Same name and namespace in other branches
- 7.3 phpsass/script/literals/SassNumber.php \SassNumber
SassNumber class. Provides operations and type testing for Sass numbers. Units are of the passed value are converted the those of the class value if it has units. e.g. 2cm + 20mm = 4cm while 2 + 20mm = 22mm. @package PHamlP @subpackage Sass.script.literals
Hierarchy
- class \SassLiteral
- class \SassNumber
Expanded class hierarchy of SassNumber
12 string references to 'SassNumber'
- SassScriptFunctions::abs in phamlp/
sass/ script/ SassScriptFunctions.php - * Finds the absolute value of a number. * For example: * abs(10px) => 10px * abs(-10px) => 10px * *
- SassScriptFunctions::adjust in phamlp/
sass/ script/ SassScriptFunctions.php - * Adjusts the colour *
- SassScriptFunctions::adjust_hue in phamlp/
sass/ script/ SassScriptFunctions.php - * Changes the hue of a colour while retaining the lightness and saturation. *
- SassScriptFunctions::ceil in phamlp/
sass/ script/ SassScriptFunctions.php - * Rounds a number up to the nearest whole number. * For example: * ceil(10.4px) => 11px * ceil(10.6px) => 11px * *
- SassScriptFunctions::comparable in phamlp/
sass/ script/ SassScriptFunctions.php - * Returns true if two numbers are similar enough to be added, subtracted, * or compared. *
File
- phamlp/
sass/ script/ literals/ SassNumber.php, line 22
View source
class SassNumber extends SassLiteral {
/**
* Regx for matching and extracting numbers
*/
const MATCH = '/^((?:-)?(?:\\d*\\.)?\\d+)(([a-z%]+)(\\s*[\\*\\/]\\s*[a-z%]+)*)?/i';
const VALUE = 1;
const UNITS = 2;
/**
* The number of decimal digits to round to.
* If the units are pixels the result is always
* rounded down to the nearest integer.
*/
const PRECISION = 4;
/**
* @var array Conversion factors for units using inches as the base unit
* (only because pt and pc are expressed as fraction of an inch, so makes the
* numbers easy to understand).
* Conversions are based on the following
* in: inches — 1 inch = 2.54 centimeters
* cm: centimeters
* mm: millimeters
* pc: picas — 1 pica = 12 points
* pt: points — 1 point = 1/72nd of an inch
*/
private static $unitConversion = array(
'in' => 1,
'cm' => 2.54,
'mm' => 25.4,
'pc' => 6,
'pt' => 72,
);
/**
* @var array numerator units of this number
*/
private $numeratorUnits = array();
/**
* @var array denominator units of this number
*/
private $denominatorUnits = array();
/**
* @var boolean whether this number is in an expression or a literal number
* Used to determine whether division should take place
*/
public $inExpression = true;
/**
* class constructor.
* Sets the value and units of the number.
* @param string number
* @return SassNumber
*/
public function __construct($value) {
preg_match(self::MATCH, $value, $matches);
$this->value = $matches[self::VALUE];
if (!empty($matches[self::UNITS])) {
$units = explode('/', $matches[self::UNITS]);
$numeratorUnits = $denominatorUnits = array();
foreach (explode('*', $units[0]) as $unit) {
$numeratorUnits[] = trim($unit);
}
if (isset($units[1])) {
foreach (explode('*', $units[1]) as $unit) {
$denominatorUnits[] = trim($unit);
}
}
$units = $this
->removeCommonUnits($numeratorUnits, $denominatorUnits);
$this->numeratorUnits = $units[0];
$this->denominatorUnits = $units[1];
}
}
/**
* Adds the value of other to the value of this
* @param mixed SassNumber|SassColour: value to add
* @return mixed SassNumber if other is a SassNumber or
* SassColour if it is a SassColour
*/
public function op_plus($other) {
if ($other instanceof SassColour) {
return $other
->op_plus($this);
}
elseif (!$other instanceof SassNumber) {
throw new SassNumberException('{what} must be a {type}', array(
'{what}' => Phamlp::t('sass', 'Number'),
'{type}' => Phamlp::t('sass', 'number'),
), SassScriptParser::$context->node);
}
else {
$other = $this
->convert($other);
return new SassNumber($this->value + $other->value . $this->units);
}
}
/**
* Unary + operator
* @return SassNumber the value of this number
*/
public function op_unary_plus() {
return $this;
}
/**
* Subtracts the value of other from this value
* @param mixed SassNumber|SassColour: value to subtract
* @return mixed SassNumber if other is a SassNumber or
* SassColour if it is a SassColour
*/
public function op_minus($other) {
if ($other instanceof SassColour) {
return $other
->op_minus($this);
}
elseif (!$other instanceof SassNumber) {
throw new SassNumberException('{what} must be a {type}', array(
'{what}' => Phamlp::t('sass', 'Number'),
'{type}' => Phamlp::t('sass', 'number'),
), SassScriptParser::$context->node);
}
else {
$other = $this
->convert($other);
return new SassNumber($this->value - $other->value . $this->units);
}
}
/**
* Unary - operator
* @return SassNumber the negative value of this number
*/
public function op_unary_minus() {
return new SassNumber($this->value * -1 . $this->units);
}
public function op_unary_concat() {
return $this;
}
/**
* Multiplies this value by the value of other
* @param mixed SassNumber|SassColour: value to multiply by
* @return mixed SassNumber if other is a SassNumber or
* SassColour if it is a SassColour
*/
public function op_times($other) {
if ($other instanceof SassColour) {
return $other
->op_times($this);
}
elseif (!$other instanceof SassNumber) {
throw new SassNumberException('{what} must be a {type}', array(
'{what}' => Phamlp::t('sass', 'Number'),
'{type}' => Phamlp::t('sass', 'number'),
), SassScriptParser::$context->node);
}
else {
return new SassNumber($this->value * $other->value . $this
->unitString(array_merge($this->numeratorUnits, $other->numeratorUnits), array_merge($this->denominatorUnits, $other->denominatorUnits)));
}
}
/**
* Divides this value by the value of other
* @param mixed SassNumber|SassColour: value to divide by
* @return mixed SassNumber if other is a SassNumber or
* SassColour if it is a SassColour
*/
public function op_div($other) {
if ($other instanceof SassColour) {
return $other
->op_div($this);
}
elseif (!$other instanceof SassNumber) {
throw new SassNumberException('{what} must be a {type}', array(
'{what}' => Phamlp::t('sass', 'Number'),
'{type}' => Phamlp::t('sass', 'number'),
), SassScriptParser::$context->node);
}
elseif ($this->inExpression || $other->inExpression) {
return new SassNumber($this->value / $other->value . $this
->unitString(array_merge($this->numeratorUnits, $other->denominatorUnits), array_merge($this->denominatorUnits, $other->numeratorUnits)));
}
else {
return parent::op_div($other);
}
}
/**
* The SassScript == operation.
* @return SassBoolean SassBoolean object with the value true if the values
* of this and other are equal, false if they are not
*/
public function op_eq($other) {
if (!$other instanceof SassNumber) {
return new SassBoolean(false);
}
try {
return new SassBoolean($this->value == $this
->convert($other)->value);
} catch (Exception $e) {
return new SassBoolean(false);
}
}
/**
* The SassScript > operation.
* @param sassLiteral the value to compare to this
* @return SassBoolean SassBoolean object with the value true if the values
* of this is greater than the value of other, false if it is not
*/
public function op_gt($other) {
if (!$other instanceof SassNumber) {
throw new SassNumberException('{what} must be a {type}', array(
'{what}' => Phamlp::t('sass', 'Number'),
'{type}' => Phamlp::t('sass', 'number'),
), SassScriptParser::$context->node);
}
return new SassBoolean($this->value > $this
->convert($other)->value);
}
/**
* The SassScript >= operation.
* @param sassLiteral the value to compare to this
* @return SassBoolean SassBoolean object with the value true if the values
* of this is greater than or equal to the value of other, false if it is not
*/
public function op_gte($other) {
if (!$other instanceof SassNumber) {
throw new SassNumberException('{what} must be a {type}', array(
'{what}' => Phamlp::t('sass', 'Number'),
'{type}' => Phamlp::t('sass', 'number'),
), SassScriptParser::$context->node);
}
return new SassBoolean($this->value >= $this
->convert($other)->value);
}
/**
* The SassScript < operation.
* @param sassLiteral the value to compare to this
* @return SassBoolean SassBoolean object with the value true if the values
* of this is less than the value of other, false if it is not
*/
public function op_lt($other) {
if (!$other instanceof SassNumber) {
throw new SassNumberException('{what} must be a {type}', array(
'{what}' => Phamlp::t('sass', 'Number'),
'{type}' => Phamlp::t('sass', 'number'),
), SassScriptParser::$context->node);
}
return new SassBoolean($this->value < $this
->convert($other)->value);
}
/**
* The SassScript <= operation.
* @param sassLiteral the value to compare to this
* @return SassBoolean SassBoolean object with the value true if the values
* of this is less than or equal to the value of other, false if it is not
*/
public function op_lte($other) {
if (!$other instanceof SassNumber) {
throw new SassNumberException('{what} must be a {type}', array(
'{what}' => Phamlp::t('sass', 'Number'),
'{type}' => Phamlp::t('sass', 'number'),
), SassScriptParser::$context->node);
}
return new SassBoolean($this->value <= $this
->convert($other)->value);
}
/**
* Takes the modulus (remainder) of this value divided by the value of other
* @param string value to divide by
* @return mixed SassNumber if other is a SassNumber or
* SassColour if it is a SassColour
*/
public function op_modulo($other) {
if (!$other instanceof SassNumber || !$other
->isUnitless()) {
throw new SassNumberException('{what} must be a {type}', array(
'{what}' => Phamlp::t('sass', 'Number'),
'{type}' => Phamlp::t('sass', 'unitless number'),
), SassScriptParser::$context->node);
}
$this->value %= $this
->convert($other)->value;
return $this;
}
/**
* Converts values and units.
* If this is a unitless numeber it will take the units of other; if not
* other is coerced to the units of this.
* @param SassNumber the other number
* @return SassNumber the other number with its value and units coerced if neccessary
* @throws SassNumberException if the units are incompatible
*/
private function convert($other) {
if ($this
->isUnitless()) {
$this->numeratorUnits = $other->numeratorUnits;
$this->denominatorUnits = $other->denominatorUnits;
}
else {
$other = $other
->coerce($this->numeratorUnits, $this->denominatorUnits);
}
return $other;
}
/**
* Returns the value of 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 is unitless, it will simply return itself with the given units.
* @param array $numeratorUnits
* @param array $denominatorUnits
* @return SassNumber
*/
public function coerce($numeratorUnits, $denominatorUnits) {
return new SassNumber(($this
->isUnitless() ? $this->value : $this->value * $this
->coercionFactor($this->numeratorUnits, $numeratorUnits) / $this
->coercionFactor($this->denominatorUnits, $denominatorUnits)) . join(' * ', $numeratorUnits) . (!empty($denominatorUnits) ? ' / ' . join(' * ', $denominatorUnits) : ''));
}
/**
* Calculates the corecion factor to apply to the value
* @param array units being converted from
* @param array units being converted to
* @return float the coercion factor to apply
*/
private function coercionFactor($fromUnits, $toUnits) {
$units = $this
->removeCommonUnits($fromUnits, $toUnits);
$fromUnits = $units[0];
$toUnits = $units[1];
if (sizeof($fromUnits) !== sizeof($toUnits) || !$this
->areConvertable(array_merge($fromUnits, $toUnits))) {
throw new SassNumberException("Incompatible units: '{from}' and '{to}'", array(
'{from}' => join(' * ', $fromUnits),
'{to}' => join(' * ', $toUnits),
), SassScriptParser::$context->node);
}
$coercionFactor = 1;
foreach ($fromUnits as $i => $from) {
if (array_key_exists($from) && array_key_exists($from)) {
$coercionFactor *= self::$unitConversion[$toUnits[$i]] / self::$unitConversion[$from];
}
else {
throw new SassNumberException("Incompatible units: '{from}' and '{to}", array(
'{from}' => join(' * ', $fromUnits),
'{to}' => join(' * ', $toUnits),
), SassScriptParser::$context->node);
}
}
return $coercionFactor;
}
/**
* Returns a value indicating if all the units are capable of being converted
* @param array units to test
* @return boolean true if all units can be converted, false if not
*/
private function areConvertable($units) {
$convertable = array_keys(self::$unitConversion);
foreach ($units as $unit) {
if (!in_array($unit, $convertable)) {
return false;
}
}
return true;
}
/**
* Removes common units from each set.
* We don't use array_diff because we want (for eaxmple) mm*mm/mm*cm to
* end up as mm/cm.
* @param array first set of units
* @param array second set of units
* @return array both sets of units with common units removed
*/
private function removeCommonUnits($u1, $u2) {
$_u1 = array();
while (!empty($u1)) {
$u = array_shift($u1);
$i = array_search($u, $u2);
if ($i !== false) {
unset($u2[$i]);
}
else {
$_u1[] = $u;
}
}
return array(
$_u1,
$u2,
);
}
/**
* Returns a value indicating if this number is unitless.
* @return boolean true if this number is unitless, false if not
*/
public function isUnitless() {
return empty($this->numeratorUnits) && empty($this->denominatorUnits);
}
/**
* Returns a value indicating if this number has units.
* @return boolean true if this number has, false if not
*/
public function hasUnits() {
return !$this
->isUnitless();
}
/**
* Returns a value indicating if this number has units that can be represented
* in CSS.
* @return boolean true if this number has units that can be represented in
* CSS, false if not
*/
public function hasLegalUnits() {
return (empty($this->numeratorUnits) || count($this->numeratorUnits) === 1) && empty($this->denominatorUnits);
}
/**
* Returns a string representation of the units.
* @return string the units
*/
public function unitString($numeratorUnits, $denominatorUnits) {
return join(' * ', $numeratorUnits) . (!empty($denominatorUnits) ? ' / ' . join(' * ', $denominatorUnits) : '');
}
/**
* Returns the units of this number.
* @return string the units of this number
*/
public function getUnits() {
return $this
->unitString($this->numeratorUnits, $this->denominatorUnits);
}
/**
* Returns the denominator units of this number.
* @return string the denominator units of this number
*/
public function getDenominatorUnits() {
return join(' * ', $this->denominatorUnits);
}
/**
* Returns the numerator units of this number.
* @return string the numerator units of this number
*/
public function getNumeratorUnits() {
return join(' * ', $this->numeratorUnits);
}
/**
* Returns a value indicating if this number can be compared to other.
* @return boolean true if this number can be compared to other, false if not
*/
public function isComparableTo($other) {
try {
$this
->op_plus($other);
return true;
} catch (Exception $e) {
return false;
}
}
/**
* Returns a value indicating if this number is an integer.
* @return boolean true if this number is an integer, false if not
*/
public function isInt() {
return $this->value % 1 === 0;
}
/**
* Returns the value of this number.
* @return float the value of this number.
*/
public function getValue() {
return $this->value;
}
/**
* Returns the integer value.
* @return integer the integer value.
* @throws SassNumberException if the number is not an integer
*/
public function toInt() {
if (!$this
->isInt()) {
throw new SassNumberException('Not an integer: {value}', array(
'{value}' => $this->value,
), SassScriptParser::$context->node);
}
return intval($this->value);
}
/**
* Converts the number to a string with it's units if any.
* If the units are px the result is rounded down to the nearest integer,
* otherwise the result is rounded to the specified precision.
* @return string number as a string with it's units if any
*/
public function toString() {
if (!$this
->hasLegalUnits()) {
throw new SassNumberException('Invalid {what}', array(
'{what}' => "CSS units ({$this->units})",
), SassScriptParser::$context->node);
}
return ($this->units == 'px' ? floor($this->value) : round($this->value, self::PRECISION)) . $this->units;
}
/**
* Returns a value indicating if a token of this type can be matched at
* the start of the subject string.
* @param string the subject string
* @return mixed match at the start of the string or false if no match
*/
public static function isa($subject) {
return preg_match(self::MATCH, $subject, $matches) ? $matches[0] : false;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
SassLiteral:: |
private static | property | * | |
SassLiteral:: |
protected | property | * | |
SassLiteral:: |
public | function | * Adds a child object to this. * | |
SassLiteral:: |
public static | function | * Asserts that the value of a literal is within the expected range * | |
SassLiteral:: |
public static | function | * Asserts that the literal is the expected type * | |
SassLiteral:: |
protected | function | * Returns the type of this * | 1 |
SassLiteral:: |
public | function | * The SassScript and operation. * | |
SassLiteral:: |
public | function | ||
SassLiteral:: |
public | function | * Bitwise AND the value of other and this value * | 1 |
SassLiteral:: |
public | function | * Bitwise NOT the value of other and the value of this * | |
SassLiteral:: |
public | function | * Bitwise OR the value of other and this value * | 1 |
SassLiteral:: |
public | function | * Bitwise XOR the value of other and the value of this * | 1 |
SassLiteral:: |
public | function | * SassScript ',' operation. * | |
SassLiteral:: |
public | function | * The SassScript default operation (e.g. $a $b, "foo" "bar"). * | |
SassLiteral:: |
public | function | * The SassScript != operation. * | |
SassLiteral:: |
public | function | * The SassScript not operation. * | 1 |
SassLiteral:: |
public | function | * The SassScript or operation. * | |
SassLiteral:: |
public | function | * Shifts the value of this left by the number of bits given in value * | 1 |
SassLiteral:: |
public | function | * Shifts the value of this right by the number of bits given in value * | 1 |
SassLiteral:: |
public | function | * The SassScript xor operation. * | |
SassLiteral:: |
public | function | * Returns the boolean representation of the value of this * | |
SassLiteral:: |
public | function | * Getter. * | |
SassLiteral:: |
public | function | ||
SassNumber:: |
private | property | * | |
SassNumber:: |
public | property | * * Used to determine whether division should take place | |
SassNumber:: |
private | property | * | |
SassNumber:: |
private static | property | * * (only because pt and pc are expressed as fraction of an inch, so makes the * numbers easy to understand). * Conversions are based on the following * in: inches — 1 inch = 2.54 centimeters cm: centimeters mm: millimeters pc: picas — 1… | |
SassNumber:: |
private | function | * Returns a value indicating if all the units are capable of being converted * | |
SassNumber:: |
public | function | * Returns the value of 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 is unitless, it will simply return itself with… | |
SassNumber:: |
private | function | * Calculates the corecion factor to apply to the value * | |
SassNumber:: |
private | function | * Converts values and units. * If this is a unitless numeber it will take the units of other; if not * other is coerced to the units of this. * | |
SassNumber:: |
public | function | * Returns the denominator units of this number. * | |
SassNumber:: |
public | function | * Returns the numerator units of this number. * | |
SassNumber:: |
public | function | * Returns the units of this number. * | |
SassNumber:: |
public | function |
* Returns the value of this number.
* Overrides SassLiteral:: |
|
SassNumber:: |
public | function | * Returns a value indicating if this number has units that can be represented * in CSS. * | |
SassNumber:: |
public | function | * Returns a value indicating if this number has units. * | |
SassNumber:: |
public static | function |
* Returns a value indicating if a token of this type can be matched at
* the start of the subject string.
* Overrides SassLiteral:: |
|
SassNumber:: |
public | function | * Returns a value indicating if this number can be compared to other. * | |
SassNumber:: |
public | function | * Returns a value indicating if this number is an integer. * | |
SassNumber:: |
public | function | * Returns a value indicating if this number is unitless. * | |
SassNumber:: |
constant | * Regx for matching and extracting numbers | ||
SassNumber:: |
public | function |
* Divides this value by the value of other
* Overrides SassLiteral:: |
|
SassNumber:: |
public | function |
* The SassScript == operation.
* Overrides SassLiteral:: |
|
SassNumber:: |
public | function |
* The SassScript > operation.
* Overrides SassLiteral:: |
|
SassNumber:: |
public | function |
* The SassScript >= operation.
* Overrides SassLiteral:: |
|
SassNumber:: |
public | function |
* The SassScript < operation.
* Overrides SassLiteral:: |
|
SassNumber:: |
public | function |
* The SassScript <= operation.
* Overrides SassLiteral:: |
|
SassNumber:: |
public | function |
* Subtracts the value of other from this value
* Overrides SassLiteral:: |
|
SassNumber:: |
public | function |
* Takes the modulus (remainder) of this value divided by the value of other
* Overrides SassLiteral:: |
|
SassNumber:: |
public | function |
* Adds the value of other to the value of this
* Overrides SassLiteral:: |
|
SassNumber:: |
public | function |
* Multiplies this value by the value of other
* Overrides SassLiteral:: |
|
SassNumber:: |
public | function | ||
SassNumber:: |
public | function | * Unary - operator * | |
SassNumber:: |
public | function | * Unary + operator * | |
SassNumber:: |
constant | * The number of decimal digits to round to. * If the units are pixels the result is always * rounded down to the nearest integer. | ||
SassNumber:: |
private | function | * Removes common units from each set. * We don't use array_diff because we want (for eaxmple) mm*mm/mm*cm to * end up as mm/cm. * | |
SassNumber:: |
public | function | * Returns the integer value. * | |
SassNumber:: |
public | function |
* Converts the number to a string with it's units if any.
* If the units are px the result is rounded down to the nearest integer,
* otherwise the result is rounded to the specified precision.
* Overrides SassLiteral:: |
|
SassNumber:: |
constant | |||
SassNumber:: |
public | function | * Returns a string representation of the units. * | |
SassNumber:: |
constant | |||
SassNumber:: |
public | function |
* class constructor.
* Sets the value and units of the number.
* Overrides SassLiteral:: |