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

support cycle ... as var syntax (ref #195).

Andreas Stenius 10 лет назад
Родитель
Сommit
34f823798e
3 измененных файлов с 39 добавлено и 7 удалено
  1. 14 4
      src/erlydtl_beam_compiler.erl
  2. 5 1
      src/erlydtl_parser.yrl
  3. 20 2
      test/erlydtl_test_defs.erl

+ 14 - 4
src/erlydtl_beam_compiler.erl

@@ -603,8 +603,8 @@ body_ast(DjangoParseTree, BodyScope, TreeWalker) ->
                 empty_ast(TW);
             ({'comment_tag', _, _}, TW) ->
                 empty_ast(TW);
-            ({'cycle', Names}, TW) ->
-                cycle_ast(Names, TW);
+            ({'cycle', Names, AsVar}, TW) ->
+                cycle_ast(Names, AsVar, TW);
             ({'cycle_compat', Names}, TW) ->
                 cycle_compat_ast(Names, TW);
             ({'date', 'now', {string_literal, _Pos, FormatString}}, TW) ->
@@ -1422,7 +1422,7 @@ ifchanged_contents_ast(Contents, {IfContentsAst, IfContentsInfo}, {ElseContentsA
       merge_info(IfContentsInfo, ElseContentsInfo)},
      TreeWalker}.
 
-cycle_ast(Names, #treewalker{ context=Context }=TreeWalker) ->
+cycle_ast(Names, undefined, #treewalker{ context=Context }=TreeWalker) ->
     {NamesTuple, VarNames}
         = lists:mapfoldl(
             fun ({string_literal, _, Str}, VarNamesAcc) ->
@@ -1439,7 +1439,17 @@ cycle_ast(Names, #treewalker{ context=Context }=TreeWalker) ->
     {ForLoop, TreeWalker1} = resolve_reserved_variable('forloop', TreeWalker),
     {{?Q("erlydtl_runtime:cycle({_@NamesTuple}, _@ForLoop)"),
       #ast_info{ var_names = VarNames }},
-     TreeWalker1}.
+     TreeWalker1};
+cycle_ast(Names, {identifier, _, VarName}, TreeWalker) ->
+    {{VarAst, AstInfo}, TW1} = cycle_ast(Names, undefined, TreeWalker),
+    VarNameAst = varname_ast(VarName),
+    {Scope, TW2} = begin_scope(
+                     {[{VarName, VarNameAst}],
+                      [?Q("_@VarNameAst = _@VarAst"),
+                       VarAst
+                      ]},
+                     TW1),
+    {{Scope, AstInfo}, TW2}.
 
 %% Older Django templates treat cycle with comma-delimited elements as strings
 cycle_compat_ast(Names, #treewalker{ context=Context }=TreeWalker) ->

+ 5 - 1
src/erlydtl_parser.yrl

@@ -57,6 +57,7 @@ Nonterminals
     CommentBraced
     EndCommentBraced
 
+    CycleAs
     CycleTag
     CycleNames
     CycleNamesCompat
@@ -314,11 +315,14 @@ EndCommentBraced -> open_tag endcomment_keyword close_tag.
 CommentTag -> comment_tag : '$1'.
 
 CycleTag -> open_tag cycle_keyword CycleNamesCompat close_tag : {cycle_compat, '$3'}.
-CycleTag -> open_tag cycle_keyword CycleNames close_tag : {cycle, '$3'}.
+CycleTag -> open_tag cycle_keyword CycleNames CycleAs close_tag : {cycle, '$3', '$4'}.
 
 CycleNames -> Value : ['$1'].
 CycleNames -> CycleNames Value : '$1' ++ ['$2'].
 
+CycleAs -> '$empty' : undefined.
+CycleAs -> as_keyword identifier : '$2'.
+
 CycleNamesCompat -> identifier ',' : ['$1'].
 CycleNamesCompat -> CycleNamesCompat identifier ',' : '$1' ++ ['$2'].
 CycleNamesCompat -> CycleNamesCompat identifier : '$1' ++ ['$2'].

+ 20 - 2
test/erlydtl_test_defs.erl

@@ -68,13 +68,31 @@ all_test_defs() ->
         <<"{{ \"foo\"|add:\"\\\"\" }}">>, [], <<"foo\"">>}
       ]},
      {"cycle",
-      [{"Cycling through quoted strings",
+      [#test{
+          title = "deprecated cycle syntax",
+          source = <<"{% for i in test %}{% cycle a,b %}{{ i }},{% endfor %}">>,
+          render_vars = [{test, [0,1,2,3,4]}],
+          output = <<"a0,b1,a2,b3,a4,">>
+         },
+       {"Cycling through quoted strings",
         <<"{% for i in test %}{% cycle 'a' 'b' %}{{ i }},{% endfor %}">>,
         [{test, ["0", "1", "2", "3", "4"]}], <<"a0,b1,a2,b3,a4,">>},
        {"Cycling through normal variables",
         <<"{% for i in test %}{% cycle aye bee %}{{ i }},{% endfor %}">>,
         [{test, ["0", "1", "2", "3", "4"]}, {aye, "a"}, {bee, "b"}],
-        <<"a0,b1,a2,b3,a4,">>}
+        <<"a0,b1,a2,b3,a4,">>},
+       #test{
+          title = "mix strings and variables",
+          source = <<"{% for i in test %}{% cycle 'a' b 'c' %}{{ i }},{% endfor %}">>,
+          render_vars = [{test, [0,1,2,3,4]}, {b, 'B'}],
+          output = <<"a0,B1,c2,a3,B4,">>
+         },
+       #test{
+          title = "keep current value in local variable",
+          source = <<"{% for i in test %}{% cycle 'a' 'b' as c %}{{ i }}{{ c }},{% endfor %}">>,
+          render_vars = [{test, [0,1,2,3,4]}],
+          output = <<"a0a,b1b,a2a,b3b,a4a,">>
+         }
       ]},
      {"number literal",
       [{"Render integer",