vregistry.py
branchtls-sprint
changeset 630 66ff0b2f7d03
parent 615 38bc11ac845b
child 631 99f5852f8604
--- a/vregistry.py	Mon Feb 16 14:18:13 2009 +0100
+++ b/vregistry.py	Mon Feb 16 16:24:24 2009 +0100
@@ -543,3 +543,65 @@
         return 0
     return selector
 
+
+# selector base classes and operations ########################################
+class Selector(object):
+    """base class for selector classes providing implementation
+    for operators ``&`` and ``|``
+
+    This class is only here to give access to binary operators, the
+    selector logic itself should be implemented in the __call__ method
+    """
+    def __init__(self, *selectors):
+        self.selectors = self.merge_selectors(selectors)
+
+    @classmethod
+    def merge_selectors(cls, selectors):
+        """merge selectors when possible :
+
+        AndSelector(AndSelector(sel1, sel2), AndSelector(sel3, sel4))
+        ==> AndSelector(sel1, sel2, sel3, sel4)
+        """
+        merged_selectors = []
+        for selector in selectors:
+            if isinstance(selector, cls):
+                merged_selectors += selector.selectors
+            else:
+                merged_selectors.append(selector)
+        return merged_selectors
+        
+    def __and__(self, other):
+        return AndSelector(self, other)
+
+    def __or__(self, other):
+        return OrSelector(self, other)
+
+    __ror__ = __or__    # for cases like (function | selector)
+    __rand__ = __and__  # for cases like (function & selector)
+    # XXX (function | function) or (function & function) not managed yet
+
+    def __call__(self, cls, *args, **kwargs):
+        return NotImplementedError("selector %s must implement its logic "
+                                   "in its __call__ method" % self.__class__.__name__)
+
+
+class AndSelector(Selector):
+    """and-chained selectors (formerly known as chainall)"""
+    def __call__(self, cls, *args, **kwargs):
+        score = 0
+        for selector in self.selectors:
+            partscore = selector(cls, *args, **kwargs)
+            if not partscore:
+                return 0
+            score += partscore
+        return score
+
+
+class OrSelector(Selector):
+    """or-chained selectors (formerly known as chainfirst)"""
+    def __call__(self, cls, *args, **kwargs):
+        for selector in self.selectors:
+            partscore = selector(cls, *args, **kwargs)
+            if partscore:
+                return partscore
+        return 0