[Subversion] / ObjectRoles / README.txt  

Diff of /ObjectRoles/README.txt

Parent Directory | Revision Log

version 2346, Thu Jul 12 17:47:01 2007 UTC version 2347, Thu Jul 12 23:07:45 2007 UTC
Line 2 
Line 2 
 Separating Concerns Using Object Roles  Separating Concerns Using Object Roles
 ======================================  ======================================
   
   (New in version 0.6: ``ClassRole.for_frame()``, ``Registry``)
   
 In any sufficiently-sized application or framework, it's common to end up  In any sufficiently-sized application or framework, it's common to end up
 lumping a lot of different concerns into the same class.  For example, you  lumping a lot of different concerns into the same class.  For example, you
 may have business logic, persistence code, and UI all jammed into a single  may have business logic, persistence code, and UI all jammed into a single
Line 130 
Line 132 
 are stored under, such that more than one role instance can exist for a given  are stored under, such that more than one role instance can exist for a given
 object::  object::
   
     >>> from UserDict import UserDict      >>> class Index(Role, dict):
     >>> class Index(Role, UserDict):  
     ...     def __init__(self, subject, expression):      ...     def __init__(self, subject, expression):
     ...         self.expression = expression      ...         self.expression = expression
     ...         self.data = {}  
   
     >>> something = Thing()      >>> something = Thing()
     >>> Index(something, "x>y")["a"] = "b"      >>> Index(something, "x>y")["a"] = "b"
Line 144 
Line 144 
     >>> "a" in Index(something, "z<22")      >>> "a" in Index(something, "z<22")
     False      False
   
       >>> Index(something, "x>y")
       {'a': 'b'}
   
       >>> Index(something, "x>y").expression
       'x>y'
   
     >>> dir(something)      >>> dir(something)
     ['__doc__', '__module__', (<class 'Index'>, 'x>y'), (<class 'Index'>, 'z<22')]      ['__doc__', '__module__', (<class 'Index'>, 'x>y'), (<class 'Index'>, 'z<22')]
   
Line 505 
Line 511 
     >>> SpecialMethodRegistry(Demo).special_methods      >>> SpecialMethodRegistry(Demo).special_methods
     {'y': 55, 'x': 23}      {'y': 55, 'x': 23}
   
 (Alternately, you can pass a specific Python frame object via the ``frame``  Alternately, you can pass a specific Python frame object via the ``frame``
 keyword argument to ``for_enclosing_class()``.)  keyword argument to ``for_enclosing_class()``, or use the ``for_frame()``
   classmethod instead.  ``for_frame()`` takes a Python stack frame, followed by
   any additional arguments needed to create the key.
   
   
   Class Registries
   ~~~~~~~~~~~~~~~~
   
   For many of common class role use cases, you just want a dictionary-like object
   with "inheritance" for the values in base classes.  The ``Registry`` base class
   provides this behavior, by subclassing ``ClassRole`` and the Python ``dict``
   builtin type, to create a class role that's also a dictionary.  It then
   overrides the ``created_for()`` method to automatically populate itself with
   any inherited values from base classes.
   
   Let's define a ``MethodGoodness`` registry that will store a "goodness"
   rating for methods::
   
       >>> from peak.util.roles import Registry
   
       >>> class MethodGoodness(Registry):
       ...     """Dictionary of method goodness"""
   
       >>> def goodness(value):
       ...     def decorate(func):
       ...         MethodGoodness.for_enclosing_class()[func.__name__]=value
       ...         return func
       ...     return decorate
   
       >>> class Demo(object):
       ...     def aMethod(self, foo):
       ...         pass
       ...     aMethod = goodness(17)(aMethod)
       ...     def another_method(whinge, spam):
       ...         woohoo
       ...     another_method = goodness(-99)(another_method)
   
       >>> MethodGoodness(Demo)
       {'aMethod': 17, 'another_method': -99}
   
   So far, so good.  Let's see what happens with a subclass::
   
       >>> class Demo2(Demo):
       ...     def another_method(self, fixed):
       ...         pass
       ...     another_method = goodness(42)(another_method)
   
       >>> MethodGoodness(Demo2)
       {'another_method': 42, 'aMethod': 17}
   
   Values set in base class registries are automatically added to the current
   class' registry of the same type and key, if the current class doesn't have
   an entry defined.  Python's new-style method resolution order is used to
   determine the precedence of inherited attributes.  (For classic classes, a
   temporary new-style class is created that inherits from the classic class, in
   order to determine the resolution order, then discarded.)
   
   Once the class in question has been created, the registry gets an extra
   attribute, ``defined_in_class``, which is a dictionary listing the entries that
   were actually defined in the corresponding class, e.g.::
   
       >>> MethodGoodness(Demo).defined_in_class
       {'aMethod': 17, 'another_method': -99}
   
       >>> MethodGoodness(Demo2).defined_in_class
       {'another_method': 42}
   
   As you can see, this second dictionary contains only the values registered in
   that class, and not any inherited values.
   
   Finally, note that ``Registry`` objects have one additional method that can
   be useful to call from a decorator: ``set(key, value)``.  This method will
   raise an error if a different value already exists for the given key, and is
   useful for catching errors in class definitions, e.g.:
   
       >>> def goodness(value):
       ...     def decorate(func):
       ...         MethodGoodness.for_enclosing_class().set(func.__name__, value)
       ...         return func
       ...     return decorate
   
       >>> class Demo3(object):
       ...     def aMethod(self, foo):
       ...         pass
       ...     aMethod = goodness(17)(aMethod)
       ...     def aMethod(self, foo):
       ...         pass
       ...     aMethod = goodness(27)(aMethod)
       Traceback (most recent call last):
         ...
       ValueError: MethodGoodness['aMethod'] already contains 17; can't set to 27
   
   
 Threading Concerns  Threading Concerns


Generate output suitable for use with a patch program
Legend:
Removed from v.2346  
changed lines
  Added in v.2347

cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help