zeam.form.base
==============

The component and component collections are basic objects used to
implement fields, actions and widgets. Their behavior described here
apply to those objects.

Components
----------

First let's see the component:

  >>> from zeam.form.base.components import Component
  >>> c1 = Component('The Sun', 'sun')
  >>> c1
  <Component The Sun>
  >>> c1.identifier
  'sun'
  >>> c1.title
  'The Sun'

It correctly implement IComponent:

  >>> from zope.interface.verify import verifyObject
  >>> from zeam.form.base import interfaces
  >>> verifyObject(interfaces.IComponent, c1)
  True

Actually you can create a component without an id, and even using a
unicode title:

  >>> c2 = Component(u'Moon')
  >>> c2
  <Component Moon>
  >>> c2.identifier
  'moon'
  >>> c2.title
  u'Moon'

If by doing so, the title contain spaces, they will be replaced by
``-``. If UTF-8 character are included, the identifiant will be
encoded:

  >>> c3 = Component(u'Some lost planet')
  >>> c3.identifier
  'some-lost-planet'
  >>> c4 = Component(u'État du désir')
  >>> c4.identifier
  'c383c2897461742d64752d64c383c2a9736972'

You can clone a component and change its identifier:

  >>> c3clone = c3.clone('new-world')
  >>> c3clone
  <Component Some lost planet>
  >>> c3clone.identifier
  'new-world'
  >>> c3clone is c3
  False

But you can keep the old one as well:

  >>> c4clone = c4.clone()
  >>> c4clone.identifier
  'c383c2897461742d64752d64c383c2a9736972'
  >>> c4clone is c4
  False


Collection
----------

Collection are simple objects, implementing ICollection:

  >>> from zeam.form.base.components import Collection
  >>> s1 = Collection()
  >>> s1
  <Collection>
  >>> len(s1)
  0
  >>> verifyObject(interfaces.ICollection, s1)
  True

Adding components to a collection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Now we can put components in a collection, and list it back in the
same order:

  >>> s1.append(c1)
  >>> list(s1)
  [<Component The Sun>]
  >>> s1.append(c2)
  >>> list(s1)
  [<Component The Sun>, <Component Moon>]

But you can't add twice the same component:

  >>> s1.append(c1)
  Traceback (most recent call last):
    ...
  ValueError: (u'Duplicate identifier', 'sun')

And this need to be a component:

  >>> s1.append('home')
  Traceback (most recent call last):
    ...
  TypeError: (u'Invalid type', 'home')

You create a collection with components or collection as argument:

  >>> s2 = Collection(Component('Jupiter'), Component('Saturn'))
  >>> list(s2)
  [<Component Jupiter>, <Component Saturn>]
  >>> len(s2)
  2
  >>> list(Collection(s2, Component('Uranus')))
  [<Component Jupiter>, <Component Saturn>, <Component Uranus>]
  >>> Collection(42)
  Traceback (most recent call last):
    ...
  TypeError: (u'Invalid type', 42)

You can add collections. You will receive a copy with all
components. Components will ordered as the addition is:

  >>> s3 = s1 + s2
  >>> s3
  <Collection>
  >>> s3 is s1
  False
  >>> list(s3)
  [<Component The Sun>, <Component Moon>,
   <Component Jupiter>, <Component Saturn>]
  >>> len(s3)
  4
  >>> list(s2 + s1)
  [<Component Jupiter>, <Component Saturn>,
   <Component The Sun>, <Component Moon>]

You can extend a collection. It work pretty much like the construtor:

  >>> s3.extend(Component('Venus'), Component('Uranus'))
  >>> list(s3)
  [<Component The Sun>, <Component Moon>,
   <Component Jupiter>, <Component Saturn>,
   <Component Venus>, <Component Uranus>]
  >>> s3.extend('Kitty')
  Traceback (most recent call last):
    ...
  TypeError: (u'Invalid type', 'Kitty')

You can copy a collection:

  >>> s3copy = s3.copy()
  >>> list(s3copy) == list(s3)
  True
  >>> s3copy is s3
  False


Retriving components from a collection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can retrieve one element of the collection:

  >>> s3.get('moon')
  <Component Moon>
  >>> s3.get('uranus')
  <Component Uranus>
  >>> s3.get('me')
  Traceback (most recent call last):
    ...
  KeyError: 'me'
  >>> s3.get('me', default=42)
  42

And dictionnary like access works:

  >>> s3['uranus']
  <Component Uranus>
  >>> s3['venus']
  <Component Venus>
  >>> s3['somewhere']
  Traceback (most recent call last):
    ...
  KeyError: 'somewhere'

You can get all components ids:

  >>> s3.keys()
  ['sun', 'moon', 'jupiter', 'saturn', 'venus', 'uranus']

You can get a new collection with some of the components of the first
one:

  >>> s4 = s3.select('venus', 'uranus')
  >>> s4 is s3
  False
  >>> list(s4)
  [<Component Venus>, <Component Uranus>]
  >>> s4.keys()
  ['venus', 'uranus']

Or the other way around some components of a collection:

  >>> s5 = s3.omit('sun', 'moon')
  >>> s5 is s3
  False
  >>> list(s5)
  [<Component Jupiter>, <Component Saturn>,
   <Component Venus>, <Component Uranus>]


Parameters on collections
~~~~~~~~~~~~~~~~~~~~~~~~~

You can provides extra parameters on collections that will be set as
attributes on the object:

  >>> s6 = Collection(s2, name=u'me', city=u'rotterdam')
  >>> s6
  <Collection>
  >>> list(s6)
  [<Component Jupiter>, <Component Saturn>]
  >>> s6.name
  u'me'
  >>> s6.city
  u'rotterdam'

Those attributes are kept if you use the operations ``select``,
``omit`` or ``copy``:

  >>> s6copy = s6.copy()
  >>> s6copy.name
  u'me'
  >>> s6copy.city
  u'rotterdam'

  >>> s6omit = s6.omit('jupiter')
  >>> s6omit.name
  u'me'
  >>> s6omit.city
  u'rotterdam'

  >>> s6select = s6.select('jupiter')
  >>> s6select.name
  u'me'
  >>> s6select.city
  u'rotterdam'
