Просмотр исходного кода

* Added the ability to use filters in if/ifelse expressions, e.g. :

{% if var1|length_is:10 %}

{% ifequal months_list|length %}

* fixed a bug with erlydtl_runtime:are_equal which always
returned false when comparing 2 single character values, e.g. :

  erlydtl_runtime:are_equal("9", "9").
  erlydtl_runtime:are_equal("x", "x").

.. always returned false.  This would have manifested itself in 
the scenario {% ifequal foo "x" %} where foo was a variable with 
the value "x".

* the generated iolist now goes through an additional output 
filter called erlydtl_tuntime:stringify_final.  This will stringify
any atoms making it safe for filters to return atoms and also 
for atoms to be passed in to the render() function.



git-svn-id: http://erlydtl.googlecode.com/svn/trunk@136 a5195066-8e3e-0410-a82a-05b01b1b9875
colm.dougan 17 лет назад
Родитель
Сommit
3a6e67817c

+ 27 - 7
src/erlydtl/erlydtl_compiler.erl

@@ -240,11 +240,17 @@ forms(File, Module, BodyAst, BodyInfo, CheckSum) ->
                     ({XFile, XCheckSum}) -> 
                         erl_syntax:tuple([erl_syntax:string(XFile), erl_syntax:string(XCheckSum)])
                 end, BodyInfo#ast_info.dependencies))])]),     
-    
+
+   BodyAstTmp = erl_syntax:application(
+                    erl_syntax:atom(erlydtl_runtime),
+                    erl_syntax:atom(stringify_final),
+                    [BodyAst]
+                ),
+
     RenderInternalFunctionAst = erl_syntax:function(
         erl_syntax:atom(render2), 
             [erl_syntax:clause([erl_syntax:variable("Variables")], none, 
-                [BodyAst])]),   
+                [BodyAstTmp])]),   
     
     ModuleAst  = erl_syntax:attribute(erl_syntax:atom(module), [erl_syntax:atom(Module)]),
     
@@ -464,9 +470,13 @@ filter_ast(Variable, Filter, Context, TreeWalker) ->
 
 filter_ast_noescape(Variable, [{identifier, _, "escape"}], Context, TreeWalker) ->
     body_ast([Variable], Context, TreeWalker);
-filter_ast_noescape(Variable, [{identifier, _, Name} | Arg], Context, TreeWalker) ->
+filter_ast_noescape(Variable, Filter, Context, TreeWalker) ->
     {{VariableAst, Info}, TreeWalker2} = body_ast([Variable], Context, TreeWalker),
-    {{erl_syntax:application(erl_syntax:atom(erlydtl_filters), erl_syntax:atom(Name), 
+    VarValue = filter_ast1(Filter, VariableAst),
+    {{VarValue, Info}, TreeWalker2}.
+
+filter_ast1([{identifier, _, Name} | Arg], VariableAst) ->
+    erl_syntax:application(erl_syntax:atom(erlydtl_filters), erl_syntax:atom(Name), 
         [VariableAst | case Arg of 
                 [{string_literal, _, ArgName}] ->
                     [erl_syntax:string(unescape_string_literal(ArgName))];
@@ -474,8 +484,8 @@ filter_ast_noescape(Variable, [{identifier, _, Name} | Arg], Context, TreeWalker
                     [erl_syntax:integer(list_to_integer(ArgName))];
                 _ ->
                     []
-            end]), Info}, TreeWalker2}.
-
+            end]).
+ 
 search_for_escape_filter(_, _, #dtl_context{auto_escape = on}) ->
     on;
 search_for_escape_filter(_, _, #dtl_context{auto_escape = did}) ->
@@ -490,6 +500,8 @@ search_for_escape_filter({apply_filter, Variable, Filter}, _) ->
 search_for_escape_filter(_Variable, _Filter) ->
     off.
 
+
+
 resolve_variable_ast(VarTuple, Context) ->
     resolve_variable_ast(VarTuple, Context, 'fetch_value').
  
@@ -509,7 +521,15 @@ resolve_variable_ast({variable, {identifier, _, VarName}}, Context, FinderFuncti
         Val ->
             Val
     end,
-    {VarValue, VarName}.
+    {VarValue, VarName};
+
+resolve_variable_ast({apply_filter, Variable, Filter}, Context, FinderFunction) ->
+    {VarAst, VarName} = resolve_variable_ast(Variable, Context, FinderFunction),
+    VarValue = filter_ast1(Filter, erl_syntax:list([VarAst])),
+    {VarValue, VarName};
+
+resolve_variable_ast(What, _Context, _FinderFunction) ->
+   error_logger:error_msg("~p:resolve_variable_ast unhandled: ~p~n", [?MODULE, What]).
 
 resolve_scoped_variable_ast(VarName, Context) ->
     lists:foldl(fun(Scope, Value) ->

+ 5 - 2
src/erlydtl/erlydtl_filters.erl

@@ -128,13 +128,16 @@ last(Input) when is_binary(Input) ->
 last(Input) when is_list(Input) ->
     [lists:last(Input)].
 
+length([]) -> "0";
 length([Input]) when is_list(Input) ->
     integer_to_list(erlang:length(Input));
 length([Input]) when is_binary(Input) ->
     integer_to_list(size(Input)).
 
-length_is(Input, Number) when is_list(Input) ->
-    lists:concat([?MODULE:length(Input) =:= integer_to_list(Number)]).
+length_is(Input, Number) when is_list(Input), is_integer(Number) ->
+    length_is(Input, integer_to_list(Number));
+length_is(Input, Number) when is_list(Input), is_list(Number) ->
+    ?MODULE:length(Input) =:= Number.
 
 linebreaksbr([Input]) when is_list(Input) or is_binary(Input) ->
     linebreaksbr(Input);

+ 21 - 6
src/erlydtl/erlydtl_runtime.erl

@@ -38,16 +38,22 @@ fetch_value(Key, Data) ->
             Val
     end.
 
-are_equal([Arg1], Arg2) when is_list(Arg1) ->
-    are_equal(Arg1, Arg2);
-are_equal(Arg1, [Arg2]) when is_list(Arg1) ->
-    are_equal(Arg1, Arg2);
+are_equal(Arg1, Arg2) when Arg1 =:= Arg2 ->
+    true;
 are_equal(Arg1, Arg2) when is_binary(Arg1) ->
     are_equal(binary_to_list(Arg1), Arg2);
 are_equal(Arg1, Arg2) when is_binary(Arg2) ->
     are_equal(Arg1, binary_to_list(Arg2));
-are_equal(Arg1, Arg2) ->
-    Arg1 =:= Arg2.
+are_equal(Arg1, Arg2) when is_integer(Arg1) ->
+    are_equal(integer_to_list(Arg1), Arg2);
+are_equal(Arg1, Arg2) when is_integer(Arg2) ->
+    are_equal(Arg1, integer_to_list(Arg2));
+are_equal([Arg1], Arg2) when is_list(Arg1) ->
+    are_equal(Arg1, Arg2);
+are_equal(Arg1, [Arg2]) when is_list(Arg1) ->
+    are_equal(Arg1, Arg2);
+are_equal(_, _) ->
+    false.
 
 is_false("") ->
     true;
@@ -64,6 +70,15 @@ is_false(<<>>) ->
 is_false(_) ->
     false.
 
+stringify_final(In) ->
+   stringify_final(In, []).
+stringify_final([], Out) ->
+   lists:reverse(Out);
+stringify_final([El | Rest], Out) when is_atom(El) ->
+   stringify_final(Rest, [atom_to_list(El) | Out]);
+stringify_final([El | Rest], Out) ->
+   stringify_final(Rest, [El | Out]).
+
 init_counter_stats(List) ->
     init_counter_stats(List, undefined).
 

+ 61 - 4
src/tests/erlydtl_unittests.erl

@@ -73,6 +73,8 @@ tests() ->
                     <<"{% if var1 %}boo{% endif %}">>, [{var1, "0"}], <<>>},
                 {"If false",
                     <<"{% if var1 %}boo{% endif %}">>, [{var1, false}], <<>>},
+                {"If false string",
+                    <<"{% if var1 %}boo{% endif %}">>, [{var1, "false"}], <<"boo">>},
                 {"If undefined",
                     <<"{% if var1 %}boo{% endif %}">>, [{var1, undefined}], <<>>},
                 {"If other atom",
@@ -136,7 +138,16 @@ tests() ->
                     [{var1, "foo"}], <<"yay">>},
                 {"Compare literal to unequal variable",
                     <<"{% ifequal \"foo\" var1 %}boo{% endifequal %}">>,
-                    [{var1, "bar"}], <<>>}
+                    [{var1, "bar"}], <<>>},
+                {"Compare variable to literal (int string)",
+                    <<"{% ifequal var1 \"2\" %}yay{% else %}boo{% endifequal %}">>,
+                    [{var1, "2"}], <<"yay">>},
+                {"Compare variable to literal (int)",
+                    <<"{% ifequal var1 2 %}yay{% else %}boo{% endifequal %}">>,
+                    [{var1, 2}], <<"yay">>},
+                {"Compare variable to unequal literal (int)",
+                    <<"{% ifequal var1 2 %}boo{% else %}yay{% endifequal %}">>,
+                    [{var1, 3}], <<"yay">>}
             ]},
         {"ifequal/else", [
                 {"Compare variable to literal",
@@ -180,8 +191,8 @@ tests() ->
                     <<"{% ifnotequal \"foo\" var1 %}yay{% else %}boo{% endifnotequal %}">>,
                     [{var1, "bar"}], <<"yay">>}
             ]},
-        {"filters", [
-                {"Filter a literal",
+       {"filters", [
+               {"Filter a literal",
                     <<"{{ \"pop\"|capfirst }}">>, [],
                     <<"Pop">>},
                 {"Filters applied in order",
@@ -254,7 +265,53 @@ tests() ->
                 {"|urlencode",
                     <<"{{ url|urlencode }}">>, [{url, "You #$*@!!"}],
                     <<"You+%23%24%2A%40%21%21">>}
-            ]}
+            ]},
+        {"filters_if", [
+                {"Filter if 1.1",
+                    <<"{% if var1|length_is:0 %}Y{% else %}N{% endif %}">>,
+                     [{var1, []}],
+                     <<"Y">>},
+                {"Filter if 1.2",
+                    <<"{% if var1|length_is:1 %}Y{% else %}N{% endif %}">>,
+                     [{var1, []}],
+                     <<"N">>},
+                {"Filter if 1.3",
+                    <<"{% if var1|length_is:7 %}Y{% else %}N{% endif %}">>,
+                     [{var1, []}],
+                     <<"N">>},
+                {"Filter if 2.1",
+                    <<"{% if var1|length_is:0 %}Y{% else %}N{% endif %}">>,
+                     [{var1, ["foo"]}],
+                     <<"N">>},
+                {"Filter if 2.2",
+                    <<"{% if var1|length_is:1 %}Y{% else %}N{% endif %}">>,
+                     [{var1, ["foo"]}],
+                     <<"Y">>},
+                {"Filter if 2.3",
+                    <<"{% if var1|length_is:7 %}Y{% else %}N{% endif %}">>,
+                     [{var1, ["foo"]}],
+                     <<"N">>},
+                {"Filter if 3.1",
+                    <<"{% ifequal var1|length 0 %}Y{% else %}N{% endifequal %}">>,
+                     [{var1, []}],
+                     <<"Y">>},
+                {"Filter if 3.1",
+                    <<"{% ifequal var1|length 1 %}Y{% else %}N{% endifequal %}">>,
+                     [{var1, []}],
+                     <<"N">>},
+                {"Filter if 4.1",
+                    <<"{% ifequal var1|length 3 %}Y{% else %}N{% endifequal %}">>,
+                     [{var1, ["foo", "bar", "baz"]}],
+                     <<"Y">>},
+                {"Filter if 4.2",
+                    <<"{% ifequal var1|length 0 %}Y{% else %}N{% endifequal %}">>,
+                     [{var1, ["foo", "bar", "baz"]}],
+                     <<"N">>},
+                {"Filter if 4.3",
+                    <<"{% ifequal var1|length 1 %}Y{% else %}N{% endifequal %}">>,
+                     [{var1, ["foo", "bar", "baz"]}],
+                     <<"N">>}
+        ]}
     ].
 
 run_tests() ->