Skip to content

Commit

Permalink
Merge pull request #23 from art4ride/master
Browse files Browse the repository at this point in the history
global_filter
  • Loading branch information
Wijnand authored Sep 16, 2016
2 parents b1b6096 + 7cdad2a commit d4b6471
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 9 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ Another option is to set up the tag using:
and for filters you should use
`Liquid.Filters.add_filters(MyFilters)`

#### Global Filters
It's also possible to apply global filter to all rendered variables setting up the config:
``` elixir
# config.exs
config :liquid,
global_filter: &MyFilter.counting_sheeps/1
```
or adding a `"global_filter"` value to context for `Liquid.Template.render` function:
`Liquid.Template.render(tpl, %{global_filter: &MyFilter.counting_sheeps/1})` (you need to define filter function first)

## File systems
You can also set up the desired default file system for your project using the `config.exs` file
``` elixir
Expand Down
2 changes: 1 addition & 1 deletion lib/liquid.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule Liquid do

def start do
Liquid.Filters.add_filter_modules
Liquid.Supervisor.start_link()
Liquid.Supervisor.start_link
end

def stop, do: {:ok, "stopped"}
Expand Down
2 changes: 1 addition & 1 deletion lib/liquid/context.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule Liquid.Context do
defstruct assigns: %{}, offsets: %{}, registers: %{}, presets: %{}, blocks: [],
extended: false, continue: false, break: false, template: nil
extended: false, continue: false, break: false, template: nil, global_filter: nil

def registers(context, key) do
context.registers |> Map.get(key)
Expand Down
26 changes: 21 additions & 5 deletions lib/liquid/template.ex
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
defmodule Liquid.Template do
@moduledoc"""
Main Liquid module, all further render and parse processing passes through it
"""

defstruct root: nil, presets: %{}, blocks: []
alias Liquid.Template, as: Template
alias Liquid.Render, as: Render
alias Liquid.Context, as: Context
alias Liquid.{Template, Render, Context}

def render(t, c \\ %{})#, do: render(t, %{})
@doc """
Function that renders passed template and context to string
"""
@file "render.ex"
@spec render(Liquid.Template, map) :: String.t
def render(t, c \\ %{})
def render(%Template{}=t, %Context{}=c) do
c = %{c | blocks: t.blocks }
c = %{c | presets: t.presets }
Expand All @@ -14,14 +21,23 @@ defmodule Liquid.Template do

def render(%Template{}=t, assigns) when is_map(assigns) do
context = %Context{template: t, assigns: assigns,
presets: t.presets, blocks: t.blocks}
presets: t.presets, blocks: t.blocks}
context = case {Map.has_key?(assigns,"global_filter"), Map.has_key?(assigns,:global_filter)} do
{true,_} -> %{context|global_filter: Map.fetch!(assigns, "global_filter")}
{_,true} -> %{context|global_filter: Map.fetch!(assigns, :global_filter)}
_ -> context
end
Render.render(t, context)
end

def render(_, _) do
raise Liquid.SyntaxError, message: "You can use only maps/structs to hold context data"
end

@doc """
Function to parse markup with given presets (if any)
"""
@spec render(String.t, map) :: Liquid.Template
def parse(<<markup::binary>>, presets \\ %{}) do
Liquid.Parse.parse(markup, %Template{presets: presets})
end
Expand Down
14 changes: 12 additions & 2 deletions lib/liquid/variable.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,24 @@ defmodule Liquid.Variable do
def lookup(%Variable{}=v, %Context{}=context) do
{ ret, filters } = Liquid.Appointer.assign(v, context)
try do
filters |> Filters.filter(ret)
filters |> Filters.filter(ret) |> apply_global_filter(context)
rescue
e in UndefinedFunctionError -> e.message
e in UndefinedFunctionError -> e.reason
e in ArgumentError -> e.message
e in ArithmeticError -> "Liquid error: #{e.message}"
end
end

defp apply_global_filter(input, %Context{global_filter: nil}) do
case Application.get_env(:liquid, :global_filter) do
nil -> input
filter -> input |> filter.()
end
end

defp apply_global_filter(input, %Context{}=context),
do: input |> context.global_filter.()


@doc """
Parses the markup to a list of filters
Expand Down
42 changes: 42 additions & 0 deletions test/liquid/global_filter_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Code.require_file "../../test_helper.exs", __ENV__.file
defmodule Liquid.GlobalFilterTest do
use ExUnit.Case, async: false
alias Liquid.Template

defmodule MyFilter do
def counting_sheeps(input) when is_binary(input), do: input <>" One, two, thr.. z-zz.."
def counting_bees(input) when is_binary(input), do: input <>" One, tw.. Ouch!"
end

setup_all do
Application.put_env(:liquid, :global_filter, &MyFilter.counting_sheeps/1)
Liquid.start
on_exit fn -> Liquid.stop Application.delete_env(:liquid, :global_filter) end
:ok
end

test "env default filter applied" do
assert_template_result "Initial One, two, thr.. z-zz..", "{{ 'initial' | capitalize }}"
end

test "preset filter overrides default applied" do
assert_template_result "Initial One, tw.. Ouch!",
"{{ 'initial' | capitalize }}", %{global_filter: &MyFilter.counting_bees/1}
end


defp assert_template_result(expected, markup, assigns \\ %{}) do
assert_result(expected, markup, assigns)
end

defp assert_result(expected, markup, assigns) do
template = Template.parse(markup)
with { :ok, result, _ } <- Template.render(template, assigns) do
assert result == expected
else
{ :error, message, _ } ->
assert message == expected
end
end

end

0 comments on commit d4b6471

Please sign in to comment.