Browse Source

Merge branch 'master' of git://github.com/noss/erlydtl

Conflicts:
	Makefile
	src/erlydtl/erlydtl.app
	src/erlydtl/erlydtl_compiler.erl
	src/erlydtl/erlydtl_filters.erl
	src/erlydtl/erlydtl_parser.yrl
	src/erlydtl/erlydtl_runtime.erl
	src/erlydtl/erlydtl_scanner.erl
	src/tests/erlydtl_functional_tests.erl
	src/tests/erlydtl_unittests.erl
Evan Miller 15 years ago
parent
commit
21cd779198

+ 25 - 0
bin/erlydtl_compile

@@ -0,0 +1,25 @@
+#!/usr/bin/env escript
+%% -*- mode: erlang -*-
+-export([main/1]).
+
+%% External API
+
+main([Prefix, File]) ->
+    ensure(),
+    Basename = filename:basename(File, ".dtl"),
+    ModuleName = list_to_atom(string:to_lower(lists:flatten([Prefix, "_", Basename]))),
+    erlydtl_compiler:compile(File, ModuleName, [{out_dir, filename:dirname(File)}]);
+main(_) ->
+    usage().
+
+ensure() ->
+    code:add_patha("ebin"),
+    code:add_patha("lib/erlydtl/ebin"),
+    [D1,D2|_] = code:get_path(),
+    io:format("Code Path: ~p~n", [[D1,D2]]).
+
+
+usage() ->
+    io:format("usage: ~s name [destdir]~n",
+              [filename:basename(escript:script_name())]),
+    halt(1).

+ 1 - 0
examples/rendered_output/.gitignore

@@ -0,0 +1 @@
+*

+ 0 - 4
src/erlydtl/erlydtl.app

@@ -19,7 +19,3 @@
   {applications, [kernel, stdlib]},
   {registered, []}
  ]}.
-
-
-
-

+ 14 - 2
src/erlydtl/erlydtl_compiler.erl

@@ -370,6 +370,8 @@ body_ast(DjangoParseTree, Context, TreeWalker) ->
             	call_ast(Name, TreeWalkerAcc);
             ({'call', {'identifier', _, Name}, With}, TreeWalkerAcc) ->
             	call_with_ast(Name, With, Context, TreeWalkerAcc);
+            ({'firstof', Vars}, TreeWalkerAcc) ->
+                firstof_ast(Vars, Context, TreeWalkerAcc);
             ({'cycle', Names}, TreeWalkerAcc) ->
                 cycle_ast(Names, Context, TreeWalkerAcc);
             ({'cycle_compat', Names}, TreeWalkerAcc) ->
@@ -571,6 +573,17 @@ auto_escape(Value, Context) ->
             Value
     end.
 
+firstof_ast(Vars, Context, TreeWalker) ->
+	body_ast([lists:foldl(fun
+        ({L, _, _}=Var, []) when L=:=string_literal;L=:=number_literal ->
+            Var;
+        ({L, _, _}, _) when L=:=string_literal;L=:=number_literal ->
+            erlang:error(errbadliteral);
+        (Var, []) ->
+            {'ifelse', Var, [Var], []};
+        (Var, Acc) ->
+            {'ifelse', Var, [Var], [Acc]} end,
+    	[], Vars)], Context, TreeWalker).
 
 ifelse_ast({'not', Expression}, IfAstInfo, ElseAstInfo, Context, TreeWalker) ->
     ifelse_ast(Expression, ElseAstInfo, IfAstInfo, Context, TreeWalker);
@@ -711,8 +724,7 @@ tag_ast(Name, Args, Context, TreeWalker) ->
                     ({{identifier, _, Key}, {string_literal, _, Value}}) ->
                         {list_to_atom(Key), erl_syntax:string(unescape_string_literal(Value))};
                     ({{identifier, _, Key}, Value}) ->
-                        {AST, _} = resolve_variable_ast(Value, Context),
-                        {list_to_atom(Key), format(AST,Context)}
+                        {list_to_atom(Key), format(resolve_variable_ast(Value, Context), Context)}
                 end, Args),
             DefaultFilePath = filename:join([erlydtl_deps:get_base_dir(), "priv", "custom_tags", Name]),
             case Context#dtl_context.custom_tags_dir of

+ 1 - 0
src/erlydtl/erlydtl_filters.erl

@@ -220,6 +220,7 @@ urlencode(Input) when is_binary(Input) ->
 urlencode(Input) when is_list(Input) ->
     urlencode(Input, []).
 
+
 % internal
 
 escape(Binary, Index) when is_binary(Binary) ->

+ 11 - 0
src/erlydtl/erlydtl_parser.yrl

@@ -54,6 +54,10 @@ Nonterminals
     CycleNames
     CycleNamesCompat
 
+    FirstofTag
+    FirstofList
+    FirstofValues
+
     ForBlock
     ForBraced
     EndForBraced
@@ -114,6 +118,7 @@ Terminals
     endifnotequal_keyword
     equal
     extends_keyword
+    firstof_keyword
     for_keyword
     identifier
     if_keyword
@@ -144,6 +149,7 @@ Elements -> Elements NowTag : '$1' ++ ['$2'].
 Elements -> Elements LoadTag : '$1' ++ ['$2'].
 Elements -> Elements CycleTag : '$1' ++ ['$2'].
 Elements -> Elements BlockBlock : '$1' ++ ['$2'].
+Elements -> Elements FirstofTag : '$1' ++ ['$2'].
 Elements -> Elements ForBlock : '$1' ++ ['$2'].
 Elements -> Elements IfBlock : '$1' ++ ['$2'].
 Elements -> Elements IfEqualBlock : '$1' ++ ['$2'].
@@ -189,6 +195,11 @@ CycleNamesCompat -> identifier comma : ['$1'].
 CycleNamesCompat -> CycleNamesCompat identifier comma : '$1' ++ ['$2'].
 CycleNamesCompat -> CycleNamesCompat identifier : '$1' ++ ['$2'].
 
+FirstofTag -> open_tag firstof_keyword FirstofList close_tag : '$3'.
+FirstofList -> FirstofValues : {firstof, '$1'}.
+FirstofValues -> FirstofValues Value : ['$2'|'$1'].
+FirstofValues -> Value : ['$1'].
+
 ForBlock -> ForBraced Elements EndForBraced : {for, '$1', '$2'}.
 ForBraced -> open_tag for_keyword ForExpression close_tag : '$3'.
 EndForBraced -> open_tag endfor_keyword close_tag.

+ 2 - 0
src/erlydtl/erlydtl_runtime.erl

@@ -2,6 +2,8 @@
 
 -compile(export_all).
 
+find_value(_, undefined) ->
+	undefined;
 find_value(Key, L) when is_list(L) ->
     case proplists:get_value(Key, L) of
         undefined ->

+ 3 - 3
src/erlydtl/erlydtl_scanner.erl

@@ -194,7 +194,7 @@ scan([H | T], Scanned, {Row, Column}, {in_code, Closer}) ->
         digit ->
             scan(T, [{number_literal, {Row, Column}, [H]} | Scanned], {Row, Column + 1}, {in_number, Closer});
         _ ->
-            {error, {illegal_character, {line, Row}, {column, Column}}}
+            {error, lists:concat(["Illegal character line ", Row, " column ", Column])}
     end;
 
 scan([H | T], Scanned, {Row, Column}, {in_number, Closer}) ->
@@ -202,7 +202,7 @@ scan([H | T], Scanned, {Row, Column}, {in_number, Closer}) ->
         digit ->
             scan(T, append_char(Scanned, H), {Row, Column + 1}, {in_number, Closer});
         _ ->
-            {error, {illegal_character, {line, Row}, {column, Column}}}
+            {error, lists:concat(["Illegal character line ", Row, " column ", Column])}
     end;
 
 scan([H | T], Scanned, {Row, Column}, {in_identifier, Closer}) ->
@@ -212,7 +212,7 @@ scan([H | T], Scanned, {Row, Column}, {in_identifier, Closer}) ->
         digit ->
             scan(T, append_char(Scanned, H), {Row, Column + 1}, {in_identifier, Closer});
         _ ->
-            {error, {illegal_character, {line, Row}, {column, Column}}}
+            {error, lists:concat(["Illegal character line ", Row, " column ", Column])}
     end.
 
 % internal functions

+ 29 - 1
src/tests/erlydtl_unittests.erl

@@ -116,7 +116,9 @@ tests() ->
                 {"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"]}], <<>>}
+                    <<"{% if var1 in var2 %}boo{% endif %}">>, [{var1, "FOO"}, {var2, ["bar", "foo", "baz"]}], <<>>},
+                {"If complex",
+                    <<"{% if foo.bar.baz %}omgwtfbbq{% endif %}">>, [], <<"">>}
             ]},
         {"for", [
                 {"Simple loop",
@@ -375,6 +377,32 @@ tests() ->
                     <<"{% ifequal var1|length 1 %}Y{% else %}N{% endifequal %}">>,
                      [{var1, ["foo", "bar", "baz"]}],
                      <<"N">>}
+        ]},
+    {"firstof", [
+            {"Firstof first",
+                <<"{% firstof foo bar baz %}">>,
+                [{foo, "1"},{bar, "2"}],
+                <<"1">>},
+            {"Firstof second",
+                <<"{% firstof foo bar baz %}">>,
+                [{bar, "2"}],
+                <<"2">>},
+            {"Firstof none",
+                <<"{% firstof foo bar baz %}">>,
+                [],
+                <<"">>},
+            {"Firstof complex",
+                <<"{% firstof foo.bar.baz bar %}">>,
+                [{foo, [{bar, [{baz, "quux"}]}]}],
+                <<"quux">>},
+            {"Firstof undefined complex",
+                <<"{% firstof foo.bar.baz bar %}">>,
+                [{bar, "bar"}],
+                <<"bar">>},
+            {"Firstof literal",
+                <<"{% firstof foo bar \"baz\" %}">>,
+                [],
+                <<"baz">>}
         ]}
     ].