[Checkins] SVN: grok/trunk/src/grok/ refactored directives and extracted them into their own module

Wolfgang Schnerring wosc at wosc.de
Mon Oct 16 09:48:03 EDT 2006


Log message for revision 70690:
  refactored directives and extracted them into their own module

Changed:
  U   grok/trunk/src/grok/_grok.py
  A   grok/trunk/src/grok/directive.py
  A   grok/trunk/src/grok/error.py
  A   grok/trunk/src/grok/tests/view/resourcedirectoryname/
  A   grok/trunk/src/grok/util.py

-=-
Modified: grok/trunk/src/grok/_grok.py
===================================================================
--- grok/trunk/src/grok/_grok.py	2006-10-16 13:16:56 UTC (rev 70689)
+++ grok/trunk/src/grok/_grok.py	2006-10-16 13:48:02 UTC (rev 70690)
@@ -13,20 +13,23 @@
 ##############################################################################
 """Grok
 """
-import types
 import sys
-import re
 import os
 from pkg_resources import resource_listdir, resource_exists, resource_string
 from zope.dottedname.resolve import resolve
 from zope import component
 from zope import interface
-from zope.interface.interfaces import IInterface
 from zope.publisher.browser import BrowserPage
 from zope.publisher.interfaces.browser import IDefaultBrowserLayer
 from zope.pagetemplate import pagetemplate
 from zope.app.pagetemplate.engine import TrustedAppPT
 
+from grok import util
+from grok.error import GrokError
+from grok.directive import (ClassDirectiveContext, ModuleDirectiveContext, ClassOrModuleDirectiveContext,
+                            TextDirective, InterfaceOrClassDirective)
+     
+
 class Model(object):
     pass
 
@@ -53,7 +56,7 @@
 
     def __init__(self, template):
         super(PageTemplate, self).__init__()
-        if not_unicode_or_ascii(template):
+        if util.not_unicode_or_ascii(template):
             raise GrokError("Invalid page template. Page templates must be "
                             "unicode or ASCII.")
         self.write(template)
@@ -62,9 +65,6 @@
         # PageTemplate cannot be subclassed
         self.__grok_module__ = caller_module()
 
-class GrokError(Exception):
-    pass
-
 AMBIGUOUS_CONTEXT = object()
 def grok(dotted_name):
     # TODO for now we only grok modules
@@ -80,14 +80,14 @@
         if not defined_locally(obj, dotted_name):
             continue
 
-        if check_subclass(obj, Model):
+        if util.check_subclass(obj, Model):
             if context is None:
                 context = obj
             else:
                 context = AMBIGUOUS_CONTEXT
-        elif check_subclass(obj, Adapter):
+        elif util.check_subclass(obj, Adapter):
             adapters.append(obj)
-        elif check_subclass(obj, View):
+        elif util.check_subclass(obj, View):
             views.append(obj)
         elif isinstance(obj, PageTemplate):
             templates.register(name, obj)
@@ -194,15 +194,6 @@
         obj_module = getattr(obj, '__module__', None)
     return obj_module == dotted_name
 
-def isclass(obj):
-    """We cannot use ``inspect.isclass`` because it will return True for interfaces"""
-    return type(obj) in (types.ClassType, type)
-
-def check_subclass(obj, class_):
-    if not isclass(obj):
-        return False
-    return issubclass(obj, class_)
-
 def check_context(source, context):
     if context is None:
         raise GrokError("No module-level context for %s, please use "
@@ -216,60 +207,9 @@
     check_context(repr(factory), context)
     return context
 
-def caller_is_module():
-    frame = sys._getframe(2)
-    return frame.f_locals is frame.f_globals
-
-def caller_is_class():
-    frame = sys._getframe(2)
-    return '__module__' in frame.f_locals
-
 def caller_module():
     return sys._getframe(2).f_globals['__name__']
 
-def set_local(name, value, error_message):
-    frame = sys._getframe(2)
-    name = '__grok_%s__' % name
-    if name in frame.f_locals:
-        raise GrokError(error_message)
-    frame.f_locals[name] = value
-
-def not_unicode_or_ascii(value):
-    if isinstance(value, unicode):
-        return False
-    if not isinstance(value, str):
-        return True
-    return is_not_ascii(value)
-
-is_not_ascii = re.compile(eval(r'u"[\u0080-\uffff]"')).search
-
-def context(obj):
-    if not (IInterface.providedBy(obj) or isclass(obj)):
-        raise GrokError("You can only pass classes or interfaces to "
-                        "grok.context.")
-    if not (caller_is_module() or caller_is_class()):
-        raise GrokError("grok.context can only be used on class or module level.")
-    set_local('context', obj, "grok.context can only be called once per class "
-              "or module.")
-
-class ClassDirective(object):
-    """
-    Class-level directive that puts unicode/ASCII values into the
-    class's locals as __grok_<name>__.
-    """
-
-    def __init__(self, name):
-        self.name = name
-
-    def __call__(self, val):
-        if not_unicode_or_ascii(val):
-            raise GrokError("You can only pass unicode or ASCII to "
-                            "grok.%s." % self.name)
-        if not caller_is_class():
-            raise GrokError("grok.%s can only be used on class level."
-                            % self.name)
-        set_local(self.name, val, "grok.%s can only be called once per class."
-                  % self.name)
-
-name = ClassDirective('name')
-template = ClassDirective('template')
+name = TextDirective('grok.name', ClassDirectiveContext())
+template = TextDirective('grok.template', ClassDirectiveContext())
+context = InterfaceOrClassDirective('grok.context', ClassOrModuleDirectiveContext())

Added: grok/trunk/src/grok/directive.py
===================================================================
--- grok/trunk/src/grok/directive.py	2006-10-16 13:16:56 UTC (rev 70689)
+++ grok/trunk/src/grok/directive.py	2006-10-16 13:48:02 UTC (rev 70690)
@@ -0,0 +1,111 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Grok directives.
+"""
+
+import sys
+from zope import interface
+from zope.interface.interfaces import IInterface
+
+from grok import util
+from grok.error import GrokError
+
+
+def frame_is_module(frame):
+    return frame.f_locals is frame.f_globals
+
+def frame_is_class(frame):
+    return '__module__' in frame.f_locals    
+
+class IDirectiveContext(interface.Interface):
+    description = interface.Attribute("The correct place in which the directive can be used.")
+
+    def matches(frame):
+        """returns whether the given frame is the correct place in
+        which the directive can be used.
+        """
+
+class ClassDirectiveContext(object):
+    interface.implements(IDirectiveContext)
+    
+    description = "class"
+
+    def matches(self, frame):
+        return frame_is_class(frame)
+
+    
+class ModuleDirectiveContext(object):
+    interface.implements(IDirectiveContext)
+    
+    description = "module"
+
+    def matches(self, frame):
+        return frame_is_module(frame)
+    
+class ClassOrModuleDirectiveContext(object):
+    interface.implements(IDirectiveContext)
+    
+    description = "class or module"
+
+    def matches(self, frame):
+        return frame_is_module(frame) or frame_is_class(frame)
+
+class Directive(object):
+    """
+    Directive sets a value into the context's locals as __<name>__
+    ('.' in the name are replaced with '_').
+    A directive can be called only once.
+    """
+
+    def __init__(self, name, directive_context):
+        self.name = name
+        self.directive_context = directive_context
+
+    def __call__(self, value):
+        self.check(value)
+        
+        frame = sys._getframe(1)
+        if not self.directive_context.matches(frame):
+            raise GrokError("%s can only be used on %s level."
+                            % (self.name, self.directive_context.description))
+        
+        local_name = '__%s__' % self.name.replace('.', '_')
+        if local_name in frame.f_locals:
+            raise GrokError("%s can only be called once per %s."
+                            % (self.name, self.directive_context.description))
+        frame.f_locals[local_name] = value
+
+    def check(self, value):
+        pass
+
+class TextDirective(Directive):
+    """
+    Directive that only accepts unicode/ASCII values.
+    """
+
+    def check(self, value):
+        if util.not_unicode_or_ascii(value):
+            raise GrokError("You can only pass unicode or ASCII to "
+                            "%s." % self.name)
+
+class InterfaceOrClassDirective(Directive):
+    """
+    Directive that only accepts classes or interface values.
+    """
+    
+    def check(self, value):
+        if not (IInterface.providedBy(value) or util.isclass(value)):
+            raise GrokError("You can only pass classes or interfaces to "
+                            "%s." % self.name)
+    

Added: grok/trunk/src/grok/error.py
===================================================================
--- grok/trunk/src/grok/error.py	2006-10-16 13:16:56 UTC (rev 70689)
+++ grok/trunk/src/grok/error.py	2006-10-16 13:48:02 UTC (rev 70690)
@@ -0,0 +1,19 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Grok errors.
+"""
+
+class GrokError(Exception):
+    pass
+

Added: grok/trunk/src/grok/util.py
===================================================================
--- grok/trunk/src/grok/util.py	2006-10-16 13:16:56 UTC (rev 70689)
+++ grok/trunk/src/grok/util.py	2006-10-16 13:48:02 UTC (rev 70690)
@@ -0,0 +1,38 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Grok utility functions.
+"""
+
+import re
+import types
+
+
+def not_unicode_or_ascii(value):
+    if isinstance(value, unicode):
+        return False
+    if not isinstance(value, str):
+        return True
+    return is_not_ascii(value)
+
+is_not_ascii = re.compile(eval(r'u"[\u0080-\uffff]"')).search
+
+def isclass(obj):
+    """We cannot use ``inspect.isclass`` because it will return True for interfaces"""
+    return type(obj) in (types.ClassType, type)
+
+def check_subclass(obj, class_):
+    if not isclass(obj):
+        return False
+    return issubclass(obj, class_)
+



More information about the Checkins mailing list