Commits

Anonymous committed 1f07cc4

* 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.

Comments (0)

Files changed (4)

src/erlydtl/erlydtl_compiler.erl

                     ({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)]),
     
 
 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))];
                     [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}) ->
 search_for_escape_filter(_Variable, _Filter) ->
     off.
 
+
+
 resolve_variable_ast(VarTuple, Context) ->
     resolve_variable_ast(VarTuple, Context, 'fetch_value').
  
         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) ->

src/erlydtl/erlydtl_filters.erl

 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);

src/erlydtl/erlydtl_runtime.erl

             Val
     end.
 
+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) 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(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(_, _) ->
+    false.
 
 is_false("") ->
     true;
 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).
 

src/tests/erlydtl_unittests.erl

                     <<"{% 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",
                     [{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",
                     <<"{% 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",
                 {"|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() ->