all calls are proxied by context.call now so that we can inject environment and context as first arguments.  This slows calls down a bit but is a lot more user friendly.  Added first draft of FAQ

--HG--
branch : trunk
diff --git a/docs/faq.rst b/docs/faq.rst
new file mode 100644
index 0000000..4b4fab4
--- /dev/null
+++ b/docs/faq.rst
@@ -0,0 +1,123 @@
+Frequently Asked Questions
+==========================
+
+This page answers some of the often asked questions about Jinja.
+
+.. highlight:: html+jinja
+
+
+Why is it called Jinja?
+-----------------------
+
+The name Jinja was chosen because it's the name of a Japanese temple and
+temple and template share a similar pronunciation.  It is not named after
+the capital city of Uganda.
+
+How fast is it?
+---------------
+
+We really hate benchmarks especially since they don't reflect much.  The
+performance of a template depends on many factors and you would have to
+benchmark different engines in different situations.  The benchmarks from the
+testsuite show that Jinja2 has a similar performance to `Mako`_ and is more
+than 20 times faster than Django's template engine or Genshi.  These numbers
+should be taken with tons of salt!
+
+.. _Mako: http://www.makotemplates.org/
+
+How Compatible is Jinja2 with Django?
+-------------------------------------
+
+The default syntax of Jinja2 matches Django syntax in many ways.  However
+this similarity doesn't mean that you can use a Django template unmodified
+in Jinja2.  For example filter arguments use a function call syntax rather
+than a colon to separate filter name and arguments.  Additionally the
+extension interface in Jinja is fundamentally different from the Django one
+which means that your custom tags won't work any longer.
+
+Generally speaking you will use much less custom extensions as the Jinja
+template system allows you to use a certain subset of Python expressions
+which can replace most Django extensions.  For example instead of using
+something like this::
+
+    {% load comments %}
+    {% get_latest_comments 10 as latest_comments %}
+    {% for comment in latest_comments %}
+        ...
+    {% endfor %}
+
+You will most likely provide an object with attributes to retrieve
+comments from the database::
+
+    {% for comment in models.comments.latest(10) %}
+        ...
+    {% endfor %}
+
+Or directly provide the model for quick testing::
+
+    {% for comment in Comment.objects.order_by('-pub_date')[:10] %}
+        ...
+    {% endfor %}
+
+Please keep in mind that even though you may put such things into templates
+it still isn't a good idea.  Queries should go into the view code and now
+the template!
+
+Isn't it a terrible idea to put Logic into Templates?
+-----------------------------------------------------
+
+Without a doubt you should try to remove as much logic from templates as
+possible.  But templates without any logic mean that you have to do all
+the processing in the code which is boring and stupid.  A template engine
+that does that is shipped with Python and called `string.Template`.  Comes
+without loops and if conditions and is by far the fastest template engine
+you can get for Python.
+
+So some amount of logic is required in templates to keep everyone happy.
+And Jinja leaves it pretty much to you how much logic you want to put into
+templates.  There are some restrictions in what you can do and what not.
+
+Jinja2 neither allows you to put arbitrary Python code into templates nor
+does it allow all Python expressions.  The operators are limited to the
+most common ones and more advanced expressions such as list comprehensions
+and generator expressions are not supported.  This keeps the template engine
+easier to maintain and templates more readable.
+
+Why is Autoescaping not the Default?
+------------------------------------
+
+There are multiple reasons why automatic escaping is not the default mode
+and also not the recommended one.  While automatic escaping of variables
+means that you will less likely have an XSS problem it also causes a huge
+amount of extra processing in the template engine which can cause serious
+performance problems.  As Python doesn't provide a way to mark strings as
+unsafe Jinja has to hack around that limitation by providing a custom
+string class (the :class:`Markup` string) that safely interacts with safe
+and unsafe strings.
+
+With explicit escaping however the template engine doesn't have to perform
+any safety checks on variables.  Also a human knows not to escape integers
+or strings that may never contain characters one has to escape or already
+HTML markup.  For example when iterating over a list over a table of
+integers and floats for a table of statistics the template designer can
+omit the escaping because he knows that integers or floats don't contain
+any unsafe parameters.
+
+Additionally Jinja2 is a general purpose template engine and not only used
+for HTML/XML generation.  For example you may generate LaTeX, emails,
+CSS, JavaScript, or configuration files.
+
+Why is the Context immutable?
+-----------------------------
+
+When writing a :func:`contextfunction` or something similar you may have
+noticed that the context tries to stop you from modifying it.  If you have
+managed to modify the context by using an internal context API you may
+have noticed that changes in the context don't seem to be visible in the
+template.  The reason for this is that Jinja uses the context only as
+primary data source for template variables for performance reasons.
+
+If you want to modify the context write a function that returns a variable
+instead that one can assign to a variable by using set::
+
+    {% set comments = get_latest_comments() %}
diff --git a/docs/index.rst b/docs/index.rst
index 43f3680..27bee23 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -17,6 +17,7 @@
    switching
    tricks
 
+   faq
    changelog
 
 If you can't find the information you're looking for, have a look at the
diff --git a/docs/templates.rst b/docs/templates.rst
index a95b874..1576142 100644
--- a/docs/templates.rst
+++ b/docs/templates.rst
@@ -326,6 +326,21 @@
     {% endblock %}
 
 
+Named Block End-Tags
+~~~~~~~~~~~~~~~~~~~~
+
+Jinja2 allows you to put the name of the block after the end tag for better
+readability::
+
+    {% block sidebar %}
+        {% block inner_sidebar %}
+            ...
+        {% endblock inner_sidebar %}
+    {% endblock sidebar %}
+
+However the name after the `endblock` word must match the block name.
+
+
 HTML Escaping
 -------------
 
diff --git a/jinja2/compiler.py b/jinja2/compiler.py
index e43c362..83afc34 100644
--- a/jinja2/compiler.py
+++ b/jinja2/compiler.py
@@ -438,21 +438,13 @@
             self._write_debug_info = node.lineno
             self._last_line = node.lineno
 
-    def signature(self, node, frame, have_comma=True, extra_kwargs=None):
+    def signature(self, node, frame, extra_kwargs=None):
         """Writes a function call to the stream for the current node.
-        Per default it will write a leading comma but this can be
-        disabled by setting have_comma to False.  The extra keyword
+        A leading comma is added automatically.  The extra keyword
         arguments may not include python keywords otherwise a syntax
         error could occour.  The extra keyword arguments should be given
         as python dict.
         """
-        have_comma = have_comma and [True] or []
-        def touch_comma():
-            if have_comma:
-                self.write(', ')
-            else:
-                have_comma.append(True)
-
         # if any of the given keyword arguments is a python keyword
         # we have to make sure that no invalid call is created.
         kwarg_workaround = False
@@ -462,28 +454,25 @@
                 break
 
         for arg in node.args:
-            touch_comma()
+            self.write(', ')
             self.visit(arg, frame)
 
         if not kwarg_workaround:
             for kwarg in node.kwargs:
-                touch_comma()
+                self.write(', ')
                 self.visit(kwarg, frame)
             if extra_kwargs is not None:
                 for key, value in extra_kwargs.iteritems():
-                    touch_comma()
-                    self.write('%s=%s' % (key, value))
+                    self.write(', %s=%s' % (key, value))
         if node.dyn_args:
-            touch_comma()
-            self.write('*')
+            self.write(', *')
             self.visit(node.dyn_args, frame)
 
         if kwarg_workaround:
-            touch_comma()
             if node.dyn_kwargs is not None:
-                self.write('**dict({')
+                self.write(', **dict({')
             else:
-                self.write('**{')
+                self.write(', **{')
             for kwarg in node.kwargs:
                 self.write('%r: ' % kwarg.key)
                 self.visit(kwarg.value, frame)
@@ -499,8 +488,7 @@
                 self.write('}')
 
         elif node.dyn_kwargs is not None:
-            touch_comma()
-            self.write('**')
+            self.write(', **')
             self.visit(node.dyn_kwargs, frame)
 
     def pull_locals(self, frame):
@@ -1353,11 +1341,12 @@
 
     def visit_Call(self, node, frame, forward_caller=False):
         if self.environment.sandboxed:
-            self.write('environment.call(')
+            self.write('environment.call(context, ')
+        else:
+            self.write('context.call(')
         self.visit(node.node, frame)
-        self.write(self.environment.sandboxed and ', ' or '(')
         extra_kwargs = forward_caller and {'caller': 'caller'} or None
-        self.signature(node, frame, False, extra_kwargs)
+        self.signature(node, frame, extra_kwargs)
         self.write(')')
 
     def visit_Keyword(self, node, frame):
diff --git a/jinja2/nodes.py b/jinja2/nodes.py
index 568220f..9eb5460 100644
--- a/jinja2/nodes.py
+++ b/jinja2/nodes.py
@@ -14,7 +14,6 @@
 """
 import operator
 from copy import copy
-from types import FunctionType
 from itertools import chain, izip
 from collections import deque
 from jinja2.utils import Markup
@@ -550,11 +549,10 @@
 
         # don't evaluate context functions
         args = [x.as_const() for x in self.args]
-        if type(obj) is FunctionType:
-            if getattr(obj, 'contextfunction', False):
-                raise Impossible()
-            elif obj.environmentfunction:
-                args.insert(0, self.environment)
+        if getattr(obj, 'contextfunction', False):
+            raise Impossible()
+        elif getattr(obj, 'environmentfunction', False):
+            args.insert(0, self.environment)
 
         kwargs = dict(x.as_const() for x in self.kwargs)
         if self.dyn_args is not None:
diff --git a/jinja2/parser.py b/jinja2/parser.py
index 86ee570..8ca1bd2 100644
--- a/jinja2/parser.py
+++ b/jinja2/parser.py
@@ -150,6 +150,7 @@
         node = nodes.Block(lineno=self.stream.next().lineno)
         node.name = self.stream.expect('name').value
         node.body = self.parse_statements(('name:endblock',), drop_needle=True)
+        self.stream.skip_if('name:' + node.name)
         return node
 
     def parse_extends(self):
diff --git a/jinja2/runtime.py b/jinja2/runtime.py
index fb72ed4..1325b17 100644
--- a/jinja2/runtime.py
+++ b/jinja2/runtime.py
@@ -66,14 +66,6 @@
         self.exported_vars = set()
         self.name = name
 
-        # bind functions to the context of environment if required
-        for name, obj in parent.iteritems():
-            if type(obj) is FunctionType:
-                if getattr(obj, 'contextfunction', 0):
-                    vars[name] = partial(obj, self)
-                elif getattr(obj, 'environmentfunction', 0):
-                    vars[name] = partial(obj, environment)
-
         # create the initial mapping of blocks.  Whenever template inheritance
         # takes place the runtime will update this mapping with the new blocks
         # from the template.
@@ -122,6 +114,17 @@
         """
         return dict(self.parent, **self.vars)
 
+    def call(__self, __obj, *args, **kwargs):
+        """Called by the template code to inject the current context
+        or environment as first arguments.  Then forwards the call to
+        the object with the arguments and keyword arguments.
+        """
+        if getattr(__obj, 'contextfunction', 0):
+            args = (__self,) + args
+        elif getattr(__obj, 'environmentfunction', 0):
+            args = (__self.environment,) + args
+        return __obj(*args, **kwargs)
+
     def _all(meth):
         proxy = lambda self: getattr(self.get_all(), meth)()
         proxy.__doc__ = getattr(dict, meth).__doc__
diff --git a/jinja2/sandbox.py b/jinja2/sandbox.py
index c558c73..b0de8e7 100644
--- a/jinja2/sandbox.py
+++ b/jinja2/sandbox.py
@@ -190,13 +190,13 @@
                 ), name=argument, exc=SecurityError)
         return self.undefined(obj=obj, name=argument)
 
-    def call(__self, __obj, *args, **kwargs):
+    def call(__self, __context, __obj, *args, **kwargs):
         """Call an object from sandboxed code."""
         # the double prefixes are to avoid double keyword argument
         # errors when proxying the call.
         if not __self.is_safe_callable(__obj):
             raise SecurityError('%r is not safely callable' % (__obj,))
-        return __obj(*args, **kwargs)
+        return __context.call(__obj, *args, **kwargs)
 
 
 class ImmutableSandboxedEnvironment(SandboxedEnvironment):
diff --git a/jinja2/utils.py b/jinja2/utils.py
index 2a671d0..258961f 100644
--- a/jinja2/utils.py
+++ b/jinja2/utils.py
@@ -64,8 +64,8 @@
 
 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 if it
-    was directly stored in the context.
+    context callable is passed the active context as first argument when
+    called from the template.
     """
     f.contextfunction = True
     return f
@@ -74,7 +74,7 @@
 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
-    if it was directly stored in the context.
+    when called from the template.
     """
     f.environmentfunction = True
     return f
diff --git a/tests/test_syntax.py b/tests/test_syntax.py
index b76fe5f..717e165 100644
--- a/tests/test_syntax.py
+++ b/tests/test_syntax.py
@@ -6,6 +6,7 @@
     :copyright: 2007 by Armin Ronacher.
     :license: BSD, see LICENSE for more details.
 """
+from py.test import raises
 from jinja2 import Environment, DictLoader
 from jinja2.exceptions import TemplateSyntaxError
 
@@ -143,11 +144,7 @@
     ]
     for should_fail, sig in tests:
         if should_fail:
-            try:
-                print env.from_string('{{ foo(%s) }}' % sig)
-            except TemplateSyntaxError:
-                continue
-            assert False, 'expected syntax error'
+            raises(TemplateSyntaxError, env.from_string, '{{ foo(%s) }}' % sig)
         else:
             env.from_string('foo(%s)' % sig)
 
@@ -161,3 +158,8 @@
 def test_trailing_comma(env):
     tmpl = env.from_string(TRAILINGCOMMA)
     assert tmpl.render().lower() == '(1, 2)|[1, 2]|{1: 2}'
+
+
+def test_block_end_name(env):
+    env.from_string('{% block foo %}...{% endblock foo %}')
+    raises(TemplateSyntaxError, env.from_string, '{% block x %}{% endblock y %}')