diff --git a/Sources/Context.swift b/Sources/Context.swift index 418aa5e..53de1a3 100644 --- a/Sources/Context.swift +++ b/Sources/Context.swift @@ -52,4 +52,16 @@ public class Context { defer { _ = pop() } return try closure() } + + public func flatten() -> [String: Any] { + var accumulator: [String: Any] = [:] + + for dictionary in dictionaries { + for (key, value) in dictionary { + accumulator.updateValue(value, forKey: key) + } + } + + return accumulator + } } diff --git a/Tests/StencilTests/ContextSpec.swift b/Tests/StencilTests/ContextSpec.swift index f4933e9..93fbd04 100644 --- a/Tests/StencilTests/ContextSpec.swift +++ b/Tests/StencilTests/ContextSpec.swift @@ -58,5 +58,15 @@ func testContext() { try expect(didRun).to.beTrue() try expect(context["name"] as? String) == "Kyle" } + + $0.it("allows you to flatten the context contents") { + try context.push(dictionary: ["test": "abc"]) { + let flattened = context.flatten() + + try expect(flattened.count) == 2 + try expect(flattened["name"] as? String) == "Kyle" + try expect(flattened["test"] as? String) == "abc" + } + } } } diff --git a/docs/api/context.rst b/docs/api/context.rst new file mode 100644 index 0000000..113cefb --- /dev/null +++ b/docs/api/context.rst @@ -0,0 +1,51 @@ +Context +======= + +A Context is a structure containing any templates you would like to use in a +template. It’s somewhat like a dictionary, however you can push and pop to +scope variables. So that means that when iterating over a for loop, you can +push a new scope into the context to store any variables local to the scope. + +You can initialise a ``Context`` with a ``Dictionary``. + +.. code-block:: swift + + Context(dictionary: [String: Any]? = nil) + +API +---- + +Subscripting +~~~~~~~~~~~~ + +You can use subscripting to get and set values from the context. + +.. code-block:: swift + + context["key"] = value + let value = context["key"] + +``push()`` +~~~~~~~~~~ + +A ``Context`` is a stack. You can push a new level onto the ``Context`` so that +modifications can easily be poped off. This is useful for isolating mutations +into scope of a template tag. Such as ``{% if %}`` and ``{% for %}`` tags. + +.. code-block:: swift + + context.push(["name": "example"]) { + // context contains name which is `example`. + } + + // name is popped off the context after the duration of the closure. + +``flatten()`` +~~~~~~~~~~~~~ + +Using ``flatten()`` method you can get whole ``Context`` stack as one +dictionary including all variables. + +.. code-block:: swift + + let dictionary = context.flatten() diff --git a/docs/index.rst b/docs/index.rst index d662b7c..a2c0c5b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -39,4 +39,5 @@ Contents: templates builtins + api/context custom-template-tags-and-filters