URLTree works, apart from trailing default values sites
authorTero Marttila <terom@fixme.fi>
Sat, 07 Feb 2009 20:34:07 +0200
branchsites
changeset 37 1f13c384508e
parent 36 02d4040d5946
child 38 9737b6ca2295
URLTree works, apart from trailing default values
sites/irclogs.qmsk.net/urls.py
--- a/sites/irclogs.qmsk.net/urls.py	Sat Feb 07 20:05:57 2009 +0200
+++ b/sites/irclogs.qmsk.net/urls.py	Sat Feb 07 20:34:07 2009 +0200
@@ -4,6 +4,7 @@
 """
 
 import re
+import os.path
 
 # our own handlers
 import handlers
@@ -18,6 +19,25 @@
 
     pass
 
+class LabelValue (object) :
+    """
+        Represents the value of a ValueLabel...
+    """
+
+    def __init__ (self, label, value) :
+        """
+            Just store
+        """
+
+        self.label = label
+        self.value = value
+    
+    def __str__ (self) :
+        return "%s=%s" % (self.label.key, self.value)
+
+    def __repr__ (self) :
+        return "<%s>" % self
+
 class Label (object) :
     """
         Base class for URL labels (i.e. the segments of the URL between /s)
@@ -54,7 +74,14 @@
 
         # invalid
         raise URLError("Invalid label: %r" % (mask, ))
+    
+    def match (self, value) :
+        """
+            Match this label against the given value, returning either True to match without a value, a LabelValue
+            object, or boolean false to not match
+        """
 
+        abstract
 
 class EmptyLabel (Label) :
     """
@@ -68,6 +95,14 @@
 
         return isinstance(other, EmptyLabel)
     
+    def match (self, value) :
+        """
+            Match empty string -> True
+        """
+
+        if value == '' :
+            return True
+
     def __str__ (self) :
         return ''
 
@@ -92,12 +127,22 @@
 
         return isinstance(other, StaticLabel) and self.name == other.name
     
+    def match (self, value) :
+        """
+            Match exactly -> True
+        """
+
+        if value == self.name :
+            return True
+
     def __str__ (self) :
         return self.name
 
 class ValueLabel (Label) :
     """
         A label with a key and a value
+
+        XXX: do we even need this?
     """
 
     def __init__ (self, key, default) :
@@ -129,6 +174,15 @@
 
         super(SimpleValueLabel, self).__init__(key, default)
     
+    def match (self, value) :
+        """
+            Match -> LabelValue
+
+            XXX: empty string?
+        """
+
+        return LabelValue(self, value)
+
     def __str__ (self) :
         if self.default :
             return '{%s=%s}' % (self.key, self.default)
@@ -162,13 +216,21 @@
         # copy self.label_path
         return list(self.label_path)
 
-    def execute (self, request, xxx) :
+    def execute (self, request, label_values) :
         """
-            Invoke the handler with the correct parameters
+            Invoke the handler, using the given label values
         """
+        
+        # start with the defaults
+        kwargs = self.defaults()
 
-        xxx
-    
+        # then add all the values
+        for label_value in label_values :
+            kwargs[label_value.label.key] = label_value.value
+            
+        # execute the handler
+        return self.handler(request, **kwargs)
+
     def __str__ (self) :
         return '/'.join(str(label) for label in self.label_path)
     
@@ -250,60 +312,60 @@
             # recurse to handle the rest of the label_path
             child.add_url(url, label_path)
     
-    def match_label (self, label) :
+    def match (self, label_path) :
         """
-            Match our label mask against the given label value.
-
-            Returns either False (no match), True (matched, no value) or a (key, value) pair.
-        """
-
-        # simple mask
-        if self.label.beginswith('{') and self.label.endswith('}') :
-            value_name = self.label.strip('{}')
+            Locate the URL object corresponding to the given label_path value under this node.
 
-            return (value_name, label)
-        
-        # literal mask
-        elif self.label == label :
-            return True
-
-        else :  
-            return False
-
-    def match (self, path, label_path) :
-        """
-            Locate the URL object corresponding to the given label_path value under this node, with the given path
-            containing the previously matched label values
+            Returns a (url, label_values) tuple
         """
 
         # empty label_path?
-        if not label_path or not label_path[0] :
-            # we wanted this node
+        if not label_path or label_path[0] == '' :
+            # the search ends at this node
             if self.url :
                 # this URL is the best match
-                return [self]
-            
-            elif self.children :
-                # continue testing our children
-                label = None
+                return (self.url, [])
             
             else :
                 # incomplete URL
-                raise URLError(url, "no URL handler defined for this Node")
+                raise URLError("no URL handler defined for this Node")
         
         else :
-            # pop our child label from the label path
+            # pop the next label from the label path
             label = label_path.pop(0)
 
-            # build a list of matching children
-            matches = []
+            # return one match...
+            match = value = None
 
             # recurse through our children
             for child in self.children :
-                matches.append(child.match(label_path))
+                # match value
+                value = child.label.match(label)
 
-            # return the list of matching children
-            return matches
+                # skip those that don't match at all
+                if not value :
+                    continue;
+                
+                # already found a match? :/
+                if match :
+                    raise URLError("Ambiguous URL")
+
+                # ok, but continue looking to make sure there's no ambiguous URLs
+                match = child
+            
+            # found something?
+            if not match :
+                raise URLError("No child found for label")
+
+            # ok, recurse into the match
+            url, label_value = match.match(label_path)
+
+            # add our value?
+            if isinstance(value, LabelValue) :
+                label_value.append(value)
+
+            # return the match
+            return url, label_value
     
     def dump (self, indent=0) :
         """
@@ -355,17 +417,23 @@
         
     def match (self, url) :
         """
-            Returns the URL object best corresponding to the given url
+            Find the URL object best corresponding to the given url, matching any ValueLabels.
+
+            Returns an (URL, [LabelValue]) tuple.
         """
 
         # normalize the URL
         url = os.path.normpath(url)
 
         # split it into labels
-        label_path = url.split('/')
+        path = url.split('/')
+
+        # ensure that it starts with a /
+        root_label = path.pop(0)
+        assert self.root.label.match(root_label), "URL must begin with root"
 
         # just match starting at root
-        return self.root.match(label_path)
+        return self.root.match(path)
 
     def handle_request (self, request) :
         """
@@ -373,12 +441,10 @@
         """
         
         # get the request's URL path
-        url = self.match(request.get_page_name())
-
-        # XXX: figure out the argument values...
+        url, label_values = self.match(request.get_page_name())
 
         # let the URL handle it
-        url.execute(request, xxx)
+        url.execute(request, label_values)
 
 # urls
 index           = URL(  '/',                                            handlers.index                                          )