def when(*desired_states):
    """
    Register the decorated function to run when all ``desired_states`` are active.

    If a state is associated with a relation, an instance of that relation
    class will be passed in to the decorated function.

    This can be used from Bash using the ``reactive.sh`` helpers::

        source `which reactive.sh`

        when db.ready cache.ready; then
            db_dsn=$(state_relation_call db.ready uri)
            cache_uri=$(state_relation_call cache.ready uri)
            chlp render_template db_dsn=$db_dsn cache_uri=$cache_uri
        nehw

    The Bash helper uses the :func:`when_cli` ``chlp`` command, and the above is
    exactly equivalent to::

        source `which reactive.sh`

        if chlp when_cli db.ready cache.ready; then
            db_dsn=$(state_relation_call db.ready uri)
            cache_uri=$(state_relation_call cache.ready uri)
            chlp render_template db_dsn=$db_dsn cache_uri=$cache_uri
        fi
    """
    return Handler.decorator(
        lambda: all_states(*desired_states),
        lambda: filter(None, map(RelationBase.from_state, desired_states)))
def when_not(*desired_states):
    """
    Register the decorated function to run when **not** all desired_states are active.

    If a state is associated with a relation, an instance of that relation
    class will be passed in to the decorated function.

    This can be used from Bash using the ``reactive.sh`` helpers::

        source `which reactive.sh`

        when_not db.ready cache.ready; then
            db_dsn=$(state_relation_call db.ready uri)
            cache_uri=$(state_relation_call cache.ready uri)
            chlp render_template db_dsn=$db_dsn cache_uri=$cache_uri
        nehw

    The Bash helper uses the `all_states` ``chlp`` command, and the above is
    exactly equivalent to::

        source `which reactive.sh`

        if ! chlp all_states db.ready cache.ready; then
            db_dsn=$(state_relation_call db.ready uri)
            cache_uri=$(state_relation_call cache.ready uri)
            chlp render_template db_dsn=$db_dsn cache_uri=$cache_uri
        fi
    """
    return Handler.decorator(lambda: not all_states(*desired_states))
def hook(*hook_patterns):
    """
    Register the decorated function to run when the current hook matches any of
    the ``hook_patterns``.

    The hook patterns can use the ``{interface:...}`` and ``{A,B,...}`` syntax
    supported by `any_hook`.

    If the hook is a relation hook, an instance of that relation class will be
    passed in to the decorated function.

    For example, to match any joined or changed hook for any relation using the
    ``mysql`` interface::

        class MySQLRelation(RelationBase):
            @hook('{interface:mysql}-relation-{joined,changed}')
            def joined_or_changed(self):
                pass

    This can be used from Bash using the ``reactive.sh`` helpers::

        source `which reactive.sh`

        hook '{interface:mysql}-relation-{joined,changed}'; then
            chlp relation_call $JUJU_RELATION handle_relation
        kooh

    The Bash helper uses the `any_hook` ``chlp`` command, and the above is
    exactly equivalent to::

        source `which reactive.sh`

        if chlp any_hook '{interface:mysql}-relation-{joined,changed}'; then
            chlp relation_call $JUJU_RELATION handle_relation
        kooh
    """
    return Handler.decorator(
        lambda: any_hook(*hook_patterns),
        lambda: filter(None, [RelationBase.from_name(hookenv.relation_type())]))