[Checkins] SVN: lovely.skinbrowser/trunk/src/lovely/skinbrowser/ Initial checkin of the Skin Browser APIDOC module.

Stephan Richter srichter at cosmos.phy.tufts.edu
Wed Sep 20 08:17:14 EDT 2006


Log message for revision 70255:
  Initial checkin of the Skin Browser APIDOC module.
  
  Th Skin Browser module allows you to discover views, pages, content 
  providers, viewlet managers and viewlets on a per skin, per object 
  interface basis. I'll note that the usefulness of this API module 
  depends on following Lovely Systems way on doing views, namely using 
  viewlets, no macros, and z3c.viewtemplate.
  
  We use this tool as a visual interface between template and view code 
  developers.
  
  I have not yet written tests for this code, since it is just a proof of 
  concept.
  
  

Changed:
  A   lovely.skinbrowser/trunk/src/lovely/skinbrowser/
  A   lovely.skinbrowser/trunk/src/lovely/skinbrowser/SETUP.cfg
  A   lovely.skinbrowser/trunk/src/lovely/skinbrowser/__init__.py
  A   lovely.skinbrowser/trunk/src/lovely/skinbrowser/browser.py
  A   lovely.skinbrowser/trunk/src/lovely/skinbrowser/configure.zcml
  A   lovely.skinbrowser/trunk/src/lovely/skinbrowser/error.pt
  A   lovely.skinbrowser/trunk/src/lovely/skinbrowser/lovely.skinbrowser-configure.zcml
  A   lovely.skinbrowser/trunk/src/lovely/skinbrowser/menu.pt
  A   lovely.skinbrowser/trunk/src/lovely/skinbrowser/menu.py
  A   lovely.skinbrowser/trunk/src/lovely/skinbrowser/module.py
  A   lovely.skinbrowser/trunk/src/lovely/skinbrowser/validator.py
  A   lovely.skinbrowser/trunk/src/lovely/skinbrowser/view.pt
  A   lovely.skinbrowser/trunk/src/lovely/skinbrowser/warning.pt

-=-
Added: lovely.skinbrowser/trunk/src/lovely/skinbrowser/SETUP.cfg
===================================================================
--- lovely.skinbrowser/trunk/src/lovely/skinbrowser/SETUP.cfg	2006-09-20 11:57:05 UTC (rev 70254)
+++ lovely.skinbrowser/trunk/src/lovely/skinbrowser/SETUP.cfg	2006-09-20 12:17:14 UTC (rev 70255)
@@ -0,0 +1,3 @@
+<data-files zopeskel/etc/package-includes>
+  lovely.skinbrowser-*.zcml
+</data-files>

Added: lovely.skinbrowser/trunk/src/lovely/skinbrowser/__init__.py
===================================================================
--- lovely.skinbrowser/trunk/src/lovely/skinbrowser/__init__.py	2006-09-20 11:57:05 UTC (rev 70254)
+++ lovely.skinbrowser/trunk/src/lovely/skinbrowser/__init__.py	2006-09-20 12:17:14 UTC (rev 70255)
@@ -0,0 +1 @@
+# Make a package.


Property changes on: lovely.skinbrowser/trunk/src/lovely/skinbrowser/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: lovely.skinbrowser/trunk/src/lovely/skinbrowser/browser.py
===================================================================
--- lovely.skinbrowser/trunk/src/lovely/skinbrowser/browser.py	2006-09-20 11:57:05 UTC (rev 70254)
+++ lovely.skinbrowser/trunk/src/lovely/skinbrowser/browser.py	2006-09-20 12:17:14 UTC (rev 70255)
@@ -0,0 +1,140 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Browser Views for Skin Browser
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+import inspect
+import zope.interface
+from zope.app.apidoc import component, interface, presentation, utilities
+from zope.app.apidoc.ifacemodule.browser import InterfaceDetails
+from zope.configuration.xmlconfig import ParserInfo
+from zope.security import proxy
+
+
+class TemplateDetails(object):
+    """View class for a Template."""
+
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+
+    @property
+    def macro(self):
+        return self.context.macro
+
+    @property
+    def filename(self):
+        file = self.context.filename
+        return {'file': utilities.relativizePath(file),
+                'url': utilities.truncateSysPath(file).replace('\\', '/')}
+
+    @property
+    def contentType(self):
+        return self.context.contentType
+
+    def fileInfo(self):
+        """Get the file where the directive was declared."""
+        info = proxy.removeSecurityProxy(self.context.reg).info
+        if proxy.isinstance(info, ParserInfo):
+            return component.getParserInfoInfoDictionary(info)
+        return None
+
+    def permission(self):
+        """Get the permission to access the view."""
+        reg = proxy.removeSecurityProxy(self.context.reg)
+        perms = utilities.getPermissionIds('publishTraverse', klass=reg.factory)
+        return perms['read_perm']
+
+    def validationMessages(self):
+        return [
+            zope.component.getMultiAdapter(
+                (message, self.request), name='listitem')
+            for message in self.context.validate()]
+
+
+class ViewDetails(object):
+    """View class for a View."""
+
+    # Attributes that are always available can be ignored here.
+    excludeAttrs = ('__parent__', '__name__', 'context', 'request',
+                    'browserDefault', 'publishTraverse',
+                    'update', 'render', '__call__')
+
+    def viewTemplate(self):
+        if self.context.template:
+            return TemplateDetails(self.context.template, self.request)
+
+    def fileInfo(self):
+        """Get the file where the directive was declared."""
+        info = proxy.removeSecurityProxy(self.context.reg).info
+        if proxy.isinstance(info, ParserInfo):
+            return component.getParserInfoInfoDictionary(info)
+        return None
+
+    def factory(self):
+        """Get factory info"""
+        reg = proxy.removeSecurityProxy(self.context.reg)
+        return presentation.getViewFactoryData(reg.factory)
+
+    def permission(self):
+        """Get the permission to access the view."""
+        reg = proxy.removeSecurityProxy(self.context.reg)
+        perms = utilities.getPermissionIds('publishTraverse', klass=reg.factory)
+        return perms['read_perm']
+
+    def doc(self):
+        reg = proxy.removeSecurityProxy(self.context.reg)
+        factory = component.getRealFactory(reg.factory)
+        if factory.__doc__:
+            return utilities.renderText(
+                factory.__doc__, inspect.getmodule(factory))
+        ifaces = tuple(zope.interface.implementedBy(factory).interfaces())
+        if ifaces[0].__doc__:
+            iface = ifaces[0]
+            return utilities.renderText(iface.__doc__, inspect.getmodule(iface))
+
+    @property
+    def iface(self):
+        reg = proxy.removeSecurityProxy(self.context.reg)
+        factory = component.getRealFactory(reg.factory)
+        implements = zope.interface.implementedBy(factory)
+        return zope.interface.interface.InterfaceClass(
+            'ITemporary', bases=tuple(implements.interfaces()))
+
+    def getAttributes(self):
+        """Return a list of attributes in the order they were specified."""
+        return [interface.getAttributeInfoDictionary(attr)
+                for name, attr in interface.getAttributes(self.iface)
+                if name not in self.excludeAttrs]
+
+    def getMethods(self):
+        """Return a list of methods in the order they were specified."""
+        return [interface.getMethodInfoDictionary(method)
+                for name, method in interface.getMethods(self.iface)
+                if name not in self.excludeAttrs]
+
+    def getFields(self):
+        r"""Return a list of fields in required + alphabetical order.
+
+        The required attributes are listed first, then the optional
+        attributes."""
+        # Make sure that the required fields are shown first
+        sorter = lambda x, y: cmp((not x[1].required, x[0].lower()),
+                                  (not y[1].required, y[0].lower()))
+        return [
+            interface.getFieldInfoDictionary(field)
+            for name, field in interface.getFieldsInOrder(self.iface, sorter)
+            if name not in self.excludeAttrs]


Property changes on: lovely.skinbrowser/trunk/src/lovely/skinbrowser/browser.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: lovely.skinbrowser/trunk/src/lovely/skinbrowser/configure.zcml
===================================================================
--- lovely.skinbrowser/trunk/src/lovely/skinbrowser/configure.zcml	2006-09-20 11:57:05 UTC (rev 70254)
+++ lovely.skinbrowser/trunk/src/lovely/skinbrowser/configure.zcml	2006-09-20 12:17:14 UTC (rev 70255)
@@ -0,0 +1,83 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    xmlns:zcml="http://namespaces.zope.org/zcml"
+    zcml:condition="have devmode">
+
+  <class class=".module.SkinBrowserModule">
+    <allow interface="zope.app.apidoc.interfaces.IDocumentationModule" />
+    <allow interface="zope.app.container.interfaces.IReadContainer" />
+  </class>
+
+  <class class=".module.Skin">
+    <allow interface="zope.app.container.interfaces.IReadContainer"
+           attributes="interface" />
+  </class>
+
+  <class class=".module.Component">
+    <allow interface="zope.app.container.interfaces.IReadContainer"
+           attributes="spec" />
+  </class>
+
+  <class class=".module.View">
+    <allow attributes="reg title template" />
+  </class>
+
+  <class class=".module.Template">
+    <allow attributes="reg filename macro contentType validate" />
+  </class>
+
+  <utility
+      provides="zope.app.apidoc.interfaces.IDocumentationModule"
+      factory=".module.SkinBrowserModule"
+      name="SkinBrowser" />
+
+  <browser:page
+      for=".module.SkinBrowserModule"
+      permission="zope.app.apidoc.UseAPIDoc"
+      class=".menu.Menu"
+      name="menu.html"
+      template="menu.pt"
+      layer="zope.app.apidoc.browser.skin.apidoc"
+      />
+
+  <browser:page
+      for=".module.View"
+      class=".browser.ViewDetails"
+      permission="zope.app.apidoc.UseAPIDoc"
+      name="index.html"
+      template="view.pt"
+      layer="zope.app.apidoc.browser.skin.apidoc"
+      />
+
+  <!-- Validation Stuff -->
+
+  <class class=".validator.FieldMissing">
+    <allow attributes="title description expression line column variable" />
+  </class>
+
+  <class class=".validator.InterfaceFieldMissing">
+    <allow attributes="title description expression line column variable" />
+  </class>
+
+  <class class=".validator.ContextDirectlyUsed">
+    <allow attributes="title description expression line column variable" />
+  </class>
+
+  <browser:page
+      for=".validator.ValidationWarning"
+      permission="zope.app.apidoc.UseAPIDoc"
+      name="listitem"
+      template="warning.pt"
+      layer="zope.app.apidoc.browser.skin.apidoc"
+      />
+
+  <browser:page
+      for=".validator.ValidationError"
+      permission="zope.app.apidoc.UseAPIDoc"
+      name="listitem"
+      template="error.pt"
+      layer="zope.app.apidoc.browser.skin.apidoc"
+      />
+
+</configure>


Property changes on: lovely.skinbrowser/trunk/src/lovely/skinbrowser/configure.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.skinbrowser/trunk/src/lovely/skinbrowser/error.pt
===================================================================
--- lovely.skinbrowser/trunk/src/lovely/skinbrowser/error.pt	2006-09-20 11:57:05 UTC (rev 70254)
+++ lovely.skinbrowser/trunk/src/lovely/skinbrowser/error.pt	2006-09-20 12:17:14 UTC (rev 70255)
@@ -0,0 +1,6 @@
+<li class="warning" style="color: red">
+  <b>ERROR</b> - <span tal:content="context/title" />
+  (line <span tal:replace="context/line" />,
+   column <span tal:replace="context/column" />) :
+  <span tal:replace="context/expression" />
+</li>


Property changes on: lovely.skinbrowser/trunk/src/lovely/skinbrowser/error.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.skinbrowser/trunk/src/lovely/skinbrowser/lovely.skinbrowser-configure.zcml
===================================================================
--- lovely.skinbrowser/trunk/src/lovely/skinbrowser/lovely.skinbrowser-configure.zcml	2006-09-20 11:57:05 UTC (rev 70254)
+++ lovely.skinbrowser/trunk/src/lovely/skinbrowser/lovely.skinbrowser-configure.zcml	2006-09-20 12:17:14 UTC (rev 70255)
@@ -0,0 +1 @@
+<include package="lovely.skinbrowser" />


Property changes on: lovely.skinbrowser/trunk/src/lovely/skinbrowser/lovely.skinbrowser-configure.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.skinbrowser/trunk/src/lovely/skinbrowser/menu.pt
===================================================================
--- lovely.skinbrowser/trunk/src/lovely/skinbrowser/menu.pt	2006-09-20 11:57:05 UTC (rev 70254)
+++ lovely.skinbrowser/trunk/src/lovely/skinbrowser/menu.pt	2006-09-20 12:17:14 UTC (rev 70255)
@@ -0,0 +1,5 @@
+<html metal:use-macro="views/apidoc_macros/menu">
+<body>
+
+</body>
+</html>


Property changes on: lovely.skinbrowser/trunk/src/lovely/skinbrowser/menu.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.skinbrowser/trunk/src/lovely/skinbrowser/menu.py
===================================================================
--- lovely.skinbrowser/trunk/src/lovely/skinbrowser/menu.py	2006-09-20 11:57:05 UTC (rev 70254)
+++ lovely.skinbrowser/trunk/src/lovely/skinbrowser/menu.py	2006-09-20 12:17:14 UTC (rev 70255)
@@ -0,0 +1,44 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Browser Views for Skin Browser
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+from zope.app import zapi
+from zope.app.apidoc import component, utilities
+from zope.traversing import api, browser
+
+from lovely.skinbrowser import module
+
+class Menu(object):
+    """Menu View Helper Class"""
+
+    def getMenuTitle(self, node):
+        """Return the title of the node that is displayed in the menu."""
+        if zapi.isinstance(node.context, module.View):
+            return node.context.title
+        return api.getName(node.context)
+
+    def getMenuLink(self, node):
+        """Return the HTML link of the node that is displayed in the menu."""
+        obj = node.context
+        if zapi.isinstance(obj, module.Skin):
+            return '../Interface/%s/index.html' %api.getName(obj)
+        elif zapi.isinstance(obj, module.Component):
+            path = utilities.getPythonPath(obj.spec)
+            return '../Interface/%s/index.html' %path
+        elif zapi.isinstance(obj, module.View):
+            return browser.absoluteURL(obj, self.request)
+


Property changes on: lovely.skinbrowser/trunk/src/lovely/skinbrowser/menu.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: lovely.skinbrowser/trunk/src/lovely/skinbrowser/module.py
===================================================================
--- lovely.skinbrowser/trunk/src/lovely/skinbrowser/module.py	2006-09-20 11:57:05 UTC (rev 70254)
+++ lovely.skinbrowser/trunk/src/lovely/skinbrowser/module.py	2006-09-20 12:17:14 UTC (rev 70255)
@@ -0,0 +1,216 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Skin Browser Module
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+import zope.component
+import zope.interface
+import zope.location
+
+from zope.app.i18n import ZopeMessageFactory as _
+from zope.app.apidoc.interfaces import IDocumentationModule
+from zope.app.apidoc import component, utilities
+from zope.contentprovider.interfaces import IContentProvider
+from zope.pagetemplate.interfaces import IPageTemplate
+from zope.viewlet.interfaces import IViewlet, IViewletManager
+
+from zope.publisher.interfaces.browser import IBrowserSkinType
+from z3c.viewtemplate.interfaces import ITemplatedContentProvider
+
+from lovely.skinbrowser import validator
+
+
+def getViewPrefix(reg):
+    factory = component.getRealFactory(reg.factory)
+    if reg.name.endswith('html'):
+        return u'Page'
+    elif len(reg.required) == 3 and IViewletManager.implementedBy(factory):
+        return u'Manager'
+    elif len(reg.required) == 3 and IContentProvider.implementedBy(factory):
+        return u'Provider'
+    elif len(reg.required) == 4 and IViewlet.implementedBy(factory):
+        return u'Viewlet'
+    else:
+        return u'View'
+
+
+def getViews(spec, skin):
+    """Get all views for the given skin and component spec."""
+    gsm = zope.component.getGlobalSiteManager()
+    result = {}
+    for reg in gsm.registeredAdapters():
+        factory = component.getRealFactory(reg.factory)
+        if (len(reg.required) >= 2 and
+            spec.isOrExtends(reg.required[0]) and
+            skin.isOrExtends(reg.required[1]) and
+            ITemplatedContentProvider.implementedBy(factory)
+            ):
+            # Make sure we pick out the most specific view
+            oldidx, oldreg = result.get(reg.name, (999, None))
+            newidx = list(spec.__iro__).index(reg.required[0])
+            if newidx < oldidx:
+                result[reg.name] = newidx, reg
+
+    return [reg for index, reg in result.values()]
+
+
+def getComponents(skin):
+    """Get all components for which views are registered in the skin."""
+    result = []
+    gsm = zope.component.getGlobalSiteManager()
+    for reg in gsm.registeredAdapters():
+        factory = component.getRealFactory(reg.factory)
+        if (len(reg.required) >= 2 and
+            skin.isOrExtends(reg.required[1]) and
+            hasattr(factory, '__implemented__') and
+            ITemplatedContentProvider.implementedBy(factory) and
+            reg.required[0] not in result
+            ):
+            result.append(reg.required[0])
+    return result
+
+
+def getTemplate(spec, skin):
+    """Get the component for the view"""
+    gsm = zope.component.getGlobalSiteManager()
+    # First look up the real adapter
+    factory = gsm.adapters.lookup((spec, skin), IPageTemplate)
+    # Now compare factories.
+    for reg in gsm.registeredAdapters():
+        if reg.factory is factory:
+            return reg
+
+
+class Template(object):
+    """Template"""
+    zope.interface.implements(zope.location.ILocation)
+
+    def __init__(self, reg, view):
+        self.__parent__ = view
+        self.__name__ = reg.name
+        self.reg = reg
+
+    @property
+    def macro(self):
+        return self.reg.factory.macro
+
+    @property
+    def filename(self):
+        return self.reg.factory.filename
+
+    @property
+    def contentType(self):
+        return self.reg.factory.contentType
+
+    def validate(self):
+        expressions = validator.getUsedExpressions(self.filename, self.macro)
+        factory = component.getRealFactory(self.__parent__.reg.factory)
+        return validator.compareExpressionsToView(expressions, factory)
+
+
+class View(object):
+    """View"""
+    zope.interface.implements(zope.location.ILocation)
+
+    template = None
+
+    def __init__(self, reg, comp):
+        self.__parent__ = comp
+        self.__name__ = reg.name
+        self.reg = reg
+        factory = component.getRealFactory(reg.factory)
+        treg = getTemplate(
+            zope.interface.implementedBy(factory), reg.required[1])
+        if treg:
+            self.template = Template(treg, self)
+
+    @property
+    def title(self):
+        return getViewPrefix(self.reg) + ' : ' + self.__name__
+
+
+class Component(utilities.ReadContainerBase):
+    """Component"""
+    zope.interface.implements(zope.location.ILocation)
+
+    def __init__(self, spec, skin):
+        self.__parent__ = skin
+        self.__name__ = spec.__name__
+        self.spec = spec
+
+    def get(self, key, default=None):
+        """See zope.app.container.interfaces.IReadContainer"""
+        return dict(self.items()).get(key, default)
+
+    def items(self):
+        """See zope.app.container.interfaces.IReadContainer"""
+        results = [
+            (reg.name, View(reg, self))
+            for reg in getViews(self.spec, self.__parent__.interface)]
+        return sorted(results, key=lambda x: x[1].title)
+
+
+class Skin(utilities.ReadContainerBase):
+    """Skin"""
+    zope.interface.implements(zope.location.ILocation)
+
+    def __init__(self, interface, parent, name):
+        self.__parent__ = parent
+        self.__name__ = name
+        self.interface = interface
+
+    def get(self, key, default=None):
+        """See zope.app.container.interfaces.IReadContainer"""
+        return dict(self.items()).get(key, default)
+
+    def items(self):
+        """See zope.app.container.interfaces.IReadContainer"""
+        results = [
+            (spec.__name__, Component(spec, self))
+            for spec in getComponents(self.interface)]
+        return sorted(results)
+
+
+class SkinBrowserModule(utilities.ReadContainerBase):
+    """Skin Browser Module"""
+    zope.interface.implements(IDocumentationModule)
+
+    # See zope.app.apidoc.interfaces.IDocumentationModule
+    title = _('Skin Browser')
+
+    # See zope.app.apidoc.interfaces.IDocumentationModule
+    description = _("""
+    The skin browser allows you to inspect each skin. All views are listed and
+    can be further discovered.
+    """)
+
+    def get(self, key, default=None):
+        """See zope.app.container.interfaces.IReadContainer"""
+        return Skin(
+            zope.component.queryUtility(IBrowserSkinType, key, default=default),
+            self, key)
+
+    def items(self):
+        """See zope.app.container.interfaces.IReadContainer"""
+        results = [
+            (name, Skin(iface, self, name))
+            for name, iface in zope.component.getUtilitiesFor(IBrowserSkinType)
+            # An educated guess that we really have a skin, since we cannot
+            # separate them from layers anymore. Sigh.
+            if '.' not in name]
+        results.sort(lambda x, y: cmp(x[1].interface.getName(),
+                                      y[1].interface.getName()))
+        return results


Property changes on: lovely.skinbrowser/trunk/src/lovely/skinbrowser/module.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: lovely.skinbrowser/trunk/src/lovely/skinbrowser/validator.py
===================================================================
--- lovely.skinbrowser/trunk/src/lovely/skinbrowser/validator.py	2006-09-20 11:57:05 UTC (rev 70254)
+++ lovely.skinbrowser/trunk/src/lovely/skinbrowser/validator.py	2006-09-20 12:17:14 UTC (rev 70255)
@@ -0,0 +1,131 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Skin Browser Module
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+import zope.interface
+from zope.tal import dummyengine, htmltalparser, talinterpreter
+
+class Devnull(object):
+    def write(self, s):
+        pass
+
+
+class ValidatorEngine(dummyengine.DummyEngine):
+
+    def __init__(self, macros=None):
+        self.expressions = []
+        dummyengine.DummyEngine.__init__(self, macros)
+
+    def evaluate(self, expression):
+        assert (expression.startswith("$") and expression.endswith("$"),
+                expression)
+        expression = expression[1:-1]
+        match = dummyengine.name_match(expression)
+        if match:
+            type, expr = match.group(1, 2)
+        else:
+            type = "path"
+            expr = expression
+        # Only support path for now; we probably want to support string as well
+        if type == 'path':
+            if expr not in self.expressions:
+                self.expressions.append((expr, self.position))
+        elif type == "not":
+            self.evaluate(expr)
+
+        return ''
+
+    def evaluateSequence(self, expr):
+        self.evaluate(expr)
+        return (0,) # dummy
+
+    def evaluateBoolean(self, expr):
+        self.evaluate(expr)
+        return True # dummy
+
+
+def getUsedExpressions(filename, macro=None):
+
+    engine = ValidatorEngine()
+
+    engine.file = filename
+    p = htmltalparser.HTMLTALParser()
+    p.parseFile(filename)
+    program, macros = p.getCode()
+
+    if macro is not None:
+        program = macros[macro]
+
+    talinterpreter.TALInterpreter(
+        program, macros, engine, stream=Devnull(), metal=False)()
+    return engine.expressions
+
+
+class ValidationMessage(object):
+    """A validation message."""
+    title = u'Message'
+    description = u''
+
+    def __init__(self, expression, position, variable):
+        self.expression = expression
+        self.line, self.column = position
+        self.variable = variable
+
+class ValidationError(ValidationMessage):
+    pass
+
+class ValidationWarning(ValidationMessage):
+    pass
+
+class FieldMissing(ValidationError):
+    title = u'Field Missing'
+    description = (u'The field is not defined in the view interface or the '
+                   u'implementation (view class).')
+
+class InterfaceFieldMissing(ValidationWarning):
+    title = u'Interface Field Missing'
+    description = (u'The field is not defined in the view interface but '
+                   u'implemented in the view class.')
+
+class ContextDirectlyUsed(ValidationWarning):
+    title = u'Context Used'
+    description = (u'The context namespace was directly used in the '
+                   u'template.')
+
+
+def compareExpressionsToView(expressions, factory):
+    # Get a list of attributes/fields and methods
+    implements = zope.interface.implementedBy(factory)
+    iface_names = zope.interface.interface.InterfaceClass(
+        'ITemporary', tuple(implements.interfaces())).names(True)
+    obj_names = list(factory.__dict__)
+    # Create the notification container
+    messages = []
+    for expression, position in expressions:
+        path = expression.split('/')
+        if path[0] == 'view':
+            if path[1] not in iface_names:
+                if path[1] not in obj_names:
+                    messages.append(
+                        FieldMissing(expression, position, path[1]))
+                else:
+                    messages.append(
+                        InterfaceFieldMissing(expression, position, path[1]))
+        elif path[0] == 'context':
+            messages.append(
+                ContextDirectlyUsed(expression, position, path[1]))
+    return messages


Property changes on: lovely.skinbrowser/trunk/src/lovely/skinbrowser/validator.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: lovely.skinbrowser/trunk/src/lovely/skinbrowser/view.pt
===================================================================
--- lovely.skinbrowser/trunk/src/lovely/skinbrowser/view.pt	2006-09-20 11:57:05 UTC (rev 70254)
+++ lovely.skinbrowser/trunk/src/lovely/skinbrowser/view.pt	2006-09-20 12:17:14 UTC (rev 70255)
@@ -0,0 +1,101 @@
+<html metal:use-macro="views/apidoc_macros/details"
+    i18n:domain="zope">
+<body metal:fill-slot="contents"
+      tal:define="rootURL request/URL/-5;
+                  template view/viewTemplate">
+
+  <h1 class="details-header">
+    <span tal:replace="context/title" />
+  </h1>
+
+  <div class="details-subheader"
+       tal:define="doc view/doc"
+       tal:condition="doc">
+    <div class="documentation" tal:content="structure doc">
+      Here is the doc string
+    </div>
+  </div>
+
+  <div tal:define="zcml view/fileInfo"
+       tal:condition="zcml">
+    <i i18n:translate="">File:</i>
+    <metal:block use-macro="context/@@interface_macros/zcml" />
+  </div>
+
+  <div tal:define="factory view/factory"
+       tal:condition="factory">
+    <i i18n:translate="">Factory:</i>
+    <a href=""
+       tal:condition="factory/referencable"
+       tal:attributes="
+           href string:$rootURL/Code/${factory/url}/index.html"
+       tal:content="factory/path" />
+    <span
+       tal:condition="not:factory/referencable"
+       tal:content="factory/path" />
+  </div>
+
+  <div tal:define="perm view/permission"
+       tal:condition="perm">
+    <i i18n:translate="">Permission:</i>
+    <span tal:replace="perm">zope.View</span>
+  </div>
+
+  <h2 class="details-section" i18n:translate="">Template</h2>
+
+  <div class="indent" tal:condition="template">
+
+    <div>
+      <i i18n:translate="">Template:</i>
+      <a href=""
+         tal:attributes="href string:$rootURL/Code/${template/filename/url}"
+         tal:content="template/filename/file" />
+    </div>
+
+    <div tal:condition="template/macro">
+      <i i18n:translate="">Macro:</i>
+      <span tal:replace="template/macro" />
+    </div>
+
+    <div>
+      <i i18n:translate="">Content-Type:</i>
+      <span tal:replace="template/contentType" />
+    </div>
+
+    <div tal:define="zcml template/fileInfo"
+         tal:condition="zcml">
+      <i i18n:translate="">File:</i>
+      <metal:block use-macro="context/@@interface_macros/zcml" />
+    </div>
+
+    <tal:block define="messages template/validationMessages"
+               condition="messages">
+
+      <h4 i18n:translate="">Validation</h4>
+
+      <ul>
+        <tal:block repeat="message messages"
+                   replace="structure message" />
+      </ul>
+
+    </tal:block>
+
+  </div>
+
+  <div class="indent" tal:condition="not:template">
+    <span i18n:translate="">
+      No template was discovered.
+    </span>
+  </div>
+
+  <tal:block define="attributes view/getAttributes;
+                     fields view/getFields">
+    <metal:block use-macro="context/@@interface_macros/attributes_fields" />
+  </tal:block>
+
+  <tal:block define="methods view/getMethods">
+    <metal:block use-macro="context/@@interface_macros/methods" />
+  </tal:block>
+
+</body>
+</html>


Property changes on: lovely.skinbrowser/trunk/src/lovely/skinbrowser/view.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.skinbrowser/trunk/src/lovely/skinbrowser/warning.pt
===================================================================
--- lovely.skinbrowser/trunk/src/lovely/skinbrowser/warning.pt	2006-09-20 11:57:05 UTC (rev 70254)
+++ lovely.skinbrowser/trunk/src/lovely/skinbrowser/warning.pt	2006-09-20 12:17:14 UTC (rev 70255)
@@ -0,0 +1,6 @@
+<li class="warning" style="color: #ccf">
+  <b>WARNING</b> - <span tal:content="context/title" />
+  (line <span tal:replace="context/line" />,
+   column <span tal:replace="context/column" />) :
+  <span tal:replace="context/expression" />
+</li>


Property changes on: lovely.skinbrowser/trunk/src/lovely/skinbrowser/warning.pt
___________________________________________________________________
Name: svn:eol-style
   + native



More information about the Checkins mailing list