lib/page_tree.py
changeset 16 4a40718c7b4b
child 17 b538e1f7011c
equal deleted inserted replaced
15:e2fe2baa7910 16:4a40718c7b4b
       
     1 """
       
     2     Implements the tree containing pages and their metadata
       
     3 """
       
     4 
       
     5 import tree_parse
       
     6 
       
     7 # path to file containing the page metadata tree
       
     8 PAGE_TREE_FILE = "pages/list"
       
     9 
       
    10 
       
    11 class PageInfo (object) :
       
    12     """
       
    13         Contains metainformation about a page
       
    14     """
       
    15 
       
    16     def __init__ (self, parent, name, title, children=None) :
       
    17         """
       
    18             Initialize, children defaults to empty list
       
    19         """
       
    20 
       
    21         # store
       
    22         self.parent = parent
       
    23         self.name = name
       
    24         self.title = title
       
    25         self.children = children if children else []
       
    26 
       
    27         # no url get
       
    28         self._url = None
       
    29     
       
    30     def set_parent (self, parent) :
       
    31         """
       
    32             Set a parent where non was set before
       
    33         """
       
    34 
       
    35         assert self.parent is None
       
    36 
       
    37         self.parent = parent
       
    38 
       
    39     def add_child (self, child) :
       
    40         """
       
    41             Add a PageInfo child
       
    42         """
       
    43 
       
    44         self.children.append(child)
       
    45     
       
    46     def get_child (self, name) :
       
    47         """
       
    48             Look up a child by name, returning None if not found
       
    49         """
       
    50 
       
    51         return dict((c.name, c) for c in self.children).get(name)
       
    52 
       
    53     def get_ancestry (self) :
       
    54         """
       
    55             Returns a list of this page's parents and the page itself, but not root
       
    56         """
       
    57         
       
    58         # collect in reverse order
       
    59         ancestry = []
       
    60         
       
    61         # starting from self
       
    62         item = self
       
    63         
       
    64         # add all items, but not root
       
    65         while item and item.parent :
       
    66             ancestry.append(item)
       
    67 
       
    68             item = item.parent
       
    69 
       
    70         # reverse
       
    71         ancestry.reverse()
       
    72         
       
    73         # done
       
    74         return ancestry
       
    75 
       
    76     @property
       
    77     def url (self) :
       
    78         """
       
    79             Build this page's URL
       
    80         """
       
    81 
       
    82         # cached?
       
    83         if self._url :
       
    84             return self._url
       
    85 
       
    86         segments = [item.name for item in self.get_ancestry()]
       
    87         
       
    88         # add empty segment if dir
       
    89         if self.children :
       
    90             segments.append('')
       
    91         
       
    92         # join
       
    93         url = '/'.join(segments)
       
    94         
       
    95         # cache
       
    96         self._url = url
       
    97         
       
    98         # done
       
    99         return url
       
   100 
       
   101 class PageTree (object) :
       
   102     """
       
   103         The tree of pages, rooted at .root.
       
   104 
       
   105         Use load_page_tree to initialize the global page_tree instance, and then use that
       
   106     """
       
   107 
       
   108     def __init__ (self) :
       
   109         """
       
   110             Empty PageList, must call load_page_list to initialize, once
       
   111         """
       
   112 
       
   113     def _load (self, path) :
       
   114         """
       
   115             Processes the lines in the given file
       
   116         """
       
   117         
       
   118         # parse tree
       
   119         tree = tree_parse.parse(path, ':')
       
   120 
       
   121         def _create_node (parent, item) :
       
   122             """
       
   123                 Creates and returns a PageInfo from the given parent node and (line_number, line, children) tuple item
       
   124             """
       
   125 
       
   126             # unpack
       
   127             line_number, line, children = item
       
   128 
       
   129             # parse line
       
   130             url, title = line.split(':')
       
   131 
       
   132             # remove whitespace
       
   133             url = url.strip()
       
   134             title = title.strip()
       
   135             
       
   136             # create PageInfo
       
   137             node = PageInfo(parent, url, title)
       
   138             
       
   139             # set node children
       
   140             node.children = [
       
   141                 _create_node(node, child_item) for child_item in children
       
   142             ]
       
   143 
       
   144             # return
       
   145             return node
       
   146         
       
   147         # translate
       
   148         self.root = _create_node(None, tree)
       
   149             
       
   150         # *evil cackle*
       
   151         self.root.children.insert(0, self.root)
       
   152         
       
   153     def get_page (self, url) :
       
   154         """
       
   155             Lookup the given page URL, and return the matching PageInfo object, or None, if not found
       
   156         """
       
   157         
       
   158         # start from root
       
   159         node = self.root
       
   160         
       
   161         # traverse the object tree
       
   162         for segment in url.split('/') :
       
   163             if segment :
       
   164                 node = node.get_child(segment)
       
   165 
       
   166             if not node :
       
   167                 return None
       
   168         
       
   169         # return
       
   170         return node
       
   171     
       
   172     def get_siblings (self, url) :
       
   173         """
       
   174             Get the list of siblings for the given url, including the given page itself
       
   175         """
       
   176         
       
   177         # look up the page itself
       
   178         page = self.get_page(url)
       
   179         
       
   180         # specialcase root/unknown node
       
   181         if page and page.parent :
       
   182             return page.parent.children
       
   183 
       
   184         else :
       
   185             return self.root.children
       
   186     
       
   187     def dump (self) :
       
   188         """
       
   189             Returns a string representation of the tree
       
   190         """
       
   191         
       
   192         def _print_node (indent, node) :
       
   193             return '\n'.join('%s%s' % (' '*indent, line) for line in [
       
   194                 "%-15s : %s" % (node.name, node.title)
       
   195             ] + [
       
   196                 _print_node(indent + 4, child) for child in node.children if child != node
       
   197             ])
       
   198 
       
   199         return _print_node(0, self.root)
       
   200 
       
   201 # global singleton PageList instance
       
   202 page_tree = PageTree()
       
   203 
       
   204 def load () :
       
   205     """
       
   206         Load the global singleton PageInfo instance
       
   207     """
       
   208     
       
   209     page_tree._load(PAGE_TREE_FILE)
       
   210