Browse Source

New syntax: {% if arg1 in arg2 %}

Tests to see if arg1 is a substring of arg2, or else if arg1 is equal to any element of arg2.

(Feature is present in Django dev)
Evan Miller 15 years ago
parent
commit
62e3426d65

+ 17 - 12
src/erlydtl/erlydtl_compiler.erl

@@ -335,22 +335,14 @@ body_ast(DjangoParseTree, Context, TreeWalker) ->
                 {{format(Ast, Context), #ast_info{var_names = [VarName]}}, TreeWalkerAcc};              
             ({'include', {string_literal, _, File}}, TreeWalkerAcc) ->
                 include_ast(unescape_string_literal(File), Context, TreeWalkerAcc);
-            ({'if', {'not', Variable}, Contents}, TreeWalkerAcc) ->
-                {IfAstInfo, TreeWalker1} = empty_ast(TreeWalkerAcc),
-                {ElseAstInfo, TreeWalker2} = body_ast(Contents, Context, TreeWalker1),
-                ifelse_ast(Variable, IfAstInfo, ElseAstInfo, Context, TreeWalker2);
-            ({'if', Variable, Contents}, TreeWalkerAcc) ->
+            ({'if', Expression, Contents}, TreeWalkerAcc) ->
                 {IfAstInfo, TreeWalker1} = body_ast(Contents, Context, TreeWalkerAcc),
                 {ElseAstInfo, TreeWalker2} = empty_ast(TreeWalker1),
-                ifelse_ast(Variable, IfAstInfo, ElseAstInfo, Context, TreeWalker2);
-            ({'ifelse', {'not', Variable}, IfContents, ElseContents}, TreeWalkerAcc) ->
-                {IfAstInfo, TreeWalker1} = body_ast(ElseContents, Context, TreeWalkerAcc),
-                {ElseAstInfo, TreeWalker2} = body_ast(IfContents, Context, TreeWalker1),
-                ifelse_ast(Variable, IfAstInfo, ElseAstInfo, Context, TreeWalker2);                  
-            ({'ifelse', Variable, IfContents, ElseContents}, TreeWalkerAcc) ->
+                ifelse_ast(Expression, IfAstInfo, ElseAstInfo, Context, TreeWalker2);
+            ({'ifelse', Expression, IfContents, ElseContents}, TreeWalkerAcc) ->
                 {IfAstInfo, TreeWalker1} = body_ast(IfContents, Context, TreeWalkerAcc),
                 {ElseAstInfo, TreeWalker2} = body_ast(ElseContents, Context, TreeWalker1),
-                ifelse_ast(Variable, IfAstInfo, ElseAstInfo, Context, TreeWalker2);
+                ifelse_ast(Expression, IfAstInfo, ElseAstInfo, Context, TreeWalker2);
             ({'ifequal', Args, Contents}, TreeWalkerAcc) ->
                 {IfAstInfo, TreeWalker1} = body_ast(Contents, Context, TreeWalkerAcc),
                 {ElseAstInfo, TreeWalker2} = empty_ast(TreeWalker1),
@@ -565,6 +557,19 @@ auto_escape(Value, Context) ->
     end.
 
 
+ifelse_ast({'not', Expression}, IfAstInfo, ElseAstInfo, Context, TreeWalker) ->
+    ifelse_ast(Expression, ElseAstInfo, IfAstInfo, Context, TreeWalker);
+ifelse_ast({'in', Variable1, Variable2}, {IfContentsAst, IfContentsInfo}, {ElseContentsAst, ElseContentsInfo}, Context, TreeWalker) ->
+    Info = merge_info(IfContentsInfo, ElseContentsInfo),
+    VarNames = Info#ast_info.var_names,
+    {Ast1, VarName1} = resolve_ifvariable_ast(Variable1, Context),
+    {Ast2, VarName2} = resolve_ifvariable_ast(Variable2, Context),
+    {{erl_syntax:case_expr(erl_syntax:application(erl_syntax:atom(erlydtl_runtime), erl_syntax:atom(is_in), [Ast1, Ast2]),
+        [erl_syntax:clause([erl_syntax:atom(true)], none, 
+                [IfContentsAst]),
+            erl_syntax:clause([erl_syntax:underscore()], none,
+                [ElseContentsAst])
+        ]), Info#ast_info{var_names = [VarName1, VarName2 | VarNames]}}, TreeWalker};
 ifelse_ast(Variable, {IfContentsAst, IfContentsInfo}, {ElseContentsAst, ElseContentsInfo}, Context, TreeWalker) ->
     Info = merge_info(IfContentsInfo, ElseContentsInfo),
     VarNames = Info#ast_info.var_names,

+ 3 - 1
src/erlydtl/erlydtl_parser.yrl

@@ -199,7 +199,9 @@ ForGroup -> ForGroup comma identifier : '$1' ++ ['$3'].
 IfBlock -> IfBraced Elements ElseBraced Elements EndIfBraced : {ifelse, '$1', '$2', '$4'}.
 IfBlock -> IfBraced Elements EndIfBraced : {'if', '$1', '$2'}.
 IfBraced -> open_tag if_keyword IfExpression close_tag : '$3'.
-IfExpression -> not_keyword IfExpression : {'not', '$2'}.
+IfExpression -> not_keyword Value : {'not', '$2'}.
+IfExpression -> Value in_keyword Value : {'in', '$1', '$3'}.
+IfExpression -> Value not_keyword in_keyword Value : {'not', {'in', '$1', '$4'}}.
 IfExpression -> Value : '$1'.
 
 ElseBraced -> open_tag else_keyword close_tag.

+ 17 - 0
src/erlydtl/erlydtl_runtime.erl

@@ -82,6 +82,23 @@ is_false(<<>>) ->
 is_false(_) ->
     false.
 
+is_in(Sublist, [Sublist|_]) ->
+    true;
+is_in(Sublist, List) when is_binary(Sublist) ->
+    is_in(binary_to_list(Sublist), List);
+is_in(Sublist, List) when is_binary(List) ->
+    is_in(Sublist, binary_to_list(List));
+is_in(Sublist, [C|Rest]) when is_list(Sublist) andalso is_binary(C) ->
+    is_in(Sublist, [binary_to_list(C)|Rest]);
+is_in(Sublist, [C|Rest]) when is_list(Sublist) andalso is_list(C) ->
+    is_in(Sublist, Rest);
+is_in(Sublist, List) when is_list(Sublist) andalso is_list(List) ->
+    string:str(List, Sublist) > 0;
+is_in(Element, List) when is_list(List) ->
+    lists:member(Element, List);
+is_in(_, _) ->
+    false.
+
 stringify_final(In) ->
    stringify_final(In, []).
 stringify_final([], Out) ->

+ 13 - 1
src/tests/erlydtl_unittests.erl

@@ -100,7 +100,19 @@ tests() ->
                 {"If non-empty string",
                     <<"{% if var1 %}yay{% endif %}">>, [{var1, "hello"}], <<"yay">>},
                 {"If proplist",
-                    <<"{% if var1 %}yay{% endif %}">>, [{var1, [{foo, "bar"}]}], <<"yay">>}
+                    <<"{% if var1 %}yay{% endif %}">>, [{var1, [{foo, "bar"}]}], <<"yay">>},
+                {"If substring in string",
+                    <<"{% if var1 in var2 %}yay{% endif %}">>, [{var1, "rook"}, {var2, "Crooks"}], <<"yay">>},
+                {"If substring in string (false)",
+                    <<"{% if var1 in var2 %}boo{% endif %}">>, [{var1, "Cook"}, {var2, "Crooks"}], <<>>},
+                {"If substring not in string",
+                    <<"{% if var1 not in var2 %}yay{% endif %}">>, [{var1, "Cook"}, {var2, "Crooks"}], <<"yay">>},
+                {"If substring not in string (false)",
+                    <<"{% if var1 not in var2 %}boo{% endif %}">>, [{var1, "rook"}, {var2, "Crooks"}], <<>>},
+                {"If element in list",
+                    <<"{% if var1 in var2 %}yay{% endif %}">>, [{var1, "foo"}, {var2, ["bar", "foo", "baz"]}], <<"yay">>},
+                {"If element in list (false)",
+                    <<"{% if var1 in var2 %}boo{% endif %}">>, [{var1, "FOO"}, {var2, ["bar", "foo", "baz"]}], <<>>}
             ]},
         {"for", [
                 {"Simple loop",