
..  _RefActionsDocTests:

Action doctests
****************************************************************************

ActionBase test suite
============================================================================

The :class:`ActionBase` class implements various basing behaviors of
action objects.


Test tool
----------------------------------------------------------------------------

The following PrintAction is used in this test suite::

    >>> from dragonfly import ActionBase, Repeat
    >>> class PrintAction(ActionBase):
    ...     def __init__(self, name):
    ...         ActionBase.__init__(self)
    ...         self._name = name
    ...     def execute(self, data=None):
    ...         if data:
    ...             # Print a sorted representation of the data dict.
    ...             sorted_data = "{%s}" % ", ".join([
    ...                 "%r: %r" % (key, value)
    ...                 for key, value in sorted(data.items())
    ...             ])
    ...             print("executing %r %s" % (self._name, sorted_data))
    ...         else:
    ...              print("executing %r" % (self._name,))
    ...
    >>> a = PrintAction("a")
    >>> a.execute()
    executing 'a'
    >>> a.execute({"foo": 2})
    executing 'a' {'foo': 2}
    >>>


Concatenating actions
----------------------------------------------------------------------------

Concatenation of multiple actions::

    >>> b = PrintAction("b")
    >>> (a + b).execute()           # Simple concatenation.
    executing 'a'
    executing 'b'
    >>> (a + b).execute({"foo": 2}) # Simple concatenation.
    executing 'a' {'foo': 2}
    executing 'b' {'foo': 2}

    >>> c = a
    >>> c += b                      # In place concatenation.
    >>> c.execute({"foo": 2})
    executing 'a' {'foo': 2}
    executing 'b' {'foo': 2}
    >>> c += a                      # In place concatenation.
    >>> c.execute()
    executing 'a'
    executing 'b'
    executing 'a'

    >>> (c + c).execute()           # Same object concatenation.
    executing 'a'
    executing 'b'
    executing 'a'
    executing 'a'
    executing 'b'
    executing 'a'


Repeating actions
----------------------------------------------------------------------------

Actions can be repeated by multiplying them with a factor::

    >>> (a * 3).execute()
    executing 'a'
    executing 'a'
    executing 'a'
    >>> ((a + b) * 2).execute({"foo": 2})
    executing 'a' {'foo': 2}
    executing 'b' {'foo': 2}
    executing 'a' {'foo': 2}
    executing 'b' {'foo': 2}

    >>> factor = Repeat(3)              # Integer-factor repetition.
    >>> (a * factor).execute()
    executing 'a'
    executing 'a'
    executing 'a'
    >>> factor = Repeat(extra="foo")    # Named-factor repetition.
    >>> ((a + b) * factor).execute({"foo": 2})
    executing 'a' {'foo': 2}
    executing 'b' {'foo': 2}
    executing 'a' {'foo': 2}
    executing 'b' {'foo': 2}
    >>> ((a + b) * factor).execute({"bar": 2})
    Traceback (most recent call last):
      ...
    ActionError: No extra repeat factor found for name 'foo'

    >>> c = a
    >>> c.execute({"foo": 2})
    executing 'a' {'foo': 2}
    >>> c *= Repeat(extra="foo")
    >>> c.execute({"foo": 2})
    executing 'a' {'foo': 2}
    executing 'a' {'foo': 2}
    >>> c += b
    >>> c *= 2
    >>> c.execute({"foo": 1})
    executing 'a' {'foo': 1}
    executing 'b' {'foo': 1}
    executing 'a' {'foo': 1}
    executing 'b' {'foo': 1}
    >>> c *= 2
    >>> c.execute({"foo": 0})
    executing 'b' {'foo': 0}
    executing 'b' {'foo': 0}
    executing 'b' {'foo': 0}
    executing 'b' {'foo': 0}
    >>> c *= 0
    >>> c.execute({"foo": 1})


Binding data to actions
----------------------------------------------------------------------------

Binding of data to actions::

    >>> a_bound = a.bind({"foo": 2})
    >>> a_bound.execute()
    executing 'a' {'foo': 2}

    >>> b_bound = b.bind({"bar": 3})
    >>> b_bound.execute()
    executing 'b' {'bar': 3}

Earliest bound data is used during execution::

    >>> ab_bound = a_bound + b_bound
    >>> ab_bound.execute({"bar": "later"})
    executing 'a' {'bar': 'later', 'foo': 2}
    executing 'b' {'bar': 3}

    >>> ab_bound = (a_bound + b_bound).bind({"bar": "later"})
    >>> ab_bound.execute()
    executing 'a' {'bar': 'later', 'foo': 2}
    executing 'b' {'bar': 3}
