Browse Source

Adding Options to reader(reader_options) for more flexible custom readers.

sag 10 years ago
parent
commit
427db670dc

+ 1 - 0
include/erlydtl_ext.hrl

@@ -21,6 +21,7 @@
           libraries = [],
           custom_tags_dir = [],
           reader = {file, read_file},
+          reader_options = [],
           module = undefined,
           compiler_options = [],
           binary_strings = true,

+ 1 - 0
src/erlydtl.erl

@@ -86,6 +86,7 @@
                         | {locale, string()}
                         | {out_dir, false | filename()}
                         | {reader, {Module::atom(), Function::atom}}
+                        | {reader_options, [{Name::atom(), iodata()}]}
                         | {record_info, [{Name::atom(), [Field::atom()]}]}
                         | {scanner_module, Module::atom()}
                         | {vars, [{atom(), iodata()}]}.

+ 4 - 2
src/erlydtl_beam_compiler.erl

@@ -320,13 +320,14 @@ maybe_debug_template(Forms, Context) ->
 is_up_to_date(CheckSum, Context) ->
     Module = Context#dtl_context.module,
     {M, F} = Context#dtl_context.reader,
+    ReaderOptions = Context#dtl_context.reader_options,
     case catch Module:source() of
         {_, CheckSum} ->
             case catch Module:dependencies() of
                 L when is_list(L) ->
                     RecompileList = lists:foldl(
                                       fun ({XFile, XCheckSum}, Acc) ->
-                                              case catch M:F(XFile) of
+                                              case catch erlydtl_runtime:read_file_internal(M, F, XFile, ReaderOptions) of
                                                   {ok, Data} ->
                                                       case binary_to_list(erlang:md5(Data)) of
                                                           XCheckSum ->
@@ -1028,11 +1029,12 @@ include_ast(File, ArgList, Scopes, #treewalker{ context=Context }=TreeWalker) ->
 ssi_ast(FileName, #treewalker{
                      context=#dtl_context{
                                 reader = {Mod, Fun},
+                                reader_options = ReaderOptions,
                                 doc_root = Dir
                                }
                     }=TreeWalker) ->
     {{FileAst, Info}, TreeWalker1} = value_ast(FileName, true, true, TreeWalker),
-    {{?Q("erlydtl_runtime:read_file(_@Mod@, _@Fun@, _@Dir@, _@FileAst)"), Info}, TreeWalker1}.
+    {{?Q("erlydtl_runtime:read_file(_@Mod@, _@Fun@, _@Dir@, _@FileAst, _@ReaderOptions@)"), Info}, TreeWalker1}.
 
 filter_tag_ast(FilterList, Contents, TreeWalker) ->
     {{InnerAst, Info}, TreeWalker1} = body_ast(Contents, push_auto_escape(did, TreeWalker)),

+ 3 - 1
src/erlydtl_compiler.erl

@@ -266,6 +266,7 @@ init_context(ParseTrail, DefDir, Module, Options) ->
            vars = proplists:get_value(default_vars, Options, Ctx#dtl_context.vars),
            const = proplists:get_value(constants, Options, Ctx#dtl_context.const),
            reader = proplists:get_value(reader, Options, Ctx#dtl_context.reader),
+           reader_options = proplists:get_value(reader_options, Options, Ctx#dtl_context.reader_options),
            compiler_options = proplists:append_values(compiler_options, Options),
            binary_strings = proplists:get_value(binary_strings, Options, Ctx#dtl_context.binary_strings),
            force_recompile = proplists:get_bool(force_recompile, Options),
@@ -366,7 +367,8 @@ is_up_to_date(CheckSum, Context) ->
 
 parse_file(File, Context) ->
     {M, F} = Context#dtl_context.reader,
-    case catch M:F(File) of
+    ReaderOptions = Context#dtl_context.reader_options,
+    case catch erlydtl_runtime:read_file_internal(M, F, File, ReaderOptions) of
         {ok, Data} ->
             parse_template(Data, Context);
         {error, Reason} ->

+ 11 - 2
src/erlydtl_runtime.erl

@@ -450,13 +450,22 @@ spaceless(Contents) ->
     Contents4 = re:replace(Contents3, ">\\s+<", "><", [global, {return,list}]),
     Contents4.
 
-read_file(Module, Function, DocRoot, FileName) ->
+read_file(Module, Function, DocRoot, FileName, ReaderOptions) ->
     AbsName = case filename:absname(FileName) of
                   FileName -> FileName;
                   _ -> filename:join([DocRoot, FileName])
               end,
-    case Module:Function(AbsName) of
+    case read_file_internal(Module, Function, AbsName, ReaderOptions) of
         {ok, Data} -> Data;
         {error, Reason} ->
             throw({read_file, AbsName, Reason})
     end.
+read_file_internal(Module, Function, FileName, ReaderOptions) ->
+    case lists:min([I || {N,I} <- Module:module_info(exports), N =:= Function] ++ [1000]) of
+        1->
+            Module:Function(FileName);
+        2->
+            Module:Function(FileName, ReaderOptions);
+        _ ->
+            {error, "Empty reader"}
+    end.

+ 24 - 2
test/erlydtl_test_defs.erl

@@ -1,6 +1,6 @@
 -module(erlydtl_test_defs).
 
--export([tests/0]).
+-export([tests/0, extra_reader/2]).
 -include("testrunner.hrl").
 -record(testrec, {foo, bar, baz}).
 -record(person, {first_name, gender}).
@@ -1740,7 +1740,7 @@ all_test_defs() ->
                 "custom_tag3", "custom_tag4", "custom_tag_var", "custom_tag_lib_var", "custom_call", "include_template", "include_path",
                 "ssi", "extends_path", "extends_path2", "trans", "extends_for", "extends2",
                 "extends3", "recursive_block", "extend_recursive_block", "missing", "block_super",
-                "wrapper", "extends4", "super_escaped", "extends_chain"]
+                "wrapper", "extends4", "super_escaped", "extends_chain", "reader_options", "ssi_reader_options"]
 
       ]},
      {"compile_dir",
@@ -1918,9 +1918,24 @@ setup_compile("custom_tag_lib_var") ->
  {ok, [[]|[{compile_opts, [{libraries, [{custom_tag_lib,erlydtl_custom_tags_lib}]}, {default_libraries, [custom_tag_lib]}]}]]};
 setup_compile("super_escaped") ->
     {ok, [[]|[{compile_opts, [auto_escape]}]]};
+setup_compile("reader_options") ->
+ {ok, [[]|[{compile_opts, [{reader, {?MODULE, extra_reader}}, {reader_options, [{user_id, <<"007">>}, {user_name, <<"Agent">>}]}]}]]};
+setup_compile("ssi_reader_options") ->
+ {ok, [[]|[{compile_opts, [{reader, {?MODULE, extra_reader}}, {reader_options, [{user_id, <<"007">>}, {user_name, <<"Agent">>}]}]}]]};
 setup_compile(_) ->
     {ok, [[]]}.
 
+extra_reader(FileName, ReaderOptions) ->
+ UserID = proplists:get_value(user_id, ReaderOptions, <<"IDUnknown">>),
+ UserName = proplists:get_value(user_name, ReaderOptions, <<"NameUnknown">>),
+ case file:read_file(FileName) of
+  {ok, Data} when UserID == <<"007">>, UserName == <<"Agent">> ->
+   {ok, Data};
+  {ok, _Data} ->
+   {error, "Not Found"};
+  Err ->
+   Err
+ end.
 
 expected(File) ->
     Filename = template_file(expect, File),
@@ -2041,6 +2056,13 @@ setup("ssi") ->
 setup("wrapper") ->
     RenderVars = [{types, ["b", "a", "c"]}],
     {ok, RenderVars};
+setup("reader_options") ->
+ RenderVars = [{base_var, "base-barstring"}, {test_var, "test-barstring"}],
+% Options = [],%[{compile_opts, [{reader, {?MODULE, extra_reader}}, {reader_options, [{user_id, <<"007">>}, {user_name, <<"Agent">>}]}]}],
+  {ok, RenderVars};
+setup("ssi_reader_options") ->
+ RenderVars = [{path, "ssi_include.html"}],
+ {ok, RenderVars};
 
 %%--------------------------------------------------------------------
 %% Custom tags

+ 11 - 0
test/files/expect/reader_options

@@ -0,0 +1,11 @@
+base-barstring
+
+base template
+
+base title
+
+more of base template
+
+base content
+
+end of base template

+ 2 - 0
test/files/expect/ssi_reader_options

@@ -0,0 +1,2 @@
+{{ "Don't evaluate me!" }}
+

+ 1 - 0
test/files/input/reader_options

@@ -0,0 +1 @@
+{% extends "base" %}

+ 1 - 0
test/files/input/ssi_reader_options

@@ -0,0 +1 @@
+{% ssi path %}