From 8c379296cad4b307897d1c9e6d73d40fa66c18ed Mon Sep 17 00:00:00 2001 From: Ilya Puchka Date: Sat, 30 Dec 2017 03:02:18 +0100 Subject: [PATCH 1/3] Cache rendered blocks content to reuse them in further calls --- Sources/Stencil/Context.swift | 15 +++++++++++++++ Sources/Stencil/Inheritance.swift | 4 +++- Tests/StencilTests/InheritanceSpec.swift | 18 ++++++++++++++++++ Tests/StencilTests/fixtures/base-repeat.html | 5 +++++ Tests/StencilTests/fixtures/child-repeat.html | 3 +++ 5 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 Tests/StencilTests/fixtures/base-repeat.html create mode 100644 Tests/StencilTests/fixtures/child-repeat.html diff --git a/Sources/Stencil/Context.swift b/Sources/Stencil/Context.swift index 1858694..b4a0b2a 100644 --- a/Sources/Stencil/Context.swift +++ b/Sources/Stencil/Context.swift @@ -85,4 +85,19 @@ public class Context { return accumulator } + + /// Cache result of block by its name in the context top-level, so that it can be later rendered + /// via `{{ block.name }}` + /// + /// - Parameters: + /// - name: The name of the stored block + /// - content: The block's rendered content + public func cacheBlock(_ name: String, content: String) { + if var block = dictionaries.first?["block"] as? [String: String] { + block[name] = content + dictionaries[0]["block"] = block + } else { + dictionaries.insert(["block": [name: content]], at: 0) + } + } } diff --git a/Sources/Stencil/Inheritance.swift b/Sources/Stencil/Inheritance.swift index 1f75e9b..971ded1 100644 --- a/Sources/Stencil/Inheritance.swift +++ b/Sources/Stencil/Inheritance.swift @@ -151,6 +151,8 @@ class BlockNode: NodeType { } } - return try renderNodes(nodes, context) + let result = try renderNodes(nodes, context) + context.cacheBlock(name, content: result) + return result } } diff --git a/Tests/StencilTests/InheritanceSpec.swift b/Tests/StencilTests/InheritanceSpec.swift index e16d83e..117b605 100644 --- a/Tests/StencilTests/InheritanceSpec.swift +++ b/Tests/StencilTests/InheritanceSpec.swift @@ -52,4 +52,22 @@ final class InheritanceTests: XCTestCase { """ } } + + func testInheritanceCache() { + it("can call block twice") { + let template: Template = "{% block repeat %}Block{% endblock %}{{ block.repeat }}" + try expect(try template.render()) == "BlockBlock" + } + + it("renders child content when calling block twice in base template") { + let template = try self.environment.loadTemplate(name: "child-repeat.html") + try expect(try template.render()) == """ + Super_Header Child_Header + Child_Body + Repeat + Super_Header Child_Header + Child_Body + """ + } + } } diff --git a/Tests/StencilTests/fixtures/base-repeat.html b/Tests/StencilTests/fixtures/base-repeat.html new file mode 100644 index 0000000..310b3b1 --- /dev/null +++ b/Tests/StencilTests/fixtures/base-repeat.html @@ -0,0 +1,5 @@ +{% block header %}Header{% endblock %} +{% block body %}Body{% endblock %} +Repeat +{{ block.header }} +{{ block.body }} \ No newline at end of file diff --git a/Tests/StencilTests/fixtures/child-repeat.html b/Tests/StencilTests/fixtures/child-repeat.html new file mode 100644 index 0000000..088b2b4 --- /dev/null +++ b/Tests/StencilTests/fixtures/child-repeat.html @@ -0,0 +1,3 @@ +{% extends "base-repeat.html" %} +{% block header %}Super_{{ block.super }} Child_Header{% endblock %} +{% block body %}Child_Body{% endblock %} From 67f94aa9f008dc2bf0fa1ea305e01be3d7d3b7e3 Mon Sep 17 00:00:00 2001 From: Ilya Puchka Date: Tue, 11 Sep 2018 18:55:30 +0100 Subject: [PATCH 2/3] Update docs --- docs/templates.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/templates.rst b/docs/templates.rst index d325635..0e605af 100644 --- a/docs/templates.rst +++ b/docs/templates.rst @@ -141,7 +141,7 @@ Let's take a look at an example. Here is our base template (``base.html``): This example declares three blocks, ``title``, ``sidebar`` and ``content``. We -can use the ``{% extends %}`` template tag to inherit from out base template +can use the ``{% extends %}`` template tag to inherit from our base template and then use ``{% block %}`` to override any blocks from our base template. A child template might look like the following: @@ -195,3 +195,5 @@ inheritance is the following three-level approach: extend ``base.html`` and include section-specific styles/design. * Create individual templates for each type of page, such as a news article or blog entry. These templates extend the appropriate section template. + +You can render block's content more than once by using ``{{ block.name }}`` **after** a block is defined. From 41e0c9c9e0d37fb4f6982f474722dfe1060e3837 Mon Sep 17 00:00:00 2001 From: Ilya Puchka Date: Tue, 11 Sep 2018 18:52:30 +0100 Subject: [PATCH 3/3] Changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9871788..56c7324 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,10 @@ - Added support for adding default whitespace trimming behaviour to an environment. [Yonas Kolb](https://github.com/yonaskolb) [#287](https://github.com/stencilproject/Stencil/pull/287) +- Blocks now can be used repeatedly in the template. When block is rendered for the first time its content will be cached and it can be rendered again later using `{{ block.block_name }}`. + [Ilya Puchka](https://github.com/ilyapuchka) + [#158](https://github.com/stencilproject/Stencil/issues/158) + [#182](https://github.com/stencilproject/Stencil/pull/182) ### Deprecations