lib/page_tree.py
changeset 16 4a40718c7b4b
child 17 b538e1f7011c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/page_tree.py	Sat Feb 07 02:46:58 2009 +0200
@@ -0,0 +1,210 @@
+"""
+    Implements the tree containing pages and their metadata
+"""
+
+import tree_parse
+
+# path to file containing the page metadata tree
+PAGE_TREE_FILE = "pages/list"
+
+
+class PageInfo (object) :
+    """
+        Contains metainformation about a page
+    """
+
+    def __init__ (self, parent, name, title, children=None) :
+        """
+            Initialize, children defaults to empty list
+        """
+
+        # store
+        self.parent = parent
+        self.name = name
+        self.title = title
+        self.children = children if children else []
+
+        # no url get
+        self._url = None
+    
+    def set_parent (self, parent) :
+        """
+            Set a parent where non was set before
+        """
+
+        assert self.parent is None
+
+        self.parent = parent
+
+    def add_child (self, child) :
+        """
+            Add a PageInfo child
+        """
+
+        self.children.append(child)
+    
+    def get_child (self, name) :
+        """
+            Look up a child by name, returning None if not found
+        """
+
+        return dict((c.name, c) for c in self.children).get(name)
+
+    def get_ancestry (self) :
+        """
+            Returns a list of this page's parents and the page itself, but not root
+        """
+        
+        # collect in reverse order
+        ancestry = []
+        
+        # starting from self
+        item = self
+        
+        # add all items, but not root
+        while item and item.parent :
+            ancestry.append(item)
+
+            item = item.parent
+
+        # reverse
+        ancestry.reverse()
+        
+        # done
+        return ancestry
+
+    @property
+    def url (self) :
+        """
+            Build this page's URL
+        """
+
+        # cached?
+        if self._url :
+            return self._url
+
+        segments = [item.name for item in self.get_ancestry()]
+        
+        # add empty segment if dir
+        if self.children :
+            segments.append('')
+        
+        # join
+        url = '/'.join(segments)
+        
+        # cache
+        self._url = url
+        
+        # done
+        return url
+
+class PageTree (object) :
+    """
+        The tree of pages, rooted at .root.
+
+        Use load_page_tree to initialize the global page_tree instance, and then use that
+    """
+
+    def __init__ (self) :
+        """
+            Empty PageList, must call load_page_list to initialize, once
+        """
+
+    def _load (self, path) :
+        """
+            Processes the lines in the given file
+        """
+        
+        # parse tree
+        tree = tree_parse.parse(path, ':')
+
+        def _create_node (parent, item) :
+            """
+                Creates and returns a PageInfo from the given parent node and (line_number, line, children) tuple item
+            """
+
+            # unpack
+            line_number, line, children = item
+
+            # parse line
+            url, title = line.split(':')
+
+            # remove whitespace
+            url = url.strip()
+            title = title.strip()
+            
+            # create PageInfo
+            node = PageInfo(parent, url, title)
+            
+            # set node children
+            node.children = [
+                _create_node(node, child_item) for child_item in children
+            ]
+
+            # return
+            return node
+        
+        # translate
+        self.root = _create_node(None, tree)
+            
+        # *evil cackle*
+        self.root.children.insert(0, self.root)
+        
+    def get_page (self, url) :
+        """
+            Lookup the given page URL, and return the matching PageInfo object, or None, if not found
+        """
+        
+        # start from root
+        node = self.root
+        
+        # traverse the object tree
+        for segment in url.split('/') :
+            if segment :
+                node = node.get_child(segment)
+
+            if not node :
+                return None
+        
+        # return
+        return node
+    
+    def get_siblings (self, url) :
+        """
+            Get the list of siblings for the given url, including the given page itself
+        """
+        
+        # look up the page itself
+        page = self.get_page(url)
+        
+        # specialcase root/unknown node
+        if page and page.parent :
+            return page.parent.children
+
+        else :
+            return self.root.children
+    
+    def dump (self) :
+        """
+            Returns a string representation of the tree
+        """
+        
+        def _print_node (indent, node) :
+            return '\n'.join('%s%s' % (' '*indent, line) for line in [
+                "%-15s : %s" % (node.name, node.title)
+            ] + [
+                _print_node(indent + 4, child) for child in node.children if child != node
+            ])
+
+        return _print_node(0, self.root)
+
+# global singleton PageList instance
+page_tree = PageTree()
+
+def load () :
+    """
+        Load the global singleton PageInfo instance
+    """
+    
+    page_tree._load(PAGE_TREE_FILE)
+