From 1bcfb8a13e051fba190bfa07a48120a0e242134c Mon Sep 17 00:00:00 2001 From: "Eevee (Alex Munroe)" Date: Mon, 19 Aug 2013 18:18:15 -0700 Subject: Add e, pow, log, and sqrt functions from Compass. --- scss/functions/compass/helpers.py | 35 ++++++++++++++++++++++++++++ scss/tests/functions/compass/test_helpers.py | 21 ++++++++++++++++- scss/types.py | 22 +++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/scss/functions/compass/helpers.py b/scss/functions/compass/helpers.py index 99e1709..a57616a 100644 --- a/scss/functions/compass/helpers.py +++ b/scss/functions/compass/helpers.py @@ -437,6 +437,41 @@ def opposite_position(p): def pi(): return Number(math.pi) + +@register('e', 0) +def e(): + return Number(math.e) + + +@register('log', 1) +@register('log', 2) +def log(number, base=None): + if not isinstance(number, Number): + raise TypeError("Expected number, got %r" % (number,)) + elif not number.is_unitless: + raise ValueError("Expected unitless number, got %r" % (number,)) + + if base is None: + pass + elif not isinstance(base, Number): + raise TypeError("Expected number, got %r" % (base,)) + elif not base.is_unitless: + raise ValueError("Expected unitless number, got %r" % (base,)) + + if base is None: + ret = math.log(number.value) + else: + ret = math.log(number.value, base.value) + + return Number(ret) + + +@register('pow', 2) +def pow(number, exponent): + return number ** exponent + + +COMPASS_HELPERS_LIBRARY.add(Number.wrap_python_function(math.sqrt), 'sqrt', 1) COMPASS_HELPERS_LIBRARY.add(Number.wrap_python_function(math.sin), 'sin', 1) COMPASS_HELPERS_LIBRARY.add(Number.wrap_python_function(math.cos), 'cos', 1) COMPASS_HELPERS_LIBRARY.add(Number.wrap_python_function(math.tan), 'tan', 1) diff --git a/scss/tests/functions/compass/test_helpers.py b/scss/tests/functions/compass/test_helpers.py index bb5dfd3..0d52956 100644 --- a/scss/tests/functions/compass/test_helpers.py +++ b/scss/tests/functions/compass/test_helpers.py @@ -116,7 +116,26 @@ def test_opposite_position(calc): ## Math -# pi +def test_pi(calc): + assert calc('pi()') == calc('3.141592653589793') + + +def test_e(calc): + assert calc('e()') == calc('2.718281828459045') + + +def test_sqrt(calc): + assert calc('sqrt(9)') == calc('3') + + +def test_log(calc): + assert calc('log(9, 3)') == calc('2') + + +def test_pow(calc): + assert calc('pow(3, 2)') == calc('9') + assert calc('pow(10px, 2) / 1px') == calc('100px') + # sin diff --git a/scss/types.py b/scss/types.py index 2944c71..99ef17c 100644 --- a/scss/types.py +++ b/scss/types.py @@ -301,6 +301,28 @@ class Number(Value): return op(round(left.value, 5), round(right.value, 5)) + def __pow__(self, exp): + if not isinstance(exp, Number): + raise TypeError("Can't raise %r to power %r" % (self, exp)) + if not exp.is_unitless: + raise TypeError("Exponent %r cannot have units" % (exp,)) + + if self.is_unitless: + return Number(self.value ** exp.value) + + # Units can only be exponentiated to integral powers -- what's the + # square root of 'px'? (Well, it's sqrt(px), but supporting that is + # a bit out of scope.) + if exp.value != int(exp.value): + raise ValueError("Can't raise units of %r to non-integral power %r" % (self, exp)) + + return Number( + self.value ** int(exp.value), + unit_numer=self.unit_numer * int(exp.value), + unit_denom=self.unit_denom * int(exp.value), + ) + + def __mul__(self, other): if not isinstance(other, Number): return NotImplemented -- cgit v1.2.1