From patchwork Thu Oct 6 12:09:12 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zygmunt Krynicki X-Patchwork-Id: 4549 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 7318223F58 for ; Thu, 6 Oct 2011 12:09:17 +0000 (UTC) Received: from mail-gx0-f180.google.com (mail-gx0-f180.google.com [209.85.161.180]) by fiordland.canonical.com (Postfix) with ESMTP id 1DB19A18D18 for ; Thu, 6 Oct 2011 12:09:17 +0000 (UTC) Received: by ggni2 with SMTP id i2so2481164ggn.11 for ; Thu, 06 Oct 2011 05:09:16 -0700 (PDT) Received: by 10.223.75.137 with SMTP id y9mr3223298faj.14.1317902956309; Thu, 06 Oct 2011 05:09:16 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.152.23.170 with SMTP id n10cs126531laf; Thu, 6 Oct 2011 05:09:15 -0700 (PDT) Received: by 10.227.6.199 with SMTP id a7mr890881wba.74.1317902953141; Thu, 06 Oct 2011 05:09:13 -0700 (PDT) Received: from indium.canonical.com (indium.canonical.com. [91.189.90.7]) by mx.google.com with ESMTPS id ev17si3798518wbb.57.2011.10.06.05.09.12 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 06 Oct 2011 05:09:13 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) client-ip=91.189.90.7; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) smtp.mail=bounces@canonical.com Received: from ackee.canonical.com ([91.189.89.26]) by indium.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1RBmlE-0001Np-Ig for ; Thu, 06 Oct 2011 12:09:12 +0000 Received: from ackee.canonical.com (localhost [127.0.0.1]) by ackee.canonical.com (Postfix) with ESMTP id 7F908E09EF for ; Thu, 6 Oct 2011 12:09:12 +0000 (UTC) MIME-Version: 1.0 X-Launchpad-Project: lava-server X-Launchpad-Branch: ~linaro-validation/lava-server/trunk X-Launchpad-Message-Rationale: Subscriber X-Launchpad-Branch-Revision-Number: 250 X-Launchpad-Notification-Type: branch-revision To: Linaro Patch Tracker From: noreply@launchpad.net Subject: [Branch ~linaro-validation/lava-server/trunk] Rev 250: Document how bread crumbs work and how to use them Message-Id: <20111006120912.6390.39172.launchpad@ackee.canonical.com> Date: Thu, 06 Oct 2011 12:09:12 -0000 Reply-To: noreply@launchpad.net Sender: bounces@canonical.com Errors-To: bounces@canonical.com Precedence: bulk X-Generated-By: Launchpad (canonical.com); Revision="14085"; Instance="launchpad-lazr.conf" X-Launchpad-Hash: 4c457bba7911ea07b7adf12827767a001742fc8d ------------------------------------------------------------ revno: 250 committer: Zygmunt Krynicki branch nick: trunk timestamp: Mon 2011-10-03 16:07:55 +0200 message: Document how bread crumbs work and how to use them modified: lava_server/bread_crumbs.py --- lp:lava-server https://code.launchpad.net/~linaro-validation/lava-server/trunk You are subscribed to branch lp:lava-server. To unsubscribe from this branch go to https://code.launchpad.net/~linaro-validation/lava-server/trunk/+edit-subscription === modified file 'lava_server/bread_crumbs.py' --- lava_server/bread_crumbs.py 2011-09-30 13:34:25 +0000 +++ lava_server/bread_crumbs.py 2011-10-03 14:07:55 +0000 @@ -18,7 +18,30 @@ """ -Bread crubm management for LAVA server +Bread crumb management for LAVA server. + +This system allows one to construct static trees of views (come to think about +it it could also be used as a site map generator) where each view has at most +one parent. In such model any view could be followed back through the parent +link to create a bread crumb trail of named URLs. + +It is important to emphasise that this system is STATIC, that is, it is not +based on browsing history. Regardless on how the user got to a particular view +the bread crumb system will report the same set of pages. The idea is not to +let users go back (that's the what the browser allows them to do) but to put +the current page into context of where it "belongs". + +To use this system apply the @BreadCrumb(name, parent=parent_view, +needs=['required', 'keywords']) decorator to your view function. To render +breadcrumbs you can use the default template that is a part of +"layout/content.html" template. Your context must include the bread_crumb_trail +variable. To construct it call BreadCrumbTrail.leading_to(your_view_name, ...) +passing any of the keyword arguments specified in needs of your and any parent +views (yes this is annoying). + +A mistake in paring 'needs' to keywords passed to BreadCrumbTrail.leading_to() +will result in logged warnings (either a name of the URL being not +constructible). To fix that simply add the missing keyword argument and reload. """ from django.core.urlresolvers import reverse @@ -26,8 +49,23 @@ class BreadCrumb(object): + """ + A crumb of bread left in the forest of pages to let you go back to (no, not + to where you came from) where the developer desired you to go. + """ def __init__(self, name, parent=None, needs=None): + """ + Construct a bread crumb object. + + The name is the essential property creating the actual text visible on + web pages. It may be a static string or a new-style python string + template. Parent allows one to construct a static brad crumb tree where + each crubm may have at most one parent. Needs, if specified, must be + an array of strings that denote identifiers required to resolve the URL + of this bread crumb. The identifiers are obtained from the call + BreadCrumbTrail.leading_to(). + """ self.name = name self.view = None self.parent = parent @@ -38,11 +76,23 @@ self.name, self.view, self.parent) def __call__(self, view): + """ + Call method, used when decorating function-based views + + Id does not redefine the function (so is not a real decorator) but + instead stores the bradcrubm object in the _bread_crumb attribute of + the function. + """ self.view = view view._bread_crumb = self return view def get_name(self, kwargs): + """ + Get the name of this crumb. + + The name is formatted with the specfied keyword argments. + """ try: return self.name.format(**kwargs) except: @@ -50,6 +100,14 @@ raise def get_absolute_url(self, kwargs): + """ + Get the URL of this crumb. + + The URL is constructed with a call to dajngo's reverse() function. It + is supplemented with the same variables that were listed in needs array + in the bread crumb constructor. The arguments are passed in order, from + the kwargs dictionary. + """ try: return reverse(self.view, args=[kwargs[name] for name in self.needs]) except: @@ -58,6 +116,16 @@ class LiveBreadCrumb(object): + """ + Bread crumb instance as observed by a particular request. + + It is a binding between the global view-specific bread crumb object and + dynamic request-specific keyword arguments. + + For convenience it provides two bread crumb functions (get_name() and + get_absolute_url()) that automatically provide the correct keyword + arguments. + """ def __init__(self, bread_crumb, kwargs): self.bread_crumb = bread_crumb @@ -71,6 +139,11 @@ class BreadCrumbTrail(object): + """ + A list of live bread crumbs that lead from a particular view, along the + parent chain, all the way to the root view (that is without any parent + view). + """ def __init__(self, bread_crumb_list, kwargs): self.bread_crumb_list = bread_crumb_list @@ -82,6 +155,16 @@ @classmethod def leading_to(cls, view, **kwargs): + """ + Create an instance of BreadCrumbTrail that starts at the specified view. + + Additional keyword arguments, if provided, will be available to + get_name() and get_absolute_url() of each LiveBreadCrumb that makes up + this trail. In practice they should contain a set of arguments that are + needed by any parent bread crumb URL or name. + + TODO: could we check this statically somehow? + """ lst = [] while view is not None: lst.append(view._bread_crumb)