Utility Functions
=================

The bop package contains numerous help functions and utilities that can
be useful in many circumstances. Many of them are imported in the
bop namespace. The implementations can be found in bop.shortcut and bop.helper.

With a single import the creation of a file and the adding of the file to a 
container can be accomplished without any other imports. Note that all
necessary creation and add events are handled for you:

    >>> import bop
    >>> file = bop.File()
    >>> root = getRootFolder()
    >>> contained = bop.add(root, 'test_de.txt', file)
 
    >>> bop.path(contained)
    u'/test_de.txt'
    
    
Permissions
-----------

Sometimes it is necessary to explicitely test for permissions. As a 
site manager, for instance, one should be able to access the component
registry:

    >>> bop.canAccessSiteManager(root)
    False
    
Public Functions
----------------

Bebop prefers at many places functions over adapters. As such the functions
are security proxied and cannot be called directly. The public decorator
declares a function as publically callable:

    
    >>> @bop.public()
    ... def hello_world():
    ...     print "Hello world"
    
    >>> hello_world()
    Hello world

    >>> hello_world.__module__
    'bop.readme_txt'

    
Generic Functions
-----------------

Many of these functions are implemented as generic functions that can be 
extended or overwritten for special types. The default behavior however is
already adapted to standard usecases. 

The bop.title function, for instance, is well suited for usage in breadcrumb or 
navigation contexts. The default behavior returns the DublinCore title or 
the name:

    >>> bop.title(file)
    u'Unnamed'

    >>> bop.title(contained)
    u'test_de.txt'
  
    >>> bop.settitle(contained, u'Title')
    >>> bop.title(contained)
    u'Title'
    
Extract a language marker from a naming convention:

    >>> bop.language(contained)
    'de'

    
Modification and Notification
-----------------------------

It's up to the programmer to ensure that all necessary modification events
are thrown. Since many programmers are lazy the events often do not describe
in detail which aspects of an object have been affected. The shortcut 
bop.modify tries to make the modification and the notification about the
modification as concise as possible:

    >>> def printEvent(event):
    ...     print event.__class__.__name__,
    ...     for desc in event.descriptions:
    ...         print desc.interface.__name__,
    ...         for attr in desc.attributes:
    ...             print attr,

    >>> zope.event.subscribers.append(printEvent)

Let's change a single attribute:

    >>> bop.modify(file, zope.app.file.interfaces.IFile, data='Test')
    ObjectModifiedEvent IFile data
    >>> file.data
    'Test'

Multiple fields of a schema can be modified as follows:

    >>> bop.modify(file, zope.dublincore.interfaces.IZopeDublinCore,
    ...     title=u'Title',
    ...     description=u'Desc')
    ObjectModifiedEvent IZopeDublinCore description title
    >>> bop.title(file)
    u'Title'

If we omit the schema the attributes are modified without detailed 
descriptions:

    >>> bop.modify(file, contentType='text/plain')
    ObjectModifiedEvent
    
    