""" .. module:: lesscpy.lessc.scope :synopsis: Scope class. Copyright (c) See LICENSE for details. .. moduleauthor:: Johann T. Mariusson <jtm@robot.is> """ from . import utility class Scope(list): """ Scope class. A stack implementation. """ def __init__(self, init=False): """Scope Args: init (bool): Initiate scope """ super(Scope, self).__init__() self._mixins = {} if init: self.push() self.deferred = False self.real = [] def push(self): """Push level on scope """ self.append({ '__variables__': {}, '__blocks__': [], '__names__': [], '__current__': None }) @property def current(self): return self[-1]['__current__'] @current.setter def current(self, value): self[-1]['__current__'] = value @property def scopename(self): """Current scope name as list Returns: list """ return [r['__current__'] for r in self if r['__current__']] def add_block(self, block): """Add block element to scope Args: block (Block): Block object """ self[-1]['__blocks__'].append(block) self[-1]['__names__'].append(block.raw()) def remove_block(self, block, index="-1"): """Remove block element from scope Args: block (Block): Block object """ self[index]["__blocks__"].remove(block) self[index]["__names__"].remove(block.raw()) def add_mixin(self, mixin): """Add mixin to scope Args: mixin (Mixin): Mixin object """ raw = mixin.tokens[0][0].raw() if raw in self._mixins: self._mixins[raw].append(mixin) else: self._mixins[raw] = [mixin] def add_variable(self, variable): """Add variable to scope Args: variable (Variable): Variable object """ self[-1]['__variables__'][variable.name] = variable def variables(self, name): """Search for variable by name. Searches scope top down Args: name (string): Search term Returns: Variable object OR False """ if isinstance(name, tuple): name = name[0] if name.startswith('@{'): name = '@' + name[2:-1] i = len(self) while i >= 0: i -= 1 if name in self[i]['__variables__']: return self[i]['__variables__'][name] return False def mixins(self, name): """ Search mixins for name. Allow '>' to be ignored. '.a .b()' == '.a > .b()' Args: name (string): Search term Returns: Mixin object list OR False """ m = self._smixins(name) if m: return m return self._smixins(name.replace('?>?', ' ')) def _smixins(self, name): """Inner wrapper to search for mixins by name. """ return (self._mixins[name] if name in self._mixins else False) def blocks(self, name): """ Search for defined blocks recursively. Allow '>' to be ignored. '.a .b' == '.a > .b' Args: name (string): Search term Returns: Block object OR False """ b = self._blocks(name) if b: return b return self._blocks(name.replace('?>?', ' ')) def _blocks(self, name): """Inner wrapper to search for blocks by name. """ i = len(self) while i >= 0: i -= 1 if name in self[i]['__names__']: for b in self[i]['__blocks__']: r = b.raw() if r and r == name: return b else: for b in self[i]['__blocks__']: r = b.raw() if r and name.startswith(r): b = utility.blocksearch(b, name) if b: return b return False def update(self, scope, at=0): """Update scope. Add another scope to this one. Args: scope (Scope): Scope object Kwargs: at (int): Level to update """ if hasattr(scope, '_mixins') and not at: self._mixins.update(scope._mixins) self[at]['__variables__'].update(scope[at]['__variables__']) self[at]['__blocks__'].extend(scope[at]['__blocks__']) self[at]['__names__'].extend(scope[at]['__names__']) def swap(self, name): """ Swap variable name for variable value Args: name (str): Variable name Returns: Variable value (Mixed) """ if name.startswith('@@'): var = self.variables(name[1:]) if var is False: raise SyntaxError('Unknown variable %s' % name) name = '@' + utility.destring(var.value[0]) var = self.variables(name) if var is False: raise SyntaxError('Unknown variable %s' % name) elif name.startswith('@{'): var = self.variables('@' + name[2:-1]) if var is False: raise SyntaxError('Unknown escaped variable %s' % name) try: if isinstance(var.value[0], basestring): # py3 var.value[0] = utility.destring(var.value[0]) except NameError: if isinstance(var.value[0], str): # py2 var.value[0] = utility.destring(var.value[0]) else: var = self.variables(name) if var is False: raise SyntaxError('Unknown variable %s' % name) return var.value