some more documentation updates and minor code cleanups.  Additionally True and true in the template are the same now, same for false/False and none/None.

--HG--
branch : trunk
diff --git a/jinja2/__init__.py b/jinja2/__init__.py
index cd720a6..194390a 100644
--- a/jinja2/__init__.py
+++ b/jinja2/__init__.py
@@ -50,7 +50,7 @@
 # decorators and public utilities
 from jinja2.filters import environmentfilter, contextfilter
 from jinja2.utils import Markup, escape, clear_caches, \
-     environmentfunction, contextfunction
+     environmentfunction, contextfunction, is_undefined
 
 __all__ = [
     'Environment', 'Template', 'BaseLoader', 'FileSystemLoader',
@@ -59,5 +59,5 @@
     'TemplateError', 'UndefinedError', 'TemplateNotFound',
     'TemplateSyntaxError', 'TemplateAssertionError', 'environmentfilter',
     'contextfilter', 'Markup', 'escape', 'environmentfunction',
-    'contextfunction', 'clear_caches'
+    'contextfunction', 'clear_caches', 'is_undefined'
 ]
diff --git a/jinja2/_speedups.c b/jinja2/_speedups.c
index f691c78..8a9a108 100644
--- a/jinja2/_speedups.c
+++ b/jinja2/_speedups.c
@@ -187,7 +187,7 @@
 static PyMethodDef module_methods[] = {
 	{"escape", (PyCFunction)escape, METH_O,
 	 "escape(s) -> markup\n\n"
-	 "Convert the characters &, <, >, and \" in string s to HTML-safe\n"
+	 "Convert the characters &, <, >, ', and \" in string s to HTML-safe\n"
 	 "sequences.  Use this if you need to display text that might contain\n"
 	 "such characters in HTML.  Marks return value as markup string."},
 	{"soft_unicode", (PyCFunction)soft_unicode, METH_O,
diff --git a/jinja2/filters.py b/jinja2/filters.py
index 0a32f9a..762b06d 100644
--- a/jinja2/filters.py
+++ b/jinja2/filters.py
@@ -23,8 +23,8 @@
 
 
 def contextfilter(f):
-    """Decorator for marking context dependent filters. The current context
-    argument will be passed as first argument.
+    """Decorator for marking context dependent filters. The current
+    :class:`Context` will be passed as first argument.
     """
     if getattr(f, 'environmentfilter', False):
         raise TypeError('filter already marked as environment filter')
@@ -33,8 +33,8 @@
 
 
 def environmentfilter(f):
-    """Decorator for marking evironment dependent filters.  The environment
-    used for the template is passed to the filter as first argument.
+    """Decorator for marking evironment dependent filters.  The current
+    :class:`Environment` is passed to the filter as first argument.
     """
     if getattr(f, 'contextfilter', False):
         raise TypeError('filter already marked as context filter')
@@ -578,7 +578,8 @@
 
 class _GroupTuple(tuple):
     __slots__ = ()
-    grouper, list = (property(itemgetter(x)) for x in xrange(2))
+    grouper = property(itemgetter(0))
+    list = property(itemgetter(1))
 
     def __new__(cls, (key, value)):
         return tuple.__new__(cls, (key, list(value)))
diff --git a/jinja2/nodes.py b/jinja2/nodes.py
index 0cccddf..f4b1f32 100644
--- a/jinja2/nodes.py
+++ b/jinja2/nodes.py
@@ -400,7 +400,8 @@
     fields = ('name', 'ctx')
 
     def can_assign(self):
-        return self.name not in ('true', 'false', 'none')
+        return self.name not in ('true', 'false', 'none',
+                                 'True', 'False', 'None')
 
 
 class Literal(Expr):
diff --git a/jinja2/parser.py b/jinja2/parser.py
index 0ce4a29..7efe79c 100644
--- a/jinja2/parser.py
+++ b/jinja2/parser.py
@@ -454,9 +454,10 @@
     def parse_primary(self, with_postfix=True):
         token = self.stream.current
         if token.type is 'name':
-            if token.value in ('true', 'false'):
-                node = nodes.Const(token.value == 'true', lineno=token.lineno)
-            elif token.value == 'none':
+            if token.value in ('true', 'false', 'True', 'False'):
+                node = nodes.Const(token.value in ('true', 'True'),
+                                   lineno=token.lineno)
+            elif token.value in ('none', 'None'):
                 node = nodes.Const(None, lineno=token.lineno)
             else:
                 node = nodes.Name(token.value, 'load', lineno=token.lineno)
diff --git a/jinja2/runtime.py b/jinja2/runtime.py
index babc3c9..2dbd569 100644
--- a/jinja2/runtime.py
+++ b/jinja2/runtime.py
@@ -117,6 +117,11 @@
         return dict(self.parent, **self.vars)
 
     def call(__self, __obj, *args, **kwargs):
+        """Call the callable with the arguments and keyword arguments
+        provided but inject the active context or environment as first
+        argument if the callable is a :func:`contextfunction` or
+        :func:`environmentfunction`.
+        """
         if __debug__:
             __traceback_hide__ = True
         if isinstance(__obj, _context_function_types):
@@ -160,6 +165,14 @@
         )
 
 
+# register the context as mutable mapping if possible
+try:
+    from collections import MutableMapping
+    MutableMapping.register(Context)
+except ImportError:
+    pass
+
+
 class TemplateReference(object):
     """The `self` in templates."""
 
@@ -321,28 +334,6 @@
         )
 
 
-def fail_with_undefined_error(self, *args, **kwargs):
-    """Regular callback function for undefined objects that raises an
-    `UndefinedError` on call.
-    """
-    if self._undefined_hint is None:
-        if self._undefined_obj is None:
-            hint = '%r is undefined' % self._undefined_name
-        elif not isinstance(self._undefined_name, basestring):
-            hint = '%r object has no element %r' % (
-                self._undefined_obj.__class__.__name__,
-                self._undefined_name
-            )
-        else:
-            hint = '%r object has no attribute %r' % (
-                self._undefined_obj.__class__.__name__,
-                self._undefined_name
-            )
-    else:
-        hint = self._undefined_hint
-    raise self._undefined_exception(hint)
-
-
 class Undefined(object):
     """The default undefined type.  This undefined type can be printed and
     iterated over, but every other access will raise an :exc:`UndefinedError`:
@@ -366,18 +357,36 @@
         self._undefined_name = name
         self._undefined_exception = exc
 
+    def _fail_with_undefined_error(self, *args, **kwargs):
+        """Regular callback function for undefined objects that raises an
+        `UndefinedError` on call.
+        """
+        if self._undefined_hint is None:
+            if self._undefined_obj is None:
+                hint = '%r is undefined' % self._undefined_name
+            elif not isinstance(self._undefined_name, basestring):
+                hint = '%r object has no element %r' % (
+                    self._undefined_obj.__class__.__name__,
+                    self._undefined_name
+                )
+            else:
+                hint = '%r object has no attribute %r' % (
+                    self._undefined_obj.__class__.__name__,
+                    self._undefined_name
+                )
+        else:
+            hint = self._undefined_hint
+        raise self._undefined_exception(hint)
+
     __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
     __realdiv__ = __rrealdiv__ = __floordiv__ = __rfloordiv__ = \
     __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
     __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
-        fail_with_undefined_error
+    __int__ = __float__ = __complex__ = _fail_with_undefined_error
 
     def __str__(self):
         return self.__unicode__().encode('utf-8')
 
-    def __repr__(self):
-        return 'Undefined'
-
     def __unicode__(self):
         return u''
 
@@ -391,6 +400,9 @@
     def __nonzero__(self):
         return False
 
+    def __repr__(self):
+        return 'Undefined'
+
 
 class DebugUndefined(Undefined):
     """An undefined that returns the debug info when printed.
@@ -439,7 +451,7 @@
     """
     __slots__ = ()
     __iter__ = __unicode__ = __len__ = __nonzero__ = __eq__ = __ne__ = \
-        fail_with_undefined_error
+        Undefined._fail_with_undefined_error
 
 
 # remove remaining slots attributes, after the metaclass did the magic they
diff --git a/jinja2/utils.py b/jinja2/utils.py
index e064a25..6d1c958 100644
--- a/jinja2/utils.py
+++ b/jinja2/utils.py
@@ -63,23 +63,47 @@
 
 
 def contextfunction(f):
-    """This decorator can be used to mark a callable as context callable.  A
-    context callable is passed the active context as first argument when
-    called from the template.
+    """This decorator can be used to mark a function or method context callable.
+    A context callable is passed the active :class:`Context` as first argument when
+    called from the template.  This is useful if a function wants to get access
+    to the context or functions provided on the context object.  For example
+    a function that returns a sorted list of template variables the current
+    template exports could look like this::
+
+        @contextcallable
+        def get_exported_names(context):
+            return sorted(context.exported_vars)
     """
     f.contextfunction = True
     return f
 
 
 def environmentfunction(f):
-    """This decorator can be used to mark a callable as environment callable.
-    A environment callable is passed the current environment as first argument
-    when called from the template.
+    """This decorator can be used to mark a function or method as environment
+    callable.  This decorator works exactly like the :func:`contextfunction`
+    decorator just that the first argument is the active :class:`Environment`
+    and not context.
     """
     f.environmentfunction = True
     return f
 
 
+def is_undefined(obj):
+    """Check if the object passed is undefined.  This does nothing more than
+    performing an instance check against :class:`Undefined` but looks nicer.
+    This can be used for custom filters or tests that want to react to
+    undefined variables.  For example a custom default filter can look like
+    this::
+
+        def default(var, default=''):
+            if is_undefined(var):
+                return default
+            return var
+    """
+    from jinja2.runtime import Undefined
+    return isinstance(obj, Undefined)
+
+
 def clear_caches():
     """Jinja2 keeps internal caches for environments and lexers.  These are
     used so that Jinja2 doesn't have to recreate environments and lexers all
@@ -532,6 +556,14 @@
     __copy__ = copy
 
 
+# register the LRU cache as mutable mapping if possible
+try:
+    from collections import MutableMapping
+    MutableMapping.register(LRUCache)
+except ImportError:
+    pass
+
+
 # we have to import it down here as the speedups module imports the
 # markup type which is define above.
 try: