Browse Source

Compile custom tags at most once per template

Evan Miller 14 years ago
parent
commit
6c59be1320

+ 1 - 1
README.markdown

@@ -38,7 +38,7 @@ Options is a proplist possibly containing:
 defaults to the compiled template's directory.
 defaults to the compiled template's directory.
 
 
 * `custom_tags_dir` - Directory of DTL files (no extension) includable as tags.
 * `custom_tags_dir` - Directory of DTL files (no extension) includable as tags.
-E.g. if $custom_tags_dir/foo contains `<b>{{ bar }}</b>`, then `{{ foo bar=100 }}` 
+E.g. if $custom_tags_dir/foo contains `<b>{{ bar }}</b>`, then `{% foo bar=100 %}` 
 will evaluate to `<b>100</b>`. Get it?
 will evaluate to `<b>100</b>`. Get it?
 
 
 * `vars` - Variables (and their values) to evaluate at compile-time rather than
 * `vars` - Variables (and their values) to evaluate at compile-time rather than

+ 1 - 2
examples/docroot/custom_tag

@@ -1,4 +1,3 @@
-{% load flashvideo %}
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
 <html>
 <html>
   <head>
   <head>
@@ -10,4 +9,4 @@
 	{% flashvideo dom_id="myvideo" width="800" height="600" static="/static" path_to_video="/myvid.mp4" path_to_preview_image="/mypic.jpg" %}
 	{% flashvideo dom_id="myvideo" width="800" height="600" static="/static" path_to_video="/myvid.mp4" path_to_preview_image="/mypic.jpg" %}
 	after
 	after
   </body>
   </body>
-</html>
+</html>

+ 0 - 12
examples/docroot/custom_tag_error

@@ -1,12 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-  <head>
-    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-    <title>Test variable</title>								 
-  </head>
-  <body>
-	before
-	{% flashvideo dom_id="myvideo" width="800" height="600" static="/static" path_to_video="/myvid.mp4" path_to_preview_image="/mypic.jpg" %}
-	after
-  </body>
-</html>

+ 77 - 75
src/erlydtl/erlydtl_compiler.erl

@@ -57,12 +57,14 @@
 -record(ast_info, {
 -record(ast_info, {
     dependencies = [],
     dependencies = [],
     translatable_strings = [],
     translatable_strings = [],
+    custom_tags = [],
     var_names = [],
     var_names = [],
     pre_render_asts = []}).
     pre_render_asts = []}).
     
     
 -record(treewalker, {
 -record(treewalker, {
-    counter = 0,
-    custom_tags = []}).    
+%    custom_tags = [],
+    counter = 0
+}).    
 
 
 compile(Binary, Module) when is_binary(Binary) ->
 compile(Binary, Module) when is_binary(Binary) ->
     compile(Binary, Module, []);
     compile(Binary, Module, []);
@@ -120,19 +122,24 @@ compile(File, Module, Options) ->
 
 
 compile_to_binary(File, DjangoParseTree, Context, CheckSum) ->
 compile_to_binary(File, DjangoParseTree, Context, CheckSum) ->
     try body_ast(DjangoParseTree, Context, #treewalker{}) of
     try body_ast(DjangoParseTree, Context, #treewalker{}) of
-        {{Ast, Info}, _} ->
-            case compile:forms(forms(File, Context#dtl_context.module, Ast, Info, CheckSum), 
-                    Context#dtl_context.compiler_options) of
-                {ok, Module1, Bin} -> 
-                    code:purge(Module1),
-                    case code:load_binary(Module1, atom_to_list(Module1) ++ ".erl", Bin) of
-                        {module, _} -> {ok, Module1, Bin};
-                        _ -> {error, lists:concat(["code reload failed: ", Module1])}
-                    end;
-                error ->
-                    {error, lists:concat(["compilation failed: ", File])};
-                OtherError ->
-                    OtherError
+        {{BodyAst, BodyInfo}, BodyTreeWalker} ->
+            try custom_tags_ast(BodyInfo#ast_info.custom_tags, Context, BodyTreeWalker) of
+                {{CustomTagsAst, CustomTagsInfo}, _} ->
+                    case compile:forms(forms(File, Context#dtl_context.module, {BodyAst, BodyInfo}, {CustomTagsAst, CustomTagsInfo}, CheckSum), 
+                            Context#dtl_context.compiler_options) of
+                        {ok, Module1, Bin} -> 
+                            code:purge(Module1),
+                            case code:load_binary(Module1, atom_to_list(Module1) ++ ".erl", Bin) of
+                                {module, _} -> {ok, Module1, Bin};
+                                _ -> {error, lists:concat(["code reload failed: ", Module1])}
+                            end;
+                        error ->
+                            {error, lists:concat(["compilation failed: ", File])};
+                        OtherError ->
+                            OtherError
+                    end
+            catch 
+                throw:Error -> Error
             end
             end
     catch 
     catch 
         throw:Error -> Error
         throw:Error -> Error
@@ -146,7 +153,7 @@ init_dtl_context(File, Module, Options) ->
         parse_trail = [File], 
         parse_trail = [File], 
         module = Module,
         module = Module,
         doc_root = proplists:get_value(doc_root, Options, filename:dirname(File)),
         doc_root = proplists:get_value(doc_root, Options, filename:dirname(File)),
-        custom_tags_dir = proplists:get_value(custom_tags_dir, Options, Ctx#dtl_context.custom_tags_dir),
+        custom_tags_dir = proplists:get_value(custom_tags_dir, Options, filename:join([erlydtl_deps:get_base_dir(), "priv", "custom_tags"])),
         vars = proplists:get_value(vars, Options, Ctx#dtl_context.vars), 
         vars = proplists:get_value(vars, Options, Ctx#dtl_context.vars), 
         reader = proplists:get_value(reader, Options, Ctx#dtl_context.reader),
         reader = proplists:get_value(reader, Options, Ctx#dtl_context.reader),
         compiler_options = proplists:get_value(compiler_options, Options, Ctx#dtl_context.compiler_options),
         compiler_options = proplists:get_value(compiler_options, Options, Ctx#dtl_context.compiler_options),
@@ -203,7 +210,7 @@ parse(File, Context) ->
                     Result
                     Result
             end;
             end;
         _ ->
         _ ->
-            {error, {File, ["Failed to read file"]}}
+            {error, {File, [{0, Context#dtl_context.module, "Failed to read file"}]}}
     end.
     end.
         
         
 parse(CheckSum, Data, Context) ->
 parse(CheckSum, Data, Context) ->
@@ -226,8 +233,38 @@ parse(Data) ->
         Err ->
         Err ->
             Err
             Err
     end.        
     end.        
+
+custom_tags_ast(CustomTags, Context, TreeWalker) ->
+    {{CustomTagsClauses, CustomTagsInfo}, TreeWalker1} = custom_tags_clauses_ast(CustomTags, Context, TreeWalker),
+    {{erl_syntax:function(erl_syntax:atom(render_tag), CustomTagsClauses), CustomTagsInfo}, TreeWalker1}.
+
+custom_tags_clauses_ast(CustomTags, Context, TreeWalker) ->
+    custom_tags_clauses_ast1(CustomTags, [], [], #ast_info{}, Context, TreeWalker).
+
+custom_tags_clauses_ast1([], _ExcludeTags, ClauseAcc, InfoAcc, _Context, TreeWalker) ->
+    {{lists:reverse([erl_syntax:clause([erl_syntax:underscore(), erl_syntax:underscore(), erl_syntax:underscore()], none,
+                        [erl_syntax:list([])])|ClauseAcc]), InfoAcc}, TreeWalker};
+custom_tags_clauses_ast1([Tag|CustomTags], ExcludeTags, ClauseAcc, InfoAcc, Context, TreeWalker) ->
+    case lists:member(Tag, ExcludeTags) of
+        true ->
+            custom_tags_clauses_ast1(CustomTags, ExcludeTags, ClauseAcc, InfoAcc, Context, TreeWalker);
+        false ->
+            CustomTagFile = filename:join([Context#dtl_context.custom_tags_dir, Tag]),
+            case parse(CustomTagFile, Context) of
+                {ok, DjangoParseTree, CheckSum} ->
+                    {{BodyAst, BodyAstInfo}, TreeWalker1} = with_dependency({CustomTagFile, CheckSum}, 
+                        body_ast(DjangoParseTree, Context, TreeWalker)),
+                    Clause = erl_syntax:clause([erl_syntax:string(Tag), erl_syntax:variable("Variables"), erl_syntax:variable("TranslationFun")],
+                                none, [BodyAst]),
+                    custom_tags_clauses_ast1(CustomTags, [Tag|ExcludeTags], [Clause|ClauseAcc], merge_info(BodyAstInfo, InfoAcc), 
+                        Context, TreeWalker1);
+                Error ->
+                    throw(Error)
+            end
+    end.
   
   
-forms(File, Module, BodyAst, BodyInfo, CheckSum) ->
+forms(File, Module, {BodyAst, BodyInfo}, {CustomTagsFunctionAst, CustomTagsInfo}, CheckSum) ->
+    MergedInfo = merge_info(BodyInfo, CustomTagsInfo),
     Render0FunctionAst = erl_syntax:function(erl_syntax:atom(render),
     Render0FunctionAst = erl_syntax:function(erl_syntax:atom(render),
         [erl_syntax:clause([], none, [erl_syntax:application(none, 
         [erl_syntax:clause([], none, [erl_syntax:application(none, 
                         erl_syntax:atom(render), [erl_syntax:list([])])])]),
                         erl_syntax:atom(render), [erl_syntax:list([])])])]),
@@ -258,12 +295,12 @@ forms(File, Module, BodyAst, BodyInfo, CheckSum) ->
             [erl_syntax:list(lists:map(fun 
             [erl_syntax:list(lists:map(fun 
                     ({XFile, XCheckSum}) -> 
                     ({XFile, XCheckSum}) -> 
                         erl_syntax:tuple([erl_syntax:string(XFile), erl_syntax:string(XCheckSum)])
                         erl_syntax:tuple([erl_syntax:string(XFile), erl_syntax:string(XCheckSum)])
-                end, BodyInfo#ast_info.dependencies))])]),     
+                end, MergedInfo#ast_info.dependencies))])]),     
 
 
     TranslatableStringsAst = erl_syntax:function(
     TranslatableStringsAst = erl_syntax:function(
         erl_syntax:atom(translatable_strings), [erl_syntax:clause([], none,
         erl_syntax:atom(translatable_strings), [erl_syntax:clause([], none,
                 [erl_syntax:list(lists:map(fun(String) -> erl_syntax:string(String) end,
                 [erl_syntax:list(lists:map(fun(String) -> erl_syntax:string(String) end,
-                            BodyInfo#ast_info.translatable_strings))])]),
+                            MergedInfo#ast_info.translatable_strings))])]),
 
 
     BodyAstTmp = erl_syntax:application(
     BodyAstTmp = erl_syntax:application(
                     erl_syntax:atom(erlydtl_runtime),
                     erl_syntax:atom(erlydtl_runtime),
@@ -286,7 +323,7 @@ forms(File, Module, BodyAst, BodyInfo, CheckSum) ->
                     erl_syntax:arity_qualifier(erl_syntax:atom(translatable_strings), erl_syntax:integer(0))])]),
                     erl_syntax:arity_qualifier(erl_syntax:atom(translatable_strings), erl_syntax:integer(0))])]),
     
     
     [erl_syntax:revert(X) || X <- [ModuleAst, ExportAst, Render0FunctionAst, Render1FunctionAst, Render2FunctionAst,
     [erl_syntax:revert(X) || X <- [ModuleAst, ExportAst, Render0FunctionAst, Render1FunctionAst, Render2FunctionAst,
-            SourceFunctionAst, DependenciesFunctionAst, TranslatableStringsAst, RenderInternalFunctionAst
+            SourceFunctionAst, DependenciesFunctionAst, TranslatableStringsAst, RenderInternalFunctionAst, CustomTagsFunctionAst
             | BodyInfo#ast_info.pre_render_asts]].    
             | BodyInfo#ast_info.pre_render_asts]].    
 
 
         
         
@@ -370,8 +407,6 @@ body_ast(DjangoParseTree, Context, TreeWalker) ->
             ({'for', {'in', IteratorList, Variable}, Contents, EmptyPartContents}, TreeWalkerAcc) ->
             ({'for', {'in', IteratorList, Variable}, Contents, EmptyPartContents}, TreeWalkerAcc) ->
                 {EmptyAstInfo, TreeWalker1} = body_ast(EmptyPartContents, Context, TreeWalkerAcc),
                 {EmptyAstInfo, TreeWalker1} = body_ast(EmptyPartContents, Context, TreeWalkerAcc),
                 for_loop_ast(IteratorList, Variable, Contents, EmptyAstInfo, Context, TreeWalker1);
                 for_loop_ast(IteratorList, Variable, Contents, EmptyAstInfo, Context, TreeWalker1);
-            ({'load', Names}, TreeWalkerAcc) ->
-                load_ast(Names, Context, TreeWalkerAcc);
             ({'tag', {'identifier', _, Name}, Args}, TreeWalkerAcc) ->
             ({'tag', {'identifier', _, Name}, Args}, TreeWalkerAcc) ->
                 tag_ast(Name, Args, Context, TreeWalkerAcc);            
                 tag_ast(Name, Args, Context, TreeWalkerAcc);            
             ({'call', {'identifier', _, Name}}, TreeWalkerAcc) ->
             ({'call', {'identifier', _, Name}}, TreeWalkerAcc) ->
@@ -451,10 +486,11 @@ value_ast(ValueToken, AsString, Context, TreeWalker) ->
     end.
     end.
 
 
 merge_info(Info1, Info2) ->
 merge_info(Info1, Info2) ->
-    #ast_info{dependencies = 
-        lists:merge(
-            lists:sort(Info1#ast_info.dependencies), 
-            lists:sort(Info2#ast_info.dependencies)),
+    #ast_info{
+        dependencies = 
+            lists:merge(
+                lists:sort(Info1#ast_info.dependencies), 
+                lists:sort(Info2#ast_info.dependencies)),
         var_names = 
         var_names = 
             lists:merge(
             lists:merge(
                 lists:sort(Info1#ast_info.var_names), 
                 lists:sort(Info1#ast_info.var_names), 
@@ -463,6 +499,10 @@ merge_info(Info1, Info2) ->
             lists:merge(
             lists:merge(
                 lists:sort(Info1#ast_info.translatable_strings),
                 lists:sort(Info1#ast_info.translatable_strings),
                 lists:sort(Info2#ast_info.translatable_strings)),
                 lists:sort(Info2#ast_info.translatable_strings)),
+        custom_tags = 
+            lists:merge(
+                lists:sort(Info1#ast_info.custom_tags),
+                lists:sort(Info2#ast_info.custom_tags)),
         pre_render_asts = 
         pre_render_asts = 
             lists:merge(
             lists:merge(
                 Info1#ast_info.pre_render_asts,
                 Info1#ast_info.pre_render_asts,
@@ -688,10 +728,6 @@ for_loop_ast(IteratorList, LoopValue, Contents, {EmptyContentsAst, EmptyContents
                     merge_info(merge_info(Info, EmptyContentsInfo), LoopValueInfo)
                     merge_info(merge_info(Info, EmptyContentsInfo), LoopValueInfo)
             }, TreeWalker2}.
             }, TreeWalker2}.
 
 
-load_ast(Names, _Context, TreeWalker) ->
-    CustomTags = lists:merge([X || {identifier, _ , X} <- Names], TreeWalker#treewalker.custom_tags),
-    {{erl_syntax:list([]), #ast_info{}}, TreeWalker#treewalker{custom_tags = CustomTags}}.  
-
 cycle_ast(Names, Context, TreeWalker) ->
 cycle_ast(Names, Context, TreeWalker) ->
     NamesTuple = lists:map(fun({string_literal, _, Str}) ->
     NamesTuple = lists:map(fun({string_literal, _, Str}) ->
                                    erl_syntax:string(unescape_string_literal(Str));
                                    erl_syntax:string(unescape_string_literal(Str));
@@ -753,50 +789,16 @@ full_path(File, DocRoot) ->
 %%-------------------------------------------------------------------
 %%-------------------------------------------------------------------
 
 
 tag_ast(Name, Args, Context, TreeWalker) ->
 tag_ast(Name, Args, Context, TreeWalker) ->
-    case lists:member(Name, TreeWalker#treewalker.custom_tags) of
-        true ->
-            InterpretedArgs = lists:map(fun
-                    ({{identifier, _, Key}, {string_literal, _, Value}}) ->
-                        {Key, erl_syntax:string(unescape_string_literal(Value))};
-                    ({{identifier, _, Key}, Value}) ->
-                        {Key, format(resolve_variable_ast(Value, Context), Context)}
-                end, Args),
-            DefaultFilePath = filename:join([erlydtl_deps:get_base_dir(), "priv", "custom_tags", Name]),
-            case Context#dtl_context.custom_tags_dir of
-                [] ->
-                    case parse(DefaultFilePath, Context) of
-                        {ok, TagParseTree, CheckSum} ->
-                            tag_ast2({DefaultFilePath, CheckSum}, TagParseTree, InterpretedArgs, Context, TreeWalker);
-                        _ ->
-                            Reason = lists:concat(["Loading tag source for '", Name, "' failed: ", 
-                                DefaultFilePath]),
-                            throw({error, Reason})
-                    end;
-                _ ->
-                    CustomFilePath = filename:join([Context#dtl_context.custom_tags_dir, Name]),
-                    case parse(CustomFilePath, Context) of
-                        {ok, TagParseTree, CheckSum} ->
-                            tag_ast2({CustomFilePath, CheckSum},TagParseTree, InterpretedArgs, Context, TreeWalker);
-                        _ ->
-                            case parse(DefaultFilePath, Context) of
-                                {ok, TagParseTree, CheckSum} ->
-                                    tag_ast2({DefaultFilePath, CheckSum}, TagParseTree, InterpretedArgs, Context, TreeWalker);
-                                _ ->
-                                    Reason = lists:concat(["Loading tag source for '", Name, "' failed: ", 
-                                        CustomFilePath, ", ", DefaultFilePath]),
-                                    throw({error, Reason})
-                            end
-                    end
-            end;
-        _ ->
-            throw({error, lists:concat(["Custom tag '", Name, "' not loaded"])})
-    end.
- 
-tag_ast2({Source, _} = Dep, TagParseTree, InterpretedArgs, Context, TreeWalker) ->
-    with_dependency(Dep, body_ast(TagParseTree, Context#dtl_context{
-        local_scopes = [ InterpretedArgs | Context#dtl_context.local_scopes ],
-        parse_trail = [ Source | Context#dtl_context.parse_trail ]}, TreeWalker)).
-
+    {InterpretedArgs, AstInfo} = lists:mapfoldl(fun
+                ({{identifier, _, Key}, {string_literal, _, Value}}, AstInfoAcc) ->
+                    {erl_syntax:tuple([erl_syntax:string(Key), erl_syntax:string(unescape_string_literal(Value))]), AstInfoAcc};
+                ({{identifier, _, Key}, Value}, AstInfoAcc) ->
+                    {AST, AstInfo1} = resolve_variable_ast(Value, Context),
+                    {erl_syntax:tuple([erl_syntax:string(Key), format(AST,Context)]), merge_info(AstInfo1, AstInfoAcc)}
+            end, #ast_info{}, Args),
+    RenderAst = erl_syntax:application(none, erl_syntax:atom(render_tag),
+        [erl_syntax:string(Name), erl_syntax:list(InterpretedArgs), erl_syntax:variable("TranslationFun")]),
+    {{RenderAst, AstInfo#ast_info{custom_tags = [Name]}}, TreeWalker}.
 
 
 call_ast(Module, TreeWalkerAcc) ->
 call_ast(Module, TreeWalkerAcc) ->
     call_ast(Module, erl_syntax:variable("Variables"), #ast_info{}, TreeWalkerAcc).
     call_ast(Module, erl_syntax:variable("Variables"), #ast_info{}, TreeWalkerAcc).

+ 0 - 9
src/erlydtl/erlydtl_parser.yrl

@@ -89,9 +89,6 @@ Nonterminals
     Variable
     Variable
     Filter
     Filter
     
     
-    LoadTag
-    LoadNames
-    
     CustomTag
     CustomTag
     Args
     Args
 
 
@@ -129,7 +126,6 @@ Terminals
     ifnotequal_keyword
     ifnotequal_keyword
     in_keyword
     in_keyword
     include_keyword
     include_keyword
-    load_keyword
     noop_keyword
     noop_keyword
     not_keyword
     not_keyword
     now_keyword
     now_keyword
@@ -163,7 +159,6 @@ Elements -> Elements ValueBraced : '$1' ++ ['$2'].
 Elements -> Elements ExtendsTag : '$1' ++ ['$2'].
 Elements -> Elements ExtendsTag : '$1' ++ ['$2'].
 Elements -> Elements IncludeTag : '$1' ++ ['$2'].
 Elements -> Elements IncludeTag : '$1' ++ ['$2'].
 Elements -> Elements NowTag : '$1' ++ ['$2'].
 Elements -> Elements NowTag : '$1' ++ ['$2'].
-Elements -> Elements LoadTag : '$1' ++ ['$2'].
 Elements -> Elements CycleTag : '$1' ++ ['$2'].
 Elements -> Elements CycleTag : '$1' ++ ['$2'].
 Elements -> Elements BlockBlock : '$1' ++ ['$2'].
 Elements -> Elements BlockBlock : '$1' ++ ['$2'].
 Elements -> Elements FirstofTag : '$1' ++ ['$2'].
 Elements -> Elements FirstofTag : '$1' ++ ['$2'].
@@ -195,10 +190,6 @@ ExtendsTag -> open_tag extends_keyword string_literal close_tag : {extends, '$3'
 IncludeTag -> open_tag include_keyword string_literal close_tag : {include, '$3'}.
 IncludeTag -> open_tag include_keyword string_literal close_tag : {include, '$3'}.
 NowTag -> open_tag now_keyword string_literal close_tag : {date, now, '$3'}.
 NowTag -> open_tag now_keyword string_literal close_tag : {date, now, '$3'}.
 
 
-LoadTag -> open_tag load_keyword LoadNames close_tag : {load, '$3'}.
-LoadNames -> identifier : ['$1'].
-LoadNames -> LoadNames identifier : '$1' ++ ['$2'].
-
 BlockBlock -> BlockBraced Elements EndBlockBraced : {block, '$1', '$2'}.
 BlockBlock -> BlockBraced Elements EndBlockBraced : {block, '$1', '$2'}.
 BlockBraced -> open_tag block_keyword identifier close_tag : '$3'.
 BlockBraced -> open_tag block_keyword identifier close_tag : '$3'.
 EndBlockBraced -> open_tag endblock_keyword close_tag.
 EndBlockBraced -> open_tag endblock_keyword close_tag.

+ 3 - 10
src/tests/erlydtl_functional_tests.erl

@@ -44,8 +44,7 @@ test_list() ->
         "for_tuple", "for_list_preset", "for_preset", "for_records",
         "for_tuple", "for_list_preset", "for_preset", "for_records",
         "for_records_preset", "include", "if", "if_preset", "ifequal",
         "for_records_preset", "include", "if", "if_preset", "ifequal",
         "ifequal_preset", "ifnotequal", "ifnotequal_preset", "now",
         "ifequal_preset", "ifnotequal", "ifnotequal_preset", "now",
-        "var", "var_preset", "cycle", "custom_tag",
-        "custom_tag_error", "custom_call", 
+        "var", "var_preset", "cycle", "custom_tag", "custom_call", 
         "include_template", "include_path",
         "include_template", "include_path",
         "extends_path", "extends_path2", "trans" ].
         "extends_path", "extends_path2", "trans" ].
 
 
@@ -73,9 +72,6 @@ setup_compile("ifnotequal_preset") ->
 setup_compile("var_preset") ->
 setup_compile("var_preset") ->
     CompileVars = [{preset_var1, "preset-var1"}, {preset_var2, "preset-var2"}],
     CompileVars = [{preset_var1, "preset-var1"}, {preset_var2, "preset-var2"}],
     {ok, CompileVars};
     {ok, CompileVars};
-setup_compile("custom_tag_error") ->
-    CompileVars  = [],
-    {error, CompileVars};
 setup_compile(_) ->
 setup_compile(_) ->
     {ok, []}.
     {ok, []}.
 
 
@@ -163,9 +159,6 @@ setup("trans") ->
 %%--------------------------------------------------------------------       
 %%--------------------------------------------------------------------       
 %% Custom tags
 %% Custom tags
 %%--------------------------------------------------------------------
 %%--------------------------------------------------------------------
-setup("custom_tag_error") ->
-    RenderVars = [],
-    {skip, RenderVars};        
 setup("custom_call") ->
 setup("custom_call") ->
     RenderVars = [{var1, "something"}],
     RenderVars = [{var1, "something"}],
     {ok, RenderVars};    
     {ok, RenderVars};    
@@ -265,9 +258,9 @@ test_render(Name, Module) ->
                 _ ->
                 _ ->
                     {error, "rendering should have failed :" ++ File}
                     {error, "rendering should have failed :" ++ File}
             end;
             end;
-        {'EXIT', _} ->
+        {'EXIT', Reason} ->
             io:format("~n"),
             io:format("~n"),
-            {error, "failed invoking render method:" ++ Module};
+            {error, lists:flatten(io_lib:format("failed invoking render method of ~p ~p", [Module, Reason]))};
         Err ->
         Err ->
             io:format("~n"),
             io:format("~n"),
             case RenderStatus of
             case RenderStatus of