From 6a8efa934d9a91c0916ecbc6659f275e25858bc6 Mon Sep 17 00:00:00 2001 From: "Eevee (Alex Munroe)" Date: Tue, 26 Aug 2014 18:08:49 -0700 Subject: Partial support for slurpy named arguments. --- scss/compiler.py | 14 +++++++++++--- scss/functions/core.py | 9 ++++++++- scss/src/grammar/grammar.g | 4 ++-- scss/tests/files/general/slurpy-keyword-args.css | 5 +++++ scss/tests/files/general/slurpy-keyword-args.scss | 12 ++++++++++++ scss/types.py | 17 +++++++++++++++++ 6 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 scss/tests/files/general/slurpy-keyword-args.css create mode 100644 scss/tests/files/general/slurpy-keyword-args.scss diff --git a/scss/compiler.py b/scss/compiler.py index 2394258..fa25e7e 100644 --- a/scss/compiler.py +++ b/scss/compiler.py @@ -30,11 +30,12 @@ from scss.rule import SassRule from scss.rule import UnparsedBlock from scss.selector import Selector from scss.source import SourceFile -from scss.types import Number +from scss.types import Arglist from scss.types import Boolean -from scss.types import String from scss.types import List from scss.types import Null +from scss.types import Number +from scss.types import String from scss.types import Undefined from scss.types import Url from scss.util import dequote @@ -518,10 +519,15 @@ class Compilation(object): if callee_argspec.slurp: # Slurpy var gets whatever is left + # TODO should preserve the order of extra kwargs + sass_kwargs = [] + for key, value in kwargs.items(): + sass_kwargs.append((String(key[1:]), value)) callee_namespace.set_variable( callee_argspec.slurp.name, - List(args, use_comma=True)) + Arglist(args, sass_kwargs)) args = [] + kwargs = {} elif callee_argspec.inject: # Callee namespace gets all the extra kwargs whether declared or # not @@ -595,6 +601,8 @@ class Compilation(object): ancestry=rule.ancestry, nested=rule.nested, ) + # TODO supposed to throw an error if there's a slurpy arg + # but keywords() is never called on it try: self.manage_children(_rule, scope) except SassReturn as e: diff --git a/scss/functions/core.py b/scss/functions/core.py index 1f6d30a..1fc830b 100644 --- a/scss/functions/core.py +++ b/scss/functions/core.py @@ -11,7 +11,7 @@ import math from six.moves import xrange from scss.functions.library import FunctionLibrary -from scss.types import Boolean, Color, List, Null, Number, String, Map, expect_type +from scss.types import Arglist, Boolean, Color, List, Null, Number, String, Map, expect_type log = logging.getLogger(__name__) @@ -783,6 +783,13 @@ def comparable(number1, number2): and left.unit_denom == right.unit_denom) +@register('keywords', 1) +def keywords(value): + """Extract named arguments, as a map, from an argument list.""" + expect_type(value, Arglist) + return value.extract_keywords() + + # ------------------------------------------------------------------------------ # Miscellaneous diff --git a/scss/src/grammar/grammar.g b/scss/src/grammar/grammar.g index 870822e..6ef9262 100644 --- a/scss/src/grammar/grammar.g +++ b/scss/src/grammar/grammar.g @@ -52,8 +52,8 @@ parser SassExpression: rule goal_argspec: argspec END {{ return argspec }} # Arguments: - # Note that at the moment, named arguments and slurpy arguments appear to - # be incompatible. + # TODO should support multiple slurpies, and enforce (probably not in the + # parser) that positional args come first rule argspec: [ argspec_items {{ args, slurpy = argspec_items }} diff --git a/scss/tests/files/general/slurpy-keyword-args.css b/scss/tests/files/general/slurpy-keyword-args.css new file mode 100644 index 0000000..ce36647 --- /dev/null +++ b/scss/tests/files/general/slurpy-keyword-args.css @@ -0,0 +1,5 @@ +p { + left: 5px; + right: 10px; + leftovers: red, blue; +} diff --git a/scss/tests/files/general/slurpy-keyword-args.scss b/scss/tests/files/general/slurpy-keyword-args.scss new file mode 100644 index 0000000..87f0b5e --- /dev/null +++ b/scss/tests/files/general/slurpy-keyword-args.scss @@ -0,0 +1,12 @@ +@mixin accepts-basically-anything($args...) { + @each $key, $value in keywords($args) { + #{$key}: $value; + } + @if length($args) { + leftovers: $args; + } +} + +p { + @include accepts-basically-anything(red, blue, $left: 5px, $right: 10px); +} diff --git a/scss/types.py b/scss/types.py index 05973fe..5803b24 100644 --- a/scss/types.py +++ b/scss/types.py @@ -733,6 +733,23 @@ class List(Value): return List([-item for item in self], use_comma=self.use_comma) +class Arglist(List): + """An argument list. Acts mostly like a list, with keyword arguments sort + of tacked on separately, and only accessible via Python (or the Sass + `keywords` function). + """ + sass_type_name = 'arglist' + keywords_retrieved = False + + def __init__(self, args, kwargs): + self._kwargs = Map(kwargs) + super(Arglist, self).__init__(args, use_comma=True) + + def extract_keywords(self): + self.keywords_retrieved = True + return self._kwargs + + def _constrain(value, lb=0, ub=1): """Helper for Color constructors. Constrains a value to a range.""" if value < lb: -- cgit v1.2.1