[Grok-dev] a "skin" keyword argument to view.url() method

Christian Klinger cklinger at novareto.de
Tue Nov 20 11:44:19 UTC 2012


Hi JW,

+1 implementation looks ok.

Cheers Christian

Jan-Jaap Driessen schrieb:
> This is very useful to me too, but hey, we share a desk :)
>
> +1
>
>
> On Tue, Nov 20, 2012 at 11:33 AM, Jan-Wijbrand Kolman
> <janwijbrand at gmail.com <mailto:janwijbrand at gmail.com>> wrote:
>
>     Hi,
>
>     In the application we develop we regularly need to compute URLs for a
>     specific skin. We have some helper functions for that, but I guess
>     having this functionality as part of the ``view.url()`` method could be
>     generally useful.
>
>     Below you will find a diff between the current grokcore.view trunk and
>     the jw-urls-with-skin branch I created to implement this feature.
>
>     Please tell me if you think this feature is indeed generally useful and
>     whether you'd agree with my implementation. Thx!
>
>     regards, jw
>
>
>     Index: src/grokcore/view/util.py
>     ===================================================================
>     --- src/grokcore/view/util.py   (.../trunk)     (revision 128365)
>     +++ src/grokcore/view/util.py   (.../branches/jw-urls-with-skin)
>         (revision
>     128365)
>     @@ -14,18 +14,37 @@
>     """Grok utility functions.
>     """
>       import urllib
>     +import urlparse
>       from grokcore.security.util import check_permission
>       from zope.component import getMultiAdapter
>       from zope.security.checker import NamesChecker, defineChecker
>       from zope.traversing.browser.absoluteurl import _safe as
>     SAFE_URL_CHARACTERS
>       from zope.traversing.browser.interfaces import IAbsoluteURL
>
>     +import directive
>
>     -def url(request, obj, name=None, data=None):
>     +ASIS = object()
>     +
>     +def url(request, obj, name=None, skin=ASIS, data=None):
>           url = getMultiAdapter((obj, request), IAbsoluteURL)()
>           if name is not None:
>               url += '/' + urllib.quote(name.encode('utf-8'),
>     SAFE_URL_CHARACTERS)
>
>     +    if skin is not ASIS:
>     +        # Remove whatever ``++skin++[name]`` is active.
>     +        parts = list(urlparse.urlparse(url))
>     +        path = parts[2]
>     +        if path.startswith('/++skin++'):
>     +            # Find next / in the path.
>     +            idx = path.find('/', 1)
>     +            path = path[idx:]
>     +        if skin is not None:
>     +            # If a skin is set, add ``++skin++`` as the leading path
>     segment.
>     +            name = directive.skin.bind().get(skin)
>     +            path = '/++skin++%s%s' % (name, path)
>     +        parts[2] = path
>     +        url = urlparse.urlunparse(parts)
>     +
>           if not data:
>               return url
>
>     Index: src/grokcore/view/ftests/url/url.py
>     ===================================================================
>     --- src/grokcore/view/ftests/url/url.py (.../trunk)     (revision
>     128365)
>     +++ src/grokcore/view/ftests/url/url.py
>     (.../branches/jw-urls-with-skin)        (revision 128365)
>     @@ -171,6 +171,45 @@
>      >>> browser.contents
>     '11'
>
>     +It is possible to compute URLs for specific skin names.
>     +
>     +First show how a view registered for a view, will by default
>     compute URLs
>     +for that skin:
>     +
>     + >>>
>     browser.open('http://127.0.0.1/++skin++urltesting/herd/manfred/@@test')
>     + >>> browser.contents
>     + "I'm on a url testing skin:
>     + http://127.0.0.1/++skin++urltesting/herd/manfred/test"
>     +
>     +We get the views manually so we can do a greater variety of url()
>     calls:
>     +
>     + >>> from zope.publisher.browser import applySkin
>     + >>> request = TestRequest()
>     + >>> applySkin(request, URLTestingSkin)
>     + >>> # Shifting names normally happens during URL traversal.
>     + >>> request._traversed_names = ['++skin++urltesting']
>     + >>> request.shiftNameToApplication()
>     + >>> index_view = component.getMultiAdapter((manfred, request),
>     name='test')
>     + >>> index_view.url()
>     + 'http://127.0.0.1/++skin++urltesting/herd/manfred/test'
>     +
>     +Explicitely remove the skin part:
>     +
>     + >>> index_view.url(skin=None)
>     + 'http://127.0.0.1/herd/manfred/test'
>     +
>     +Use another skin:
>     +
>     + >>> index_view.url(skin=AnotherURLTestingSkin)
>     + 'http://127.0.0.1/++skin++anotherurltesting/herd/manfred/test'
>     +
>     +Use something that is not a skin will fail:
>     +
>     + >>> index_view.url(skin='foobar')
>     +  Traceback (most recent call last):
>     +  ...
>     +  AttributeError: 'str' object has no attribute 'queryTaggedValue'
>     +
>     """
>       import grokcore.view as grok
>       from zope.container.contained import Contained
>     @@ -199,3 +238,16 @@
>               return unicode(self.age * 2)
>
>       yetanother = grok.PageTemplate('<p tal:replace="view/url" />')
>     +
>     +class URLTestingSkin(grok.IBrowserRequest):
>     +    grok.skin('urltesting')
>     +
>     +class AnotherURLTestingSkin(grok.IBrowserRequest):
>     +    grok.skin('anotherurltesting')
>     +
>     +class URLTestingViewOnASkin(grok.View):
>     +    grok.layer(URLTestingSkin)
>     + grok.name <http://grok.name>('test')
>     +
>     +    def render(self):
>     +        return u"I'm on a url testing skin: %s" % self.url()
>     Index: src/grokcore/view/components.py
>     ===================================================================
>     --- src/grokcore/view/components.py     (.../trunk)     (revision
>     128365)
>     +++ src/grokcore/view/components.py     (.../branches/jw-urls-with-skin)
>     (revision 128365)
>     @@ -78,7 +78,7 @@
>               return self.request.response.redirect(
>                   url, status=status, trusted=trusted)
>
>     -    def url(self, obj=None, name=None, data=None):
>     +    def url(self, obj=None, name=None, skin=util.ASIS, data=None):
>     """Return string for the URL based on the obj and name.
>
>               If no arguments given, construct URL to view itself.
>     @@ -91,6 +91,16 @@
>               If both object and name arguments are supplied, construct URL
>               to `obj/name`.
>
>     +        Optionally pass a `skin` keyword argument. This should be a
>     +        skin component and the skin's name is taken from this
>     +        component. The effect of this argument is a leading
>     +        ``++skin++[skinname]/`` segment in the path-part of the URL.
>     +        When the argument is not passed, whatever skin is currently set
>     +        on the request will be effective in the URL.
>     +
>     +        When passing ``None`` whatever skin is currently effective will
>     +        be removed from the URLs.
>     +
>               Optionally pass a `data` keyword argument which gets added to
>               the URL as a CGI query string.
>
>     @@ -110,7 +120,7 @@
>                   # create URL to view on context
>                   obj = self.context
>
>     -        return util.url(self.request, obj, name, data)
>     +        return util.url(self.request, obj, name, skin, data)
>
>
>     _______________________________________________
>     Grok-dev mailing list
>     Grok-dev at zope.org <mailto:Grok-dev at zope.org>
>     https://mail.zope.org/mailman/listinfo/grok-dev
>
>
> _______________________________________________
> Grok-dev mailing list
> Grok-dev at zope.org
> https://mail.zope.org/mailman/listinfo/grok-dev



More information about the Grok-dev mailing list