--- 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 )