Browse Source

Implement "iriencode" filter

Evan Miller 14 years ago
parent
commit
9646b5a4e6

+ 3 - 3
README.markdown

@@ -1,15 +1,15 @@
 ErlyDTL
 ErlyDTL
 =======
 =======
 
 
-ErlyDTL implements most but not all of the Django Template Language.
+ErlyDTL compiles Django Template Language to Erlang bytecode.
 
 
 *Supported tags*: autoescape, block, comment, cycle, extends, filter, firstof, for, if, ifequal, ifnotequal, include, now, spaceless, ssi, templatetag, trans, widthratio, with
 *Supported tags*: autoescape, block, comment, cycle, extends, filter, firstof, for, if, ifequal, ifnotequal, include, now, spaceless, ssi, templatetag, trans, widthratio, with
 
 
 _Unsupported tags_: csrf_token, ifchanged, regroup, url
 _Unsupported tags_: csrf_token, ifchanged, regroup, url
 
 
-*Supported filters*: add, addslashes, capfirst, center, cut, date, default, default_if_none, dictsort, dictsortreversed, divisibleby, escape, escapejs, filesizeformat, first, fix_ampersands, floatformat, force_escape, format_integer, format_number, get_digit, join, last, length, length_is, linebreaks, linebreaksbr, linenumbers, ljust, lower, make_list, phonenumeric, pluralize, pprint, random, random_num, random_range, removetags, rjust, safe, safeseq, slice, slugify, stringformat, striptags, time, timesince, timeuntil, title, truncatewords, truncatewords_html, unordered_list, upper, urlencode, urlize, urlizetrunc, wordcount, wordwrap, yesno
+*Supported filters*: add, addslashes, capfirst, center, cut, date, default, default_if_none, dictsort, dictsortreversed, divisibleby, escape, escapejs, filesizeformat, first, fix_ampersands, floatformat, force_escape, format_integer, format_number, get_digit, iriencode, join, last, length, length_is, linebreaks, linebreaksbr, linenumbers, ljust, lower, make_list, phonenumeric, pluralize, pprint, random, random_num, random_range, removetags, rjust, safe, safeseq, slice, slugify, stringformat, striptags, time, timesince, timeuntil, title, truncatewords, truncatewords_html, unordered_list, upper, urlencode, urlize, urlizetrunc, wordcount, wordwrap, yesno
 
 
-_Unsupported filter_: iriencode
+_Unsupported filters_: _none_
 
 
 Project homepage: <http://code.google.com/p/erlydtl/>
 Project homepage: <http://code.google.com/p/erlydtl/>
 
 

+ 1 - 1
src/erlydtl_compiler.erl

@@ -852,7 +852,7 @@ auto_escape(Value, _, _) ->
     Value.
     Value.
 
 
 firstof_ast(Vars, Context, TreeWalker) ->
 firstof_ast(Vars, Context, TreeWalker) ->
-	body_ast([lists:foldl(fun
+	body_ast([lists:foldr(fun
         ({L, _, _}=Var, []) when L=:=string_literal;L=:=number_literal ->
         ({L, _, _}=Var, []) when L=:=string_literal;L=:=number_literal ->
             Var;
             Var;
         ({L, _, _}, _) when L=:=string_literal;L=:=number_literal ->
         ({L, _, _}, _) when L=:=string_literal;L=:=number_literal ->

+ 35 - 1
src/erlydtl_filters.erl

@@ -67,7 +67,7 @@
         format_integer/1,
         format_integer/1,
         format_number/1,
         format_number/1,
         get_digit/2,
         get_digit/2,
-        %iriencode/1,
+        iriencode/1,
         join/2,
         join/2,
         last/1,
         last/1,
         length/1,
         length/1,
@@ -117,6 +117,27 @@
         (C >= $0 andalso C =< $9) orelse
         (C >= $0 andalso C =< $9) orelse
         (C =:= $\. orelse C =:= $-
         (C =:= $\. orelse C =:= $-
         orelse C =:= $~ orelse C =:= $_))).
         orelse C =:= $~ orelse C =:= $_))).
+
+-define(NO_IRI_ENCODE(C), (?NO_ENCODE(C) orelse (
+            C =:= $/ orelse 
+            C =:= $# orelse 
+            C =:= $[ orelse
+            C =:= $] orelse
+            C =:= $= orelse
+            C =:= $: orelse
+            C =:= $; orelse
+            C =:= $$ orelse
+            C =:= $& orelse
+            C =:= $( orelse
+            C =:= $) orelse
+            C =:= $+ orelse
+            C =:= $, orelse
+            C =:= $! orelse
+            C =:= $? orelse
+            C =:= $* orelse
+            C =:= $@ orelse
+            C =:= $' orelse
+            C =:= $~))).
  
  
 -define(KILOBYTE, 1024).
 -define(KILOBYTE, 1024).
 -define(MEGABYTE, (1024 * ?KILOBYTE)).
 -define(MEGABYTE, (1024 * ?KILOBYTE)).
@@ -308,6 +329,9 @@ get_digit(Input, Digit) when Digit > 0 ->
 get_digit(Input, _) ->
 get_digit(Input, _) ->
     Input.
     Input.
 
 
+iriencode(Input) ->
+    iriencode(unicode:characters_to_list(Input), []).
+
 %% @doc Joins a list with a given separator.
 %% @doc Joins a list with a given separator.
 join(Input, Separator) when is_list(Input) ->
 join(Input, Separator) when is_list(Input) ->
     join_io(Input, Separator).
     join_io(Input, Separator).
@@ -832,6 +856,16 @@ fix_ampersands("&" ++ Rest, Acc) ->
 fix_ampersands([C | Rest], Acc) ->
 fix_ampersands([C | Rest], Acc) ->
     fix_ampersands(Rest, [C | Acc]).
     fix_ampersands(Rest, [C | Acc]).
 
 
+iriencode([], Acc) ->
+    lists:reverse(Acc);
+iriencode([C | Rest], Acc) when ?NO_IRI_ENCODE(C) ->
+    iriencode(Rest, [C | Acc]);
+iriencode([$\s | Rest], Acc) ->
+    iriencode(Rest, [$+ | Acc]);
+iriencode([C | Rest], Acc) ->
+    <<Hi:4, Lo:4>> = <<C>>,
+    iriencode(Rest, [hexdigit(Lo), hexdigit(Hi), $\% | Acc]).
+
 join_io([], _Sep) -> [];
 join_io([], _Sep) -> [];
 join_io([_] = X, _Sep) -> X;
 join_io([_] = X, _Sep) -> X;
 join_io([X|T], Sep) -> [X,Sep] ++ join_io(T, Sep).
 join_io([X|T], Sep) -> [X,Sep] ++ join_io(T, Sep).

+ 5 - 6
src/erlydtl_parser.yrl

@@ -39,6 +39,7 @@ Nonterminals
     ValueBraced
     ValueBraced
 
 
     Value
     Value
+    Values
     Variable
     Variable
     Filter
     Filter
     
     
@@ -63,8 +64,6 @@ Nonterminals
     NowTag
     NowTag
 
 
     FirstofTag
     FirstofTag
-    FirstofList
-    FirstofValues
 
 
     FilterBlock
     FilterBlock
     FilterBraced
     FilterBraced
@@ -218,6 +217,9 @@ Value -> Value '|' Filter : {apply_filter, '$1', '$3'}.
 Value -> Variable : '$1'.
 Value -> Variable : '$1'.
 Value -> Literal : '$1'.
 Value -> Literal : '$1'.
 
 
+Values -> Value : ['$1'].
+Values -> Values Value : '$1' ++ ['$2'].
+
 Variable -> identifier : {variable, '$1'}.
 Variable -> identifier : {variable, '$1'}.
 Variable -> Variable '.' identifier : {attribute, {'$3', '$1'}}.
 Variable -> Variable '.' identifier : {attribute, {'$3', '$1'}}.
 
 
@@ -254,10 +256,7 @@ EndFilterBraced -> open_tag endfilter_keyword close_tag.
 Filters -> Filter : ['$1'].
 Filters -> Filter : ['$1'].
 Filters -> Filters '|' Filter : '$1' ++ ['$3'].
 Filters -> Filters '|' Filter : '$1' ++ ['$3'].
 
 
-FirstofTag -> open_tag firstof_keyword FirstofList close_tag : '$3'.
-FirstofList -> FirstofValues : {firstof, '$1'}.
-FirstofValues -> FirstofValues Value : ['$2'|'$1'].
-FirstofValues -> Value : ['$1'].
+FirstofTag -> open_tag firstof_keyword Values close_tag : {firstof, '$3'}.
 
 
 ForBlock -> ForBraced Elements EndForBraced : {for, '$1', '$2'}.
 ForBlock -> ForBraced Elements EndForBraced : {for, '$1', '$2'}.
 ForBlock -> ForBraced Elements EmptyBraced Elements EndForBraced : {for, '$1', '$2', '$4'}.
 ForBlock -> ForBraced Elements EmptyBraced Elements EndForBraced : {for, '$1', '$2', '$4'}.

+ 1 - 1
src/erlydtl_scanner.erl

@@ -96,7 +96,7 @@ scan([], Scanned, _, in_text) ->
                             
                             
                             "templatetag", "openblock", "closeblock", "openvariable", "closevariable", "openbrace", "closebrace", "opencomment", "closecomment",
                             "templatetag", "openblock", "closeblock", "openvariable", "closevariable", "openbrace", "closebrace", "opencomment", "closecomment",
 
 
-                            %TODO "url",
+                            % "url", - implemented as custom tag
 
 
                             "widthratio",
                             "widthratio",
 
 

+ 2 - 0
tests/src/erlydtl_unittests.erl

@@ -425,6 +425,8 @@ tests() ->
                     <<"{{ var1|format_number }}">>, [{var1, fun() -> fun() -> 31 end end}], <<"31">>},
                     <<"{{ var1|format_number }}">>, [{var1, fun() -> fun() -> 31 end end}], <<"31">>},
                 {"|get_digit:\"2\"",
                 {"|get_digit:\"2\"",
                     <<"{{ var1|get_digit:\"2\" }}">>, [{var1, 42}], <<"4">>},
                     <<"{{ var1|get_digit:\"2\" }}">>, [{var1, 42}], <<"4">>},
+                {"|iriencode",
+                    <<"{{ url|iriencode }}">>, [{url, "You #$*@!!"}], <<"You+#$*@!!">>},
                 {"|join:\", \" (list)",
                 {"|join:\", \" (list)",
                     <<"{{ var1|join:\", \" }}">>, [{var1, ["Liberte", "Egalite", "Fraternite"]}],
                     <<"{{ var1|join:\", \" }}">>, [{var1, ["Liberte", "Egalite", "Fraternite"]}],
                     <<"Liberte, Egalite, Fraternite">>},
                     <<"Liberte, Egalite, Fraternite">>},