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
+