improve documentation for embed tag
authorliteral <github@imbt.de>
Thu, 10 May 2012 00:10:48 +0000 (03:10 +0300)
committerliteral <github@imbt.de>
Thu, 10 May 2012 00:10:48 +0000 (03:10 +0300)
doc/tags/embed.rst

index b75f557..454f11c 100644 (file)
@@ -4,64 +4,82 @@
 .. versionadded:: 1.8
     The ``embed`` tag was added in Twig 1.8.
 
-The ``embed`` statement allows you to embed a template instead of including it
-from an external file (like with the ``include`` statement):
+The ``embed`` tag combines the behaviour of :doc:`include<include>` and
+:doc:`extends<extends>`.
+It allows you to include another template's contents, just like ``include``
+does. But it also allows you to override any block defined inside the
+included template, like when extending a template.
+
+Think of an embedded template as a "micro layout skeleton".
 
 .. code-block:: jinja
 
-    {% embed "sidebar.twig" %}
-        {% block content %}
-            Some content for the sidebar
+    {% embed "teasers_skeleton.twig" %}
+        {# These blocks are defined in "teasers_skeleton.twig" #}
+        {# and we override them right here:                    #}
+        {% block left_teaser %}
+            Some content for the left teaser box
+        {% endblock %}
+        {% block right_teaser %}
+            Some content for the right teaser box
         {% endblock %}
     {% endembed %}
 
-As it's not easy to understand in which circumstances it might come in handy,
-let's take an example; imagine a base template shared by many pages with a
-single block:
+The ``embed`` tag takes the idea of template inheritance to the level of
+content fragments. While template inheritance allows for "document skeletons",
+which are filled with life by child templates, the ``embed`` tag allows you to
+create "skeletons" for smaller units of content and re-use and fill them
+anywhere you like.
+
+Since the use case may not be obvious, let's look at a simplified example.
+Imagine a base template shared by multiple HTML pages, defining a single block
+named "content":
 
 .. code-block:: text
 
-    ┌─── Page n ──────────────────────────┐
+    ┌─── page layout ─────────────────────┐
     │                                     │
-    │           ┌─────────────────────┐   │
-    │           │                     │   │
-    │           │                     │   │
+    │           ┌── block "content" ──┐   │
     │           │                     │   │
     │           │                     │   │
+    │           │ (child template to  │   │
+    │           │  put content here)  │   │
     │           │                     │   │
     │           │                     │   │
     │           └─────────────────────┘   │
     │                                     │
     └─────────────────────────────────────┘
 
-Some pages (page 1, 2, ...) share the same structure for the block:
+Some pages ("foo" and "bar") share the same content structure -
+two vertically stacked boxes:
 
 .. code-block:: text
 
-    ┌─── Page 1 & 2 ──────────────────────┐
+    ┌─── page layout ─────────────────────┐
     │                                     │
-    │           ┌── Base A ───────────┐   │
-    │           │ ┌── content1 ─────┐ │   │
-    │           │ │ content for p1  │ │   │
+    │           ┌── block "content" ──┐   │
+    │           │ ┌─ block "top" ───┐ │   │
+    │           │ │                 │ │   │
     │           │ └─────────────────┘ │   │
-    │           │ ┌── content2 ─────┐ │   │
-    │           │ │ content for p1  │ │   │
+    │           │ ┌─ block "bottom" ┐ │   │
+    │           │ │                 │ │   │
     │           │ └─────────────────┘ │   │
     │           └─────────────────────┘   │
     │                                     │
     └─────────────────────────────────────┘
 
-While other pages (page a, b, ...) share a different structure for the block:
+While other pages ("boom" and "baz") share a different content structure -
+two boxes side by side:
 
 .. code-block:: text
 
-    ┌─── Page a, b ───────────────────────┐
+    ┌─── page layout ─────────────────────┐
     │                                     │
-    │           ┌── Base B ───────────┐   │
-    │           │ ┌───────┐ ┌───────┐ │   │
+    │           ┌── block "content" ──┐   │
+    │           │                     │   │    
+    │           │ ┌ block ┐ ┌ block ┐ │   │
+    │           │ │"left" │ │"right"│ │   │
     │           │ │       │ │       │ │   │
-    │           │ │content│ │content│ │   │
-    │           │ │a, ... │ │b, ... │ │   │
     │           │ │       │ │       │ │   │
     │           │ └───────┘ └───────┘ │   │
     │           └─────────────────────┘   │
@@ -70,64 +88,68 @@ While other pages (page a, b, ...) share a different structure for the block:
 
 Without the ``embed`` tag, you have two ways to design your templates:
 
- * Create two base templates (one for 1, 2, ... blocks and another one for a,
-   b, ... blocks) to factor out the common template code, then one template
-   for each page that inherits from one of the base template;
+ * Create two "intermediate" base templates that extend the master layout
+   template: one with vertically stacked boxes to be used by the "foo" and
+   "bar" pages and another one with side-by-side boxes for the "boom" and
+   "baz" pages.
 
- * Embed each custom page content directly into each page without any use of
-   external templates (you need to repeat the common code for all templates).
+ * Embed the markup for the top/bottom and left/right boxes into each page 
+   template directly.
 
 These two solutions do not scale well because they each have a major drawback:
 
- * The first solution makes you create many external files (that you won't
-   re-use anywhere else) and so it fails to keep your templates readable (many
-   code and content are out of context);
+ * The first solution may indeed work for this simplified example. But imagine
+   we add a sidebar, which may again contain different, recurring structures
+   of content. Now we would need to create intermediate base templates for
+   all occurring combinations of content structure and sidebar structure...
+   and so on.
 
- * The second solution makes you duplicate some common code from one template
-   to another (so it fails to obey the "Don't repeat yourself" principle).
+ * The second solution involves duplication of common code with all its negative
+   consequences: any change involves finding and editing all affected copies
+   of the structure, correctness has to be verified for each copy, copies may
+   go out of sync by careless modifications etc.
 
-In such a situation, the ``embed`` tag fixes all these issues. The common code
-can be factored out in base templates (as in solution 1), and the custom
-content is kept in each page (as in solution 2):
+In such a situation, the ``embed`` tag comes in handy. The common layout
+code can live in a single base template, and the two different content structures,
+let's call them "micro layouts" go into separate templates which are embedded
+as necessary:
 
-.. code-block:: jinja
+Page template ``foo.twig``:
 
-    {# template for pages 1, 2, ... #}
+.. code-block:: jinja
 
-    {% extends page %}
+    {% extends "layout_skeleton.twig" %}
 
-    {% block base %}
-        {% embed "base_A.twig" %}
-            {% block content1 %}
-                Content 1 for page 2
+    {% block content %}
+        {% embed "vertical_boxes_skeleton.twig" %}
+            {% block top %}
+                Some content for the top box
             {% endblock %}
 
-            {% block content2 %}
-                Content 2 for page 2
+            {% block bottom %}
+                Some content for the bottom box
             {% endblock %}
         {% endembed %}
     {% endblock %}
 
-And here is the code for ``base_A.twig``:
+And here is the code for ``vertical_boxes_skeleton.twig``:
 
-.. code-block:: jinja
+.. code-block:: html+jinja
 
-    Some code
-
-    {% block content1 %}
-        Some default content
-    {% endblock %}
-
-    Some other code
-
-    {% block content2 %}
-        Some default content
-    {% endblock %}
+    <div class="top_box">
+        {% block content1 %}
+            Top box default content
+        {% endblock %}
+    </div>
 
-    Yet some other code
+    <div class="bottom_box">
+        {% block content2 %}
+            Bottom box default content
+        {% endblock %}
+    </div>
 
-The goal of the ``base_a.twig`` base template being to factor out the ``Some
-code``, ``Some other code``, and ``Yet some other code`` parts.
+The goal of the ``vertical_boxes_skeleton.twig`` template being to factor
+out the HTML markup for the boxes.
 
 The ``embed`` tag takes the exact same arguments as the ``include`` tag: