Metadata-Version: 2.1
Name: forwardable
Version: 0.4.1
Summary: Forwardable as in Ruby's stdlib
Home-page: https://github.com/5long/forwardable
Author: Whyme Lyu
Author-email: callme5long@gmail.com
License: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Topic :: Software Development :: Code Generators
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.3
License-File: LICENSE

Forwardable
===========

Utility for easy object composition via delegation. Roughly ported from
Ruby's forwardable_ standard library.

Requirements
------------

Python 2.7 or 3.3 w/ standard library. Might work on other version of
Python, too.

Installation
------------

``$ pip install forwardable``

Usage
-----

Most Common Use Case
~~~~~~~~~~~~~~~~~~~~

The ``@forwardable.forwardable()`` decorator enables you to use
``def_delegator()`` and ``def_delegators()`` in a class definition block.

Use ``def_delegators()`` to define multiple attr forwarding:

.. code-block:: python

    from forwardable import forwardable

    @forwardable() # Note the () here, which is required.
    class Foo(object):
        def_delegators('bar', 'add, __len__')

        def __init__(self):
            self.bar = set()

    foo = Foo()
    foo.add(1) # Delegates to foo.bar.add()
    assert len(foo) == 1 # Magic methods works, too

Easy, heh?

Define a Single Forwarding
~~~~~~~~~~~~~~~~~~~~~~~~~~

In case you only need to delegate one method to a delegatee, just
use ``def_delegator``:

.. code-block:: python

    from forwardable import forwardable

    @forwardable()
    class Foo(object):
        def_delegator('bar', '__len__')

        def __init__(self):
            self.bar = set()

    assert len(Foo()) == 0

And it should work just fine. Actually, ``def_delegators()`` calls
``def_delegator()`` under the hood.

Plucking
~~~~~~~~

.. code-block:: python

    from forwardable import forwardable

    @forwardable()
    class MyDict(object):
        def_delegator('dct.get', '__call__')
        def __init__(self):
            self.dct = {'foo', 42}

    d = MyDict()
    # Equivlant to d.dct.get('foo')
    assert d('foo') == 42

Less Magical Usage
~~~~~~~~~~~~~~~~~~

The ``@forwardable()`` decorator injects ``def_delegator{,s}`` into the
module scope temorarily, which is why you don't have to import them
explicitly. This is admittedly magical but discourages the usage
of ``import *``. And it's always nice to type less characters whenever
unnecessary.

If you hesitate to utilize this injection magic, just explicitly say
``from forwardable import def_delegator, def_delegators``, use them in
a class definition and you'll be fine.

Links
-----

* Source Repository: https://github.com/5long/forwardable
* Feedback: https://github.com/5long/forwardable/issues

License
-------

MIT license.

.. _forwardable: http://ruby-doc.org/stdlib-2.0/libdoc/forwardable/rdoc/Forwardable.html
