changeset 233:4379d8f8f831

internal: Removing some dependency of filters and iterators on pages.
author Ludovic Chabant <ludovic@chabant.com>
date Wed, 11 Feb 2015 20:36:18 -0800
parents e534d2bc657c
children 1c4078ec3011
files piecrust/data/filters.py piecrust/data/iterators.py tests/test_data_iterators.py
diffstat 3 files changed, 44 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/piecrust/data/filters.py	Wed Feb 11 08:31:36 2015 -0800
+++ b/piecrust/data/filters.py	Wed Feb 11 20:36:18 2015 -0800
@@ -5,8 +5,9 @@
 
 
 class PaginationFilter(object):
-    def __init__(self):
+    def __init__(self, value_accessor=None):
         self.root_clause = None
+        self.value_accessor = value_accessor or self._default_value_accessor
 
     @property
     def is_empty(self):
@@ -23,7 +24,7 @@
     def pageMatches(self, page):
         if self.root_clause is None:
             return True
-        return self.root_clause.pageMatches(page)
+        return self.root_clause.pageMatches(self, page)
 
     def _ensureRootClause(self):
         if self.root_clause is None:
@@ -76,13 +77,19 @@
             else:
                 raise Exception("Unknown filter clause: %s" % key)
 
+    @staticmethod
+    def _default_value_accessor(item, name):
+        try:
+            return getattr(item, name)
+        except AttributeError:
+            return None
 
 
 class IFilterClause(object):
     def addClause(self, clause):
         raise NotImplementedError()
 
-    def pageMatches(self, page):
+    def pageMatches(self, fil, page):
         raise NotImplementedError()
 
 
@@ -96,11 +103,11 @@
                             "child clause.")
         self.child = clause
 
-    def pageMatches(self, page):
+    def pageMatches(self, fil, page):
         if self.child is None:
             raise Exception("'NOT' filtering clauses must have one child "
                             "clause.")
-        return not self.child.pageMatches(page)
+        return not self.child.pageMatches(fil, page)
 
 
 class BooleanClause(IFilterClause):
@@ -112,17 +119,17 @@
 
 
 class AndBooleanClause(BooleanClause):
-    def pageMatches(self, page):
+    def pageMatches(self, fil, page):
         for c in self.clauses:
-            if not c.pageMatches(page):
+            if not c.pageMatches(fil, page):
                 return False
         return True
 
 
 class OrBooleanClause(BooleanClause):
-    def pageMatches(self, page):
+    def pageMatches(self, fil, page):
         for c in self.clauses:
-            if c.pageMatches(page):
+            if c.pageMatches(fil, page):
                 return True
         return False
 
@@ -139,8 +146,8 @@
 
 
 class HasFilterClause(SettingFilterClause):
-    def pageMatches(self, page):
-        actual_value = page.config.get(self.name)
+    def pageMatches(self, fil, page):
+        actual_value = fil.value_accessor(page, self.name)
         if actual_value is None or not isinstance(actual_value, list):
             return False
 
@@ -151,8 +158,8 @@
 
 
 class IsFilterClause(SettingFilterClause):
-    def pageMatches(self, page):
-        actual_value = page.config.get(self.name)
+    def pageMatches(self, fil, page):
+        actual_value = fil.value_accessor(page, self.name)
         if self.coercer:
             actual_value = self.coercer(actual_value)
         return actual_value == self.value
--- a/piecrust/data/iterators.py	Wed Feb 11 08:31:36 2015 -0800
+++ b/piecrust/data/iterators.py	Wed Feb 11 20:36:18 2015 -0800
@@ -46,23 +46,19 @@
 
 
 class SettingFilterIterator(object):
-    def __init__(self, it, fil_conf, page_accessor=None):
+    def __init__(self, it, fil_conf, setting_accessor=None):
         self.it = it
         self.fil_conf = fil_conf
         self._fil = None
-        self.page_accessor = page_accessor
+        self.setting_accessor = setting_accessor
 
     def __iter__(self):
         if self._fil is None:
-            self._fil = PaginationFilter()
+            self._fil = PaginationFilter(self.setting_accessor)
             self._fil.addClausesFromConfig(self.fil_conf)
 
         for i in self.it:
-            if self.page_accessor:
-                page = self.page_accessor(i)
-            else:
-                page = i
-            if self._fil.pageMatches(page):
+            if self._fil.pageMatches(i):
                 yield i
 
 
@@ -174,19 +170,25 @@
         if name[:3] == 'is_' or name[:3] == 'in_':
             def is_filter(value):
                 conf = {'is_%s' % name[3:]: value}
-                return self._simpleNonSortedWrap(SettingFilterIterator, conf)
+                accessor = self._getSettingAccessor()
+                return self._simpleNonSortedWrap(SettingFilterIterator, conf,
+                                                 accessor)
             return is_filter
 
         if name[:4] == 'has_':
             def has_filter(value):
                 conf = {name: value}
-                return self._simpleNonSortedWrap(SettingFilterIterator, conf)
+                accessor = self._getSettingAccessor()
+                return self._simpleNonSortedWrap(SettingFilterIterator, conf,
+                                                 accessor)
             return has_filter
 
         if name[:5] == 'with_':
             def has_filter(value):
                 conf = {'has_%s' % name[5:]: value}
-                return self._simpleNonSortedWrap(SettingFilterIterator, conf)
+                accessor = self._getSettingAccessor()
+                return self._simpleNonSortedWrap(SettingFilterIterator, conf,
+                                                 accessor)
             return has_filter
 
         return self.__getattribute__(name)
@@ -209,15 +211,15 @@
             raise Exception("Couldn't find filter '%s' in the configuration "
                             "header for page: %s" %
                             (filter_name, self._current_page.path))
-        return self._simpleNonSortedWrap(SettingFilterIterator, filter_conf)
+        accessor = self._getSettingAccessor()
+        return self._simpleNonSortedWrap(SettingFilterIterator, filter_conf,
+                                         accessor)
 
     def sort(self, setting_name=None, reverse=False):
         self._ensureUnlocked()
         self._unload()
         if setting_name is not None:
-            accessor = None
-            if isinstance(self._source, IPaginationSource):
-                accessor = self._source.getSettingAccessor()
+            accessor = self._getSettingAccessor()
             self._pages = SettingSortIterator(self._pages, setting_name,
                                               reverse, accessor)
         else:
@@ -253,6 +255,12 @@
         self._pages = it_class(self._pages, *args, **kwargs)
         return self
 
+    def _getSettingAccessor(self):
+        accessor = None
+        if isinstance(self._source, IPaginationSource):
+            accessor = self._source.getSettingAccessor()
+        return accessor
+
     def _ensureUnlocked(self):
         if self._locked:
             raise Exception(
--- a/tests/test_data_iterators.py	Wed Feb 11 08:31:36 2015 -0800
+++ b/tests/test_data_iterators.py	Wed Feb 11 20:36:18 2015 -0800
@@ -46,7 +46,7 @@
 class TestItem(object):
     def __init__(self, value):
         self.name = str(value)
-        self.config = {'foo': value}  # `config` makes it look like a `Page`.
+        self.foo = value
 
     def __eq__(self, other):
         return other.name == self.name