Mercurial > piecrust2
diff piecrust/data/filters.py @ 3:f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
- Serving works, with debug window.
- Baking works, multi-threading, with dependency handling.
- Various things not implemented yet.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 10 Aug 2014 23:43:16 -0700 |
parents | |
children | 474c9882decf |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piecrust/data/filters.py Sun Aug 10 23:43:16 2014 -0700 @@ -0,0 +1,159 @@ +import logging + + +logger = logging.getLogger(__name__) + + +class PaginationFilter(object): + def __init__(self): + self.root_clause = None + + @property + def is_empty(self): + return self.root_clause is None + + def addClause(self, clause): + self._ensureRootClause() + self.root_clause.addClause(clause) + + def addClausesFromConfig(self, config): + self._ensureRootClause() + self._addClausesFromConfigRecursive(config, self.root_clause) + + def pageMatches(self, page): + if self.root_clause is None: + return True + return self.root_clause.pageMatches(page) + + def _ensureRootClause(self): + if self.root_clause is None: + self.root_clause = AndBooleanClause() + + def _addClausesFromConfigRecursive(self, config, parent_clause): + for key, val in config.iteritems(): + if key == 'and': + if not isinstance(val, list) or len(val) == 0: + raise Exception("The given boolean 'AND' filter clause " + "doesn't have an array of child clauses.") + subcl = AndBooleanClause() + parent_clause.addClause(subcl) + for c in val: + self._addClausesFromConfigRecursive(c, subcl) + + elif key == 'or': + if not isinstance(val, list) or len(val) == 0: + raise Exception("The given boolean 'OR' filter clause " + "doesn't have an array of child clauses.") + subcl = OrBooleanClause() + parent_clause.addClause(subcl) + for c in val: + self._addClausesFromConfigRecursive(c, subcl) + + elif key == 'not': + if isinstance(val, list): + if len(val) != 1: + raise Exception("'NOT' filter clauses must have " + "exactly one child clause.") + val = val[0] + subcl = NotClause() + parent_clause.addClause(subcl) + self._addClausesFromConfigRecursive(val, subcl) + + elif key[:4] == 'has_': + setting_name = key[4:] + if isinstance(val, list): + wrappercl = AndBooleanClause() + for c in val: + wrappercl.addClause(HasFilterClause(setting_name, c)) + parent_clause.addClause(wrappercl) + else: + parent_clause.addClause(HasFilterClause(setting_name, val)) + + elif key[:3] == 'is_': + setting_name = key[3:] + parent_clause.addClause(IsFilterClause(setting_name, val)) + + else: + raise Exception("Unknown filter clause: %s" % key) + + + +class IFilterClause(object): + def addClause(self, clause): + raise NotImplementedError() + + def pageMatches(self, page): + raise NotImplementedError() + + +class NotClause(IFilterClause): + def __init__(self): + self.child = None + + def addClause(self, clause): + if self.child is not None: + raise Exception("'NOT' filtering clauses can only have one " + "child clause.") + self.child = clause + + def pageMatches(self, page): + if self.child is None: + raise Exception("'NOT' filtering clauses must have one child " + "clause.") + return not self.child.pageMatches(page) + + +class BooleanClause(IFilterClause): + def __init__(self): + self.clauses = [] + + def addClause(self, clause): + self.clauses.append(clause) + + +class AndBooleanClause(BooleanClause): + def pageMatches(self, page): + for c in self.clauses: + if not c.pageMatches(page): + return False + return True + + +class OrBooleanClause(BooleanClause): + def pageMatches(self, page): + for c in self.clauses: + if c.pageMatches(page): + return True + return False + + +class SettingFilterClause(IFilterClause): + def __init__(self, name, value, coercer=None): + self.name = name + self.value = value + self.coercer = coercer + + def addClause(self, clause): + raise Exception("Setting filter clauses can't have child clauses. " + "Use a boolean filter clause instead.") + + +class HasFilterClause(SettingFilterClause): + def pageMatches(self, page): + actual_value = page.config.get(self.name) + if actual_value is None or not isinstance(actual_value, list): + return False + + if self.coercer: + actual_value = map(self.coercer, actual_value) + + return self.value in actual_value + + +class IsFilterClause(SettingFilterClause): + def pageMatches(self, page): + actual_value = page.config.get(self.name) + if self.coercer: + actual_value = self.coercer(actual_value) + return actual_value == self.value +