|
@@ -36,16 +36,22 @@
|
|
|
-author('emmiller@gmail.com').
|
|
|
|
|
|
-export([add/2,
|
|
|
+ addslashes/1,
|
|
|
capfirst/1,
|
|
|
center/2,
|
|
|
+ cut/2,
|
|
|
date/2,
|
|
|
+ default/2,
|
|
|
default_if_none/2,
|
|
|
+ divisibleby/2,
|
|
|
escapejs/1,
|
|
|
+ filesizeformat/1,
|
|
|
first/1,
|
|
|
fix_ampersands/1,
|
|
|
force_escape/1,
|
|
|
format_integer/1,
|
|
|
format_number/1,
|
|
|
+ get_digit/2,
|
|
|
join/2,
|
|
|
last/1,
|
|
|
length/1,
|
|
@@ -53,10 +59,15 @@
|
|
|
linebreaksbr/1,
|
|
|
ljust/2,
|
|
|
lower/1,
|
|
|
+ phone2numeric/1,
|
|
|
+ random/1,
|
|
|
rjust/2,
|
|
|
+ slugify/1,
|
|
|
+ title/1,
|
|
|
truncatewords/2,
|
|
|
upper/1,
|
|
|
- urlencode/1]).
|
|
|
+ urlencode/1,
|
|
|
+ wordcount/1]).
|
|
|
|
|
|
-define(NO_ENCODE(C), ((C >= $a andalso C =< $z) orelse
|
|
|
(C >= $A andalso C =< $Z) orelse
|
|
@@ -64,6 +75,10 @@
|
|
|
(C =:= $\. orelse C =:= $-
|
|
|
orelse C =:= $~ orelse C =:= $_))).
|
|
|
|
|
|
+-define(KILOBYTE, 1024).
|
|
|
+-define(MEGABYTE, (1024 * ?KILOBYTE)).
|
|
|
+-define(GIGABYTE, (1024 * ?MEGABYTE)).
|
|
|
+
|
|
|
%% @doc Adds a number to the value.
|
|
|
add(Input, Number) when is_binary(Input) ->
|
|
|
list_to_binary(add(binary_to_list(Input), Number));
|
|
@@ -72,6 +87,12 @@ add(Input, Number) when is_list(Input) ->
|
|
|
add(Input, Number) when is_integer(Input) ->
|
|
|
Input + Number.
|
|
|
|
|
|
+%% @doc Adds slashes before quotes.
|
|
|
+addslashes(Input) when is_binary(Input) ->
|
|
|
+ addslashes(binary_to_list(Input));
|
|
|
+addslashes(Input) when is_list(Input) ->
|
|
|
+ addslashes(Input, []).
|
|
|
+
|
|
|
%% @doc Capitalizes the first character of the value.
|
|
|
capfirst([H|T]) when H >= $a andalso H =< $z ->
|
|
|
[H + $A - $a | T];
|
|
@@ -84,6 +105,12 @@ center(Input, Number) when is_binary(Input) ->
|
|
|
center(Input, Number) when is_list(Input) ->
|
|
|
string:centre(Input, Number).
|
|
|
|
|
|
+%% @doc Removes all values of arg from the given string.
|
|
|
+cut(Input, Arg) when is_binary(Input) ->
|
|
|
+ cut(binary_to_list(Input), Arg);
|
|
|
+cut(Input, [Char]) when is_list(Input) ->
|
|
|
+ cut(Input, Char, []).
|
|
|
+
|
|
|
%% @doc Formats a date according to the given format.
|
|
|
date(Input, FormatStr) when is_binary(Input) ->
|
|
|
list_to_binary(date(binary_to_list(Input), FormatStr));
|
|
@@ -95,17 +122,49 @@ date(Input, _FormatStr) when is_list(Input) ->
|
|
|
io:format("Unexpected date parameter : ~p~n", [Input]),
|
|
|
"".
|
|
|
|
|
|
+%% @doc If value evaluates to `false', use given default. Otherwise, use the value.
|
|
|
+default(Input, Default) ->
|
|
|
+ case erlydtl_runtime:is_false(Input) of
|
|
|
+ true -> Default;
|
|
|
+ false -> Input
|
|
|
+ end.
|
|
|
+
|
|
|
+%% @doc If (and only if) value is `undefined', use given default. Otherwise, use the value.
|
|
|
default_if_none(undefined, Default) ->
|
|
|
Default;
|
|
|
default_if_none(Input, _) ->
|
|
|
Input.
|
|
|
|
|
|
+%% @doc Returns `true' if the value is divisible by the argument.
|
|
|
+divisibleby(Input, Divisor) when is_binary(Input) ->
|
|
|
+ divisibleby(binary_to_list(Input), Divisor);
|
|
|
+divisibleby(Input, Divisor) when is_list(Input) ->
|
|
|
+ divisibleby(list_to_integer(Input), Divisor);
|
|
|
+divisibleby(Input, Divisor) when is_list(Divisor) ->
|
|
|
+ divisibleby(Input, list_to_integer(Divisor));
|
|
|
+divisibleby(Input, Divisor) when is_integer(Input), is_integer(Divisor) ->
|
|
|
+ Input rem Divisor =:= 0.
|
|
|
+
|
|
|
%% @doc Escapes characters for use in JavaScript strings.
|
|
|
escapejs(Input) when is_binary(Input) ->
|
|
|
escapejs(Input, 0);
|
|
|
escapejs(Input) when is_list(Input) ->
|
|
|
escapejs(Input, []).
|
|
|
|
|
|
+%% @doc Format the value like a human-readable file size.
|
|
|
+filesizeformat(Input) when is_binary(Input) ->
|
|
|
+ filesizeformat(binary_to_list(Input));
|
|
|
+filesizeformat(Input) when is_list(Input) ->
|
|
|
+ filesizeformat(list_to_integer(Input));
|
|
|
+filesizeformat(Bytes) when is_integer(Bytes), Bytes >= ?GIGABYTE->
|
|
|
+ filesizeformat(Bytes / ?GIGABYTE, "GB");
|
|
|
+filesizeformat(Bytes) when is_integer(Bytes), Bytes >= ?MEGABYTE ->
|
|
|
+ filesizeformat(Bytes / ?MEGABYTE, "MB");
|
|
|
+filesizeformat(Bytes) when is_integer(Bytes), Bytes >= ?KILOBYTE ->
|
|
|
+ filesizeformat(Bytes / ?KILOBYTE, "KB");
|
|
|
+filesizeformat(Bytes) when is_integer(Bytes) ->
|
|
|
+ integer_to_list(Bytes) ++ " bytes".
|
|
|
+
|
|
|
%% @doc Returns the first item in a list.
|
|
|
first([First|_Rest]) ->
|
|
|
[First];
|
|
@@ -138,6 +197,20 @@ format_number(Input) when is_function(Input, 0) ->
|
|
|
format_number(Input) ->
|
|
|
Input.
|
|
|
|
|
|
+%% @doc Given a whole number, returns the requested digit, where 1 is the right-most digit.
|
|
|
+get_digit(Input, Digit) when is_binary(Input) ->
|
|
|
+ get_digit(binary_to_list(Input), Digit);
|
|
|
+get_digit(Input, Digit) when is_integer(Input) ->
|
|
|
+ get_digit(integer_to_list(Input), Digit);
|
|
|
+get_digit(Input, Digit) when is_list(Digit) ->
|
|
|
+ get_digit(Input, list_to_integer(Digit));
|
|
|
+get_digit(Input, Digit) when Digit > length(Input) ->
|
|
|
+ 0;
|
|
|
+get_digit(Input, Digit) when Digit > 0 ->
|
|
|
+ lists:nth(Digit, lists:reverse(Input)) - $0;
|
|
|
+get_digit(Input, _) ->
|
|
|
+ Input.
|
|
|
+
|
|
|
%% @doc Joins a list with a given separator.
|
|
|
join(Input, Separator) when is_list(Input) ->
|
|
|
join_io(Input, Separator).
|
|
@@ -184,12 +257,36 @@ lower(Input) when is_binary(Input) ->
|
|
|
lower(Input) ->
|
|
|
string:to_lower(Input).
|
|
|
|
|
|
+%% @doc Converts a phone number (possibly containing letters) to its numerical equivalent.
|
|
|
+phone2numeric(Input) when is_binary(Input) ->
|
|
|
+ phone2numeric(binary_to_list(Input));
|
|
|
+phone2numeric(Input) when is_list(Input) ->
|
|
|
+ phone2numeric(Input, []).
|
|
|
+
|
|
|
+%% @doc Returns a random item from the given list.
|
|
|
+random(Input) when is_list(Input) ->
|
|
|
+ lists:nth(random:uniform(erlang:length(Input)), Input);
|
|
|
+random(_) ->
|
|
|
+ "".
|
|
|
+
|
|
|
%% @doc Right-aligns the value in a field of a given width.
|
|
|
rjust(Input, Number) when is_binary(Input) ->
|
|
|
list_to_binary(rjust(binary_to_list(Input), Number));
|
|
|
rjust(Input, Number) ->
|
|
|
string:right(Input, Number).
|
|
|
|
|
|
+%% @doc Converts to lowercase, removes non-word characters (alphanumerics and underscores) and converts spaces to hyphens.
|
|
|
+slugify(Input) when is_binary(Input) ->
|
|
|
+ slugify(binary_to_list(Input));
|
|
|
+slugify(Input) when is_list(Input) ->
|
|
|
+ slugify(Input, []).
|
|
|
+
|
|
|
+%% @doc Converts a string into titlecase.
|
|
|
+title(Input) when is_binary(Input) ->
|
|
|
+ title(binary_to_list(Input));
|
|
|
+title(Input) when is_list(Input) ->
|
|
|
+ title(Input, [], capnext).
|
|
|
+
|
|
|
%% @doc Truncates a string after a certain number of words.
|
|
|
truncatewords(Input, Max) when is_binary(Input) ->
|
|
|
list_to_binary(truncatewords(binary_to_list(Input), Max));
|
|
@@ -210,9 +307,29 @@ urlencode(Input) when is_binary(Input) ->
|
|
|
urlencode(Input) when is_list(Input) ->
|
|
|
urlencode(Input, []).
|
|
|
|
|
|
+%% @doc Returns the number of words.
|
|
|
+wordcount(Input) when is_binary(Input) ->
|
|
|
+ wordcount(binary_to_list(Input));
|
|
|
+wordcount(Input) when is_list(Input) ->
|
|
|
+ wordcount(Input, 0).
|
|
|
+
|
|
|
|
|
|
% internal
|
|
|
|
|
|
+addslashes([], Acc) ->
|
|
|
+ lists:reverse(Acc);
|
|
|
+addslashes([H|T], Acc) when H =:= $"; H =:= $' ->
|
|
|
+ addslashes(T, [H, $\\|Acc]);
|
|
|
+addslashes([H|T], Acc) ->
|
|
|
+ addslashes(T, [H|Acc]).
|
|
|
+
|
|
|
+cut([], _, Acc) ->
|
|
|
+ lists:reverse(Acc);
|
|
|
+cut([H|T], H, Acc) ->
|
|
|
+ cut(T, H, Acc);
|
|
|
+cut([H|T], Char, Acc) ->
|
|
|
+ cut(T, Char, [H|Acc]).
|
|
|
+
|
|
|
escape(Binary, Index) when is_binary(Binary) ->
|
|
|
case Binary of
|
|
|
<<Pre:Index/binary, $<, Post/binary>> ->
|
|
@@ -266,6 +383,9 @@ escapejs(Binary, Index) when is_binary(Binary) ->
|
|
|
Binary
|
|
|
end.
|
|
|
|
|
|
+filesizeformat(Bytes, UnitStr) ->
|
|
|
+ lists:flatten(io_lib:format("~.1f ~s", [Bytes, UnitStr])).
|
|
|
+
|
|
|
fix_ampersands(Input, Index) when is_binary(Input) ->
|
|
|
case Input of
|
|
|
<<Pre:Index/binary, $&, Post/binary>> ->
|
|
@@ -317,15 +437,69 @@ lower(Input, Index) ->
|
|
|
Input
|
|
|
end.
|
|
|
|
|
|
-truncatewords(Input, _WordsLeft, Acc) when length(Input) =:= 0 ->
|
|
|
+phone2numeric([], Acc) ->
|
|
|
+ lists:reverse(Acc);
|
|
|
+phone2numeric([H|T], Acc) when H >= $a, H =< $c; H >= $A, H =< $C ->
|
|
|
+ phone2numeric(T, [$2|Acc]);
|
|
|
+phone2numeric([H|T], Acc) when H >= $d, H =< $f; H >= $D, H =< $F ->
|
|
|
+ phone2numeric(T, [$3|Acc]);
|
|
|
+phone2numeric([H|T], Acc) when H >= $g, H =< $i; H >= $G, H =< $I ->
|
|
|
+ phone2numeric(T, [$4|Acc]);
|
|
|
+phone2numeric([H|T], Acc) when H >= $j, H =< $l; H >= $J, H =< $L ->
|
|
|
+ phone2numeric(T, [$5|Acc]);
|
|
|
+phone2numeric([H|T], Acc) when H >= $m, H =< $o; H >= $M, H =< $O ->
|
|
|
+ phone2numeric(T, [$6|Acc]);
|
|
|
+phone2numeric([H|T], Acc) when H >= $p, H =< $s; H >= $P, H =< $S ->
|
|
|
+ phone2numeric(T, [$7|Acc]);
|
|
|
+phone2numeric([H|T], Acc) when H >= $t, H =< $v; H >= $T, H =< $V ->
|
|
|
+ phone2numeric(T, [$8|Acc]);
|
|
|
+phone2numeric([H|T], Acc) when H >= $w, H =< $z; H >= $W, H =< $Z ->
|
|
|
+ phone2numeric(T, [$9|Acc]);
|
|
|
+phone2numeric([H|T], Acc) ->
|
|
|
+ phone2numeric(T, [H|Acc]).
|
|
|
+
|
|
|
+slugify([], Acc) ->
|
|
|
lists:reverse(Acc);
|
|
|
-truncatewords(_Input, WordsLeft, Acc) when WordsLeft =:= 0 ->
|
|
|
+slugify([H|T], Acc) when H >= $A, H =< $Z ->
|
|
|
+ slugify(T, [H-$A+$a|Acc]);
|
|
|
+slugify([$\ |T], Acc) ->
|
|
|
+ slugify(T, [$-|Acc]);
|
|
|
+slugify([H|T], Acc) when H >= $a, H =< $z; H >= $0, H =< $9; H =:= $_ ->
|
|
|
+ slugify(T, [H|Acc]);
|
|
|
+slugify([_|T], Acc) ->
|
|
|
+ slugify(T, Acc).
|
|
|
+
|
|
|
+title([], Acc, _) ->
|
|
|
+ lists:reverse(Acc);
|
|
|
+title([$\ = H|T], Acc, capnext) ->
|
|
|
+ title(T, [H|Acc], capnext);
|
|
|
+title([H|T], Acc, capnext) when H >= $a, H =< $z ->
|
|
|
+ title(T, [H - $a + $A|Acc], dont);
|
|
|
+title([H|T], Acc, capnext) ->
|
|
|
+ title(T, [H|Acc], dont);
|
|
|
+title([$\ = H|T], Acc, dont) ->
|
|
|
+ title(T, [H|Acc], capnext);
|
|
|
+title([H|T], Acc, dont) ->
|
|
|
+ title(T, [H|Acc], dont).
|
|
|
+
|
|
|
+truncatewords([], _WordsLeft, Acc) ->
|
|
|
+ lists:reverse(Acc);
|
|
|
+truncatewords(_Input, 0, Acc) ->
|
|
|
lists:reverse("..." ++ Acc);
|
|
|
truncatewords([C1, C2|Rest], WordsLeft, Acc) when C1 =/= $\ andalso C2 =:= $\ ->
|
|
|
truncatewords([C2|Rest], WordsLeft - 1, [C1|Acc]);
|
|
|
truncatewords([C1|Rest], WordsLeft, Acc) ->
|
|
|
truncatewords(Rest, WordsLeft, [C1|Acc]).
|
|
|
|
|
|
+wordcount([], Count) ->
|
|
|
+ Count;
|
|
|
+wordcount([C1], Count) when C1 =/= $\ ->
|
|
|
+ Count+1;
|
|
|
+wordcount([C1, C2|Rest], Count) when C1 =/= $\ andalso C2 =:= $\ ->
|
|
|
+ wordcount([C2|Rest], Count + 1);
|
|
|
+wordcount([_|Rest], Count) ->
|
|
|
+ wordcount(Rest, Count).
|
|
|
+
|
|
|
% Taken from quote_plus of mochiweb_util
|
|
|
|
|
|
urlencode(Input, Index) when is_binary(Input) ->
|