Skip to content

Commit

Permalink
Fix compose block inherit (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
mworrell authored Jun 30, 2024
1 parent 8cab2ea commit 97429f4
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 10 deletions.
4 changes: 3 additions & 1 deletion src/template_compiler_element.erl
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ maybe_add_include(_Token, _Method, _IsCatinclude, Ws) ->
Ws.


compose({_, SrcPos, _}, Template, ArgsList, IsContextVars, Blocks, #cs{runtime=Runtime} = CState, Ws) ->
compose({_, SrcPos, _}, Template, ArgsList, IsContextVars, Blocks, #cs{runtime=Runtime, module=Module} = CState, Ws) ->
{Ws1, TemplateAst} = template_compiler_expr:compile(Template, CState, Ws),
ArgsListAst = erl_syntax:list([ erl_syntax:tuple([A,B]) || {A,B} <- ArgsList ]),
{_BlocksWs, BlocksAsts} = template_compiler:compile_blocks(Blocks, CState),
Expand All @@ -754,6 +754,7 @@ compose({_, SrcPos, _}, Template, ArgsList, IsContextVars, Blocks, #cs{runtime=R
"_@is_context_vars,"
"_@vars,"
"_@block_list,",
"_@module,",
"_@block_fun,",
"_@context)"
],
Expand All @@ -766,6 +767,7 @@ compose({_, SrcPos, _}, Template, ArgsList, IsContextVars, Blocks, #cs{runtime=R
{context, erl_syntax:variable(CState#cs.context_var)},
{context_vars, erl_syntax:abstract(CState#cs.context_vars)},
{block_list, BlockListAst},
{module, erl_syntax:atom(Module)},
{block_fun, BlockFunAst},
{is_context_vars, erl_syntax:abstract(IsContextVars)}
]),
Expand Down
33 changes: 24 additions & 9 deletions src/template_compiler_runtime_internal.erl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
block_call/6,
block_inherit/7,
include/9,
compose/10,
compose/11,
call/4,
print/1,
unique/0
Expand Down Expand Up @@ -153,8 +153,17 @@ block_call(SrcPos, Block, Vars, BlockMap, Runtime, Context) ->
After
]
end;
{ok, [RenderFun|_]} when is_function(RenderFun) ->
RenderFun(Block, Vars, BlockMap, Context);
{ok, [{Module, RenderFun}|_]} when is_function(RenderFun) ->
case Runtime:trace_block(SrcPos, Block, Module, Context) of
ok ->
RenderFun(Block, Vars, BlockMap, Context);
{ok, Before, After} ->
[
Before,
RenderFun(Block, Vars, BlockMap, Context),
After
]
end;
error ->
% No such block, return empty data.
<<>>
Expand All @@ -165,8 +174,13 @@ block_call(SrcPos, Block, Vars, BlockMap, Runtime, Context) ->
block_inherit(SrcPos, Module, Block, Vars, BlockMap, Runtime, Context) ->
case maps:find(Block, BlockMap) of
{ok, Modules} ->
case lists:dropwhile(fun(M) -> M =/= Module end, Modules) of
[Module, Next|_] ->
case lists:dropwhile(
fun
({M, _F}) -> M =/= Module;
(M) -> M =/= Module
end, Modules)
of
[ _Module, Next | _ ] when is_atom(Next) ->
case Runtime:trace_block(SrcPos, Block, Next, Context) of
ok ->
Next:render_block(Block, Vars, BlockMap, Context);
Expand All @@ -177,7 +191,7 @@ block_inherit(SrcPos, Module, Block, Vars, BlockMap, Runtime, Context) ->
After
]
end;
_ ->
[] ->
<<>>
end;
error ->
Expand Down Expand Up @@ -258,7 +272,7 @@ include_1(SrcPos, Method, Template, Runtime, ContextVars, Vars, Context) ->
end.

%% @doc Compose include of a template, with overruling blocks.
-spec compose(SrcPos, Template, Args, Runtime, ContextVars, IsContextVars, Vars, BlockList, BlockFun, Context) -> Output when
-spec compose(SrcPos, Template, Args, Runtime, ContextVars, IsContextVars, Vars, BlockList, BlockModule, BlockFun, Context) -> Output when
SrcPos :: {File::binary(), Line::integer(), Col::integer()},
Template :: template_compiler:template(),
Args :: list({atom(),term()}),
Expand All @@ -267,10 +281,11 @@ include_1(SrcPos, Method, Template, Runtime, ContextVars, Vars, Context) ->
IsContextVars :: boolean(),
Vars :: map(),
BlockList :: list( atom() ),
BlockModule :: atom(),
BlockFun :: function(), % (_@BlockName@, Vars, Blocks, Context) -> _@BlockAst
Context :: term(),
Output :: template_compiler:render_result().
compose(SrcPos, Template, Args, Runtime, ContextVars, IsContextVars, Vars, BlockList, BlockFun, Context) ->
compose(SrcPos, Template, Args, Runtime, ContextVars, IsContextVars, Vars, BlockList, BlockModule, BlockFun, Context) ->
Vars1 = lists:foldl(
fun
({'$cat', [Cat|_] = E}, Acc) when is_atom(Cat); is_binary(Cat); is_list(Cat) ->
Expand All @@ -289,7 +304,7 @@ compose(SrcPos, Template, Args, Runtime, ContextVars, IsContextVars, Vars, Block
true -> Runtime:set_context_vars(Args, Context);
false -> Context
end,
BlockMap = lists:foldl(fun(Block, Acc) -> Acc#{ Block => [ BlockFun ] } end, #{}, BlockList),
BlockMap = lists:foldl(fun(Block, Acc) -> Acc#{ Block => [ {BlockModule, BlockFun} ] } end, #{}, BlockList),
{SrcFile, SrcLine, _SrcCol} = SrcPos,
Options = [
{runtime, Runtime},
Expand Down
6 changes: 6 additions & 0 deletions test/template_compiler_include_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ groups() ->
,include_dynamic_test
,include_args_test
,compose_test
,compose_inherit_test
]}].

init_per_suite(Config) ->
Expand Down Expand Up @@ -78,6 +79,11 @@ compose_test(_Config) ->
<<"AxB1yC">> = iolist_to_binary(Bin1),
ok.

compose_inherit_test(_Config) ->
{ok, Bin1} = template_compiler:render("compose2.tpl", #{}, [], undefined),
<<"AxBXYC1yD">> = iolist_to_binary(Bin1),
ok.

test_data_dir(Config) ->
filename:join([
filename:dirname(filename:dirname(?config(data_dir, Config))),
Expand Down
1 change: 1 addition & 0 deletions test/test-data/compose2.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A{% compose "compose_b.tpl" v=1 %}{% block a %}B{% inherit %}C{{ v }}{% endblock %}{% endcompose %}D

0 comments on commit 97429f4

Please sign in to comment.