=========
Reference
=========


Overview
========

TTag replaces the normal method of creating custom template tags.  It
uses a custom template ``Node`` subclass called ``Tag`` which handles all of
the relevant aspects of a tag: defining and parsing arguments, handling
validation, resolving variables from the context, and rendering output.


Tag
===

.. currentmodule:: ttag

.. class:: Tag

    A representation of a template tag. For example::

	    class Welcome(ttag.Tag):
	
	        def output(self, data):
	            return "Hi there!"

Meta options
------------

.. class:: Tag.Meta

    A ``Tag`` takes options via a ``Meta`` inner class::

        class Welcome(ttag.Tag):

            class Meta:
                name = "hi"

    .. attribute:: name

        Explicitly choose a name for the tag. If not given, the tag's name will be
    	created by taking the class's name and converting it from CamelCase to
    	under_score format. For example, ``AmazingStuff`` would turn into
    	``{% amazing_stuff %}``.

    .. attribute:: register

        Register the tag in a tag library.

        Alternatively, a tag can still be rendered the standard way:
        ``some_library.tag(ThisTag)``.

    .. attribute:: block

        Retrieve subsequent template nodes until ``{% end[tagname] %}``, adding
        them to ``self.nodelists``.

    .. attribute:: end_block

        An alternative ending block node. Defaults to ``'end%(name)s'``.

output
------

If your tag does not modify the output, override this method to change the
output of this tag. 

.. method:: Tag.output(data)

    :param data: A dictionary of data built from the arguments this tag uses,
    	usually built by the :meth:`resolve` method.

render
------

As an alternative to overriding the ``output`` method, a ``TemplateTag``
subclass may directly override the ``render`` method. This is useful for
when you want to alter the context.

.. method:: Tag.render(context)

    :param context: The current template context.

    ``render`` must return a unicode string.

    If your tag doesn't return anything (e.g., it only manipulates the
    context), ``render`` should simply return an empty string.

To retrieve the values of the tag's arguments, if any, use the following method
inside ``render``:

.. method:: Tag.resolve(context)

	Retrieve the values of the tag's arguments.
	
	:param context: The current template context.
	:returns: A data dictionary containing the values of the tag's arguments.


Arguments
=========

Arguments can be either positional or named. They are specified as properties
of the tag class, in a similar way to Django's forms and models.

If the property name clashes with a append a trailing slash - it will be
removed from the argument's ``name``. For example, pay attention to the ``as_``
argument in the tag below::

    class Set(ttag.Tag):
        value = ttag.Arg()
        as_ = ttag.BasicArg()

        def render(self, context):
            data = self.resolve(context)
            as_var = data['as']
            context[as_var] = data['value']
            return ''

Positional arguments
--------------------

By default, an argument is considered positional::  

    class Positional(ttag.Tag):
        first = ttag.Arg()
        second = ttag.Arg()

This would result in a tag named ``positional`` which took two required
arguments, which would be assigned to ``'first'`` and ``'second'`` items
of the data dictionary returned by the ``resolve`` method.

Use the :class:`ConstantArg` for simple required string-based arguments which
assist readability::

    class Measure(ttag.Tag):
        start = ttag.Arg()
        to = ttag.ConstantArg()
        finish = ttag.Arg()

Named arguments
---------------

Named arguments can appear in any order in a tag's arguments, after the
positional arguments.

The standard type of named argument uses space separation::

    class Named(ttag.Tag):
        limit = ttag.Arg(named=True)
        offset = ttag.Arg(named=True)

This would create a tag named ``named`` which took two named arguments,
``limit`` and ``offset``.  They could be specified in any order::

    {% named limit 15 offset 42 %}

    {% named offset 4 limit 12 %}

Alternatively, named arguments can use "keyword" style named arguments::
you can use the ``keyword`` parameter::

    class Named(ttag.Tag):
        limit = ttag.Arg(keyword=True)
        offset = ttag.Arg(keyword=True)

Which would be used by:
    {% named offset 4 limit 12 %}

If an optional argument is not specified in the template, it will not be
added to the data dictionary. Alternately, use ``default`` to have a default
value added to the data dictionary if an argument is not provided::

    class NamedTag(ttag.Tag):
        limit = ttag.Arg(default=100)
        offset = ttag.Arg(required=False)


Argument Types
==============

``Arg`` and its subclasses provide various other levels of parsing and
validation.


Arg
---

.. class:: Arg(required=True, default=None, null=False, keyword=False, named=False)

    A standard argument in a :class:`Tag`. Used as a base class for all other
    argument classes.

    :param required:
        Whether the argument is required as part of the tag definition in the
        template. Required positional arguments can not occur after optional
        ones. 

        Defaults to ``True``.

    :param default:
        The default value for this argument if it is not specified.

        If ``None`` and the field is required, an exception will be raised when
        the template is parsed.

        Defaults to ``None``.

    :param null:
        Determines whether a value of ``None`` is an acceptable value for the
        argument resolution.

        When set to ``False``, a value of ``None`` or a missing context
        variable will cause a ``TemplateTagValidationError`` when this argument
        is cleaned.

        Defaults to ``False``.

    :param keyword:
        Make this a named argument, using an equals to separate the value
        from the argument name, for example, ``{% tag limit=10 %}``.

        Defaults to ``False``.

    :param named:
        Make this a named argument, using an space to separate the argument
        name from its value, for example, ``{% tag limit 10 %}``. 

        Defaults to ``False``.

    The ``named`` and ``keyword`` parameters can not both be set to ``True``.


Casting Arguments
-----------------

.. class:: IntegerArg

    Tries to cast the argument value to an integer, throwing a template error
    if this fails.


.. class:: StringArg

    Tries to cast the argument value to unicode, throwing a template error if
    this fails.


Validation Arguments
--------------------

.. class:: IsInstanceArg(..., cls, cls_name)

    Validates that the argument is an instance of the provided class (``cls``),
    otherwise throws a a template error, using the ``cls_name`` in the error
    message.

    For example::

    	date = IsInstanceArg(cls=datetime.date, cls_name=_('Date'))


.. class:: DateTimeArg

    Validates that the argument is a ``datetime`` instance, otherwise throws a
    template error.


.. class:: DateArg

    Validates that the argument is a ``date`` instance, otherwise throws a
    template error.


.. class:: TimeArg

    Validates that the argument is a ``time`` instance, otherwise throws a
    template error.


.. class:: ModelInstanceArg(..., model)

    Validates that the passed in value is an instance of the specified
    ``Model`` class.  It requires a single additional named argument.

    :param model:
        The ``Model`` class you want to validate against.


Other Arguments
---------------

.. class:: BooleanArg

    A "flag" argument which doesn't consume any additional tokens.

    If it is not defined in the tag, the argument value will not exist in the
    resolved data dictionary.

    For example::

        class Cool(ttag.Tag)
            cool = ttag.BooleanArg()

            def output(self, data):
                if 'cool' in data:
                    return "That's cool!"
                else:
                    return "Uncool."


.. class:: BasicArg

    A simpler argument which doesn't compile its value as a
    ``FilterExpression``.

    Example usage::

        class GetUsers(ttag.Tag):
            as_ = ttag.BasicArg()

            def render(self, context):
                data = self.resolve(data)
                context[data['as']] = Users.objects.all()
                return '' 


.. class:: ConstantArg

    An argument which expects it's value to be a constant (non-compiled) value,
    usually used to enhance tag readability.

    Cannot be a named or keyword argument.

    Example usage::

        class Range(ttag.Tag):
            start = ttag.IntegerArg()
            to_ = ttag.ConstantArg()
            finish = ttag.IntegerArg()

            def output(self, data):
                start = data['start']
                finish = data['finish'] + 1
                return ', '.join([str(num) for num in range(start, finish)])


.. class:: MultiArg

    Greedily parses all remaining positional arguments.

    Stops when all the tag tokens tokens are consumed or named keyword argument
    is hit. For example::

        class DotConcat(ttag.Tag):
            bits = ttag.MultiArg()
            default = ttag.Arg(named=True, required=False)

            def output(self, data):
                bits = []
                default = data.get('default', '')
                for bit in data['bits']:
                    bits.append([force_unicode(bit) or default])
                return '.'.join(bits)

    This tag could be used like this::

        {% dot_concat "a" "" "c" default "X" %}

    Resulting in ``a.X.c``.


.. class:: KeywordsArg(..., compact=True, verbose=False, compile_values=True)

    Parses one or more additional tokens as keywords.

    :param compact:
        Use compact format. For example::

            {% compact with foo=1 bar=2 %}

    :param verbose:
        Use verbose format::

        	{% verbose with 1 as foo and 2 as bar %}

        In verbose mode, the ``and`` is required for multiple arguments unless
        ``compact`` is also set to ``True`` (in which case the ``and`` is
        optional).

    :param compile_values:
        Compile keyword values as template variables (defaults to ``True``).

    If ``verbose`` and ``compact`` are set to ``True``, then either (or
    even both) formats are allowed. This is usually only used for backwards
    compatibility::

        {% mixed with foo=1 bar=2 %}
        {% mixed with 1 as foo and 2 as bar %}
        {% mixed with foo=1 and 2 as bar %}
