Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Partials support #7

Open
wants to merge 5 commits into from

3 participants

@vladimir-vg

Actually this pull-request changes code alot, so very possible that you will decline it.

However, it may be useful for someone.

@vladimir-vg

btw, this pull-requests changes compiled template type signature, now it requires two args.

@devinus
Owner

Let me review this.

@dch
dch commented

how did that review go?

@devinus
Owner

@dch @vladimir-vg now has a library that surpasses the functionality of Walrus here: https://github.com/vladimir-vg/elk.erl

@dch
dch commented
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 6, 2012
  1. @vladimir-vg
  2. @vladimir-vg
  3. @vladimir-vg

    Now template function accepts two arguments: context and partials

    vladimir-vg authored
    This change breaks compatability, renderer that returned from compile/1
    requires two arguments instead of one.
  4. @vladimir-vg
  5. @vladimir-vg
This page is out of date. Refresh to see the latest.
View
75 src/walrus.erl
@@ -1,7 +1,7 @@
-module(walrus).
-author("Devin Torres <devin@devintorres.com>").
--export([compile/1, render/2]).
+-export([compile/1, render/2, render/3]).
-define(is_falsy(V),
(V =:= false orelse V =:= [] orelse V =:= undefined orelse V =:= null)).
@@ -11,59 +11,78 @@
-type stringifiable() :: value() | fun((Context :: context())
-> value()).
--spec compile(Template :: list() | binary()) -> fun((Context :: context())
- -> binary()).
+-spec compile(Template :: list() | binary()) ->
+ fun((Context :: context(), PartialsContext :: context()) -> binary()).
compile(Template) when is_binary(Template) ->
compile(binary_to_list(Template));
compile(Template) when is_list(Template) ->
{ok, Tokens, _} = walrus_lexer:string(Template),
{ok, ParseTree} = walrus_parser:parse(Tokens),
- fun (Context) ->
- render(ParseTree, Context, [])
+ fun (Context, PartialsContext) ->
+ IOList = render_iolist(ParseTree, Context, PartialsContext, []),
+ iolist_to_binary(IOList)
end.
-spec render(Template :: list() | binary(), Context :: context())
-> binary().
-render(Template, Context) when is_binary(Template) ->
- render(binary_to_list(Template), Context);
-render(Template, Context) when is_list(Template) ->
+render(Template, Context) ->
+ render(Template, Context, []).
+
+-spec render(Template :: list() | binary(), Context :: context(), PartialsContext :: context())
+ -> binary().
+render(Template, Context, PartialsContext) when is_binary(Template) ->
+ render(binary_to_list(Template), Context, PartialsContext);
+render(Template, Context, PartialsContext) when is_list(Template) ->
{ok, Tokens, _} = walrus_lexer:string(Template),
{ok, ParseTree} = walrus_parser:parse(Tokens),
- render(ParseTree, Context, []).
+ IOList = render_iolist(ParseTree, Context, PartialsContext, []),
+ iolist_to_binary(IOList).
--spec render(ParseTree :: list(), Context :: context(), Acc :: list())
+-spec render_iolist(ParseTree :: list(), Context :: context(), PartialsContext :: context(), Acc :: list())
-> binary().
-render([{text, Text} | ParseTree], Context, Acc) ->
- render(ParseTree, Context, [Text | Acc]);
-render([{var, Key} | ParseTree], Context, Acc) ->
+render_iolist([{text, Text} | ParseTree], Context, PartialsContext, Acc) ->
+ render_iolist(ParseTree, Context, PartialsContext, [Text | Acc]);
+render_iolist([{var, Key} | ParseTree], Context, PartialsContext, Acc) ->
Value = get(Key, Context),
- render(ParseTree, Context, [stringify(Value, Context, true) | Acc]);
-render([{var_unescaped, Key} | ParseTree], Context, Acc) ->
+ render_iolist(ParseTree, Context, PartialsContext, [stringify(Value, Context, true) | Acc]);
+render_iolist([{var_unescaped, Key} | ParseTree], Context, PartialsContext, Acc) ->
Value = get(Key, Context),
- render(ParseTree, Context, [stringify(Value, Context, false) | Acc]);
-render([{block, Key, SubParseTree} | ParseTree], Context, Acc) ->
+ render_iolist(ParseTree, Context, PartialsContext, [stringify(Value, Context, false) | Acc]);
+render_iolist([{block, Key, SubParseTree} | ParseTree], Context, PartialsContext, Acc) ->
Value = get(Key, Context),
case Value of
Val when ?is_falsy(Val) ->
- render(ParseTree, Context, Acc);
+ render_iolist(ParseTree, Context, PartialsContext, Acc);
Val when is_list(Val) ->
- Tmpl = [render(SubParseTree, Ctx, []) || Ctx <- Val],
- render(ParseTree, Context, [Tmpl | Acc]);
+ Tmpl = [render_iolist(SubParseTree, Ctx, PartialsContext, []) || Ctx <- Val],
+ render_iolist(ParseTree, Context, PartialsContext, [Tmpl | Acc]);
_ ->
- Tmpl = render(SubParseTree, Context, []),
- render(ParseTree, Context, [Tmpl | Acc])
+ Tmpl = render_iolist(SubParseTree, Context, PartialsContext, []),
+ render_iolist(ParseTree, Context, PartialsContext, [Tmpl | Acc])
end;
-render([{inverse, Key, SubParseTree} | ParseTree], Context, Acc) ->
+render_iolist([{inverse, Key, SubParseTree} | ParseTree], Context, PartialsContext, Acc) ->
Value = get(Key, Context),
case Value of
Val when ?is_falsy(Val) ->
- Tmpl = render(SubParseTree, Context, []),
- render(ParseTree, Context, [Tmpl | Acc]);
+ Tmpl = render_iolist(SubParseTree, Context, PartialsContext, []),
+ render_iolist(ParseTree, Context, PartialsContext, [Tmpl | Acc]);
_ ->
- render(ParseTree, Context, Acc)
+ render_iolist(ParseTree, Context, PartialsContext, Acc)
end;
-render([], _Context, Acc) ->
- iolist_to_binary(lists:reverse(Acc)).
+render_iolist([{partial, Key} | ParseTree], Context, PartialsContext, Acc) ->
+ Value = get(Key, PartialsContext),
+ case Value of
+ Template when is_list(Template); is_binary(Template) ->
+ {ok, Tokens, _} = walrus_lexer:string(Template),
+ {ok, PartialParseTree} = walrus_parser:parse(Tokens),
+ IOList = render_iolist(PartialParseTree, Context, PartialsContext, []),
+ render_iolist(ParseTree, Context, PartialsContext, [ IOList | Acc]);
+ Fun when is_function(Fun, 2) ->
+ Output = Fun(Context, PartialsContext),
+ render_iolist(ParseTree, Context, PartialsContext, [ Output | Acc])
+ end;
+render_iolist([], _Context, _PartialsContext, Acc) ->
+ lists:reverse(Acc).
-spec get(Key :: atom(), Context :: context()) -> stringifiable().
get(Key, Context) ->
View
1  src/walrus_lexer.xrl
@@ -11,6 +11,7 @@ Rules.
{{/ : {token,{'{{/',TokenLine}}.
{{\^ : {token,{'{{^',TokenLine}}.
{{{ : {token,{'{{{',TokenLine}}.
+{{> : {token,{'{{>',TokenLine}}.
\s*{Key}\s*}} : {token,{key,TokenLine,?key(TokenChars,TokenLen)},"}}"}.
}} : {token,{'}}',TokenLine}}.
}}} : {token,{'}}}',TokenLine}}.
View
7 src/walrus_parser.yrl
@@ -1,6 +1,6 @@
-Nonterminals template token var block inverse.
+Nonterminals template token var partial block inverse.
-Terminals text key '{{' '{{{' '{{#' '{{/' '{{^' '}}' '}}}'.
+Terminals text key '{{' '{{{' '{{#' '{{>' '{{/' '{{^' '}}' '}}}'.
Rootsymbol template.
@@ -11,10 +11,13 @@ token -> text : {text, ?value('$1')}.
token -> var : '$1'.
token -> block : '$1'.
token -> inverse : '$1'.
+token -> partial : '$1'.
var -> '{{' key '}}' : {var, ?value('$2')}.
var -> '{{{' key '}}}' : {var_unescaped, ?value('$2')}.
+partial -> '{{>' key '}}' : {partial, ?value('$2')}.
+
block -> '{{#' key '}}' template '{{/' key '}}'
: section(block, '$2', '$6', '$4').
View
2  test/compile_test.erl
@@ -22,4 +22,4 @@ basic_test() ->
" - Beer, 5\n\n"
" - Juice, 8\n">>,
- Expected = Renderer(Context).
+ Expected = Renderer(Context, []).
View
42 test/partials_test.erl
@@ -0,0 +1,42 @@
+-module(partials_test).
+
+-compile([export_all]).
+
+basic_test() ->
+ HelloTemplate = "Hello {{{name}}}.\n"
+ "Drinks:",
+ Template = "{{> hello }}\n"
+ "{{#drinks}}\n"
+ " - {{name}}, {{tastiness}}\n"
+ "{{/drinks}}",
+ Context = [{name, "Devin & Jane"},
+ {drinks, [[{name, "Beer"},
+ {tastiness, 5}],
+ [{name, "Juice"},
+ {tastiness, 8}]]}],
+ Expected = <<"Hello Devin & Jane.\n"
+ "Drinks:\n\n"
+ " - Beer, 5\n\n"
+ " - Juice, 8\n">>,
+ Expected = walrus:render(Template, Context, [{hello, HelloTemplate}]).
+
+nested_test() ->
+ MainTemplate = "My name is {{name}}\n"
+ "I plan to travel into following places:\n"
+
+ "{{#places}}\n {{> place_item }}\n{{/places}}\n",
+
+ PlaceItemTemplate = "{{name}} ({{country}}): {{> place_description }}",
+ PlaceDescTemplate = "{{description}}",
+ Context = [{name, "Vladimir"},
+ {places, [
+ [{name, "San Jose"}, {country, "USA"}, {description, "Very interesting place"}],
+ [{name, "Kiev"}, {country, "Ukraine"}, {description, "Great place"}]
+ ]}],
+ PartialsContext = [{place_item, PlaceItemTemplate}, {place_description, PlaceDescTemplate}],
+ Expected = <<"My name is Vladimir\n"
+ "I plan to travel into following places:\n\n"
+ " San Jose (USA): Very interesting place\n\n"
+ " Kiev (Ukraine): Great place\n\n">>,
+ Expected = walrus:render(MainTemplate, Context, PartialsContext).
+
Something went wrong with that request. Please try again.