PageRenderTime 73ms CodeModel.GetById 14ms app.highlight 53ms RepoModel.GetById 2ms app.codeStats 0ms

/src/support/z_convert.erl

https://code.google.com/p/zotonic/
Erlang | 304 lines | 225 code | 38 blank | 41 comment | 3 complexity | fa1c47de29c572e45a97641895750a1e MD5 | raw file
  1%% @author Rusty Klophaus
  2%% @copyright Copyright (c) 2008-2009 Rusty Klophaus, Copyright (c) 2009 Marc Worrell
  3%%
  4%% @doc Conversion functions for all kinds of data types. Changes to
  5%% Rusty's version: added date conversion, undefined handling and more
  6%% to_bool cases.
  7
  8%% Copyright 2009 Marc Worrell
  9%%
 10%% Licensed under the Apache License, Version 2.0 (the "License");
 11%% you may not use this file except in compliance with the License.
 12%% You may obtain a copy of the License at
 13%% 
 14%%     http://www.apache.org/licenses/LICENSE-2.0
 15%% 
 16%% Unless required by applicable law or agreed to in writing, software
 17%% distributed under the License is distributed on an "AS IS" BASIS,
 18%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 19%% See the License for the specific language governing permissions and
 20%% limitations under the License.
 21
 22-module(z_convert).
 23-author("Rusty Klophaus").
 24-author("Marc Worrell <marc@worrell.nl>").
 25-author("Arjan Scherpenisse <arjan@scherpenisse.net>").
 26
 27
 28-export ([
 29	clean_lower/1,
 30	to_list/1,
 31	to_flatlist/1,
 32	to_atom/1, 
 33	to_binary/1, 
 34	to_integer/1,
 35	to_float/1,
 36	to_bool_strict/1,
 37	to_bool/1,
 38	to_utc/1,
 39	to_localtime/1,
 40	to_datetime/1,
 41    to_date/1,
 42    to_time/1,
 43    to_isotime/1,
 44    to_json/1,
 45    
 46    ip_to_list/1
 47]).
 48
 49
 50-include("zotonic.hrl").
 51
 52
 53%%% CONVERSION %%%
 54
 55clean_lower(L) -> string:strip(z_string:to_lower(to_list(L))).
 56
 57to_list(undefined) -> [];
 58to_list(<<>>) -> [];
 59to_list({rsc_list, L}) -> L;
 60to_list(L) when is_list(L) -> lists:flatten(L);
 61to_list(A) when is_atom(A) -> atom_to_list(A);
 62to_list(B) when is_binary(B) -> binary_to_list(B);
 63to_list(I) when is_integer(I) -> integer_to_list(I);
 64to_list(F) when is_float(F) -> float_to_list(F).
 65
 66to_flatlist(L) when is_list(L) ->
 67	case z_string:is_string(L) of
 68		true -> L;
 69		false -> to_list(iolist_to_binary(L))
 70	end;
 71to_flatlist(L) ->
 72	to_list(L).
 73
 74
 75to_atom(<<>>) -> undefined;
 76to_atom([]) -> undefined;
 77to_atom(A) when is_atom(A) -> A;
 78to_atom(B) when is_binary(B) -> to_atom(binary_to_list(B));
 79to_atom(I) when is_integer(I) -> to_atom(integer_to_list(I));
 80to_atom(L) when is_list(L) -> list_to_atom(binary_to_list(list_to_binary(L))).
 81
 82to_binary(undefined) -> <<>>;
 83to_binary(A) when is_atom(A) -> to_binary(atom_to_list(A));
 84to_binary(B) when is_binary(B) -> B;
 85to_binary(I) when is_integer(I) -> to_binary(integer_to_list(I));
 86to_binary(F) when is_float(F) -> to_binary(float_to_list(F));
 87to_binary(L) when is_list(L) -> list_to_binary(L).
 88
 89to_integer(undefined) -> undefined;
 90to_integer([]) -> undefined;
 91to_integer(A) when is_atom(A) -> to_integer(atom_to_list(A));
 92to_integer(B) when is_binary(B) -> to_integer(binary_to_list(B));
 93to_integer(I) when is_integer(I) -> I;
 94to_integer(F) when is_float(F) -> erlang:round(F);
 95to_integer([C]) when is_integer(C) andalso (C > $9 orelse C < $0) -> C;
 96to_integer(L) when is_list(L) -> list_to_integer(L).
 97
 98to_float(undefined) -> undefined;
 99to_float([]) -> undefined;
100to_float(A) when is_atom(A) -> to_float(atom_to_list(A));
101to_float(B) when is_binary(B) -> to_float(binary_to_list(B));
102to_float(I) when is_integer(I) -> I + 0.0;
103to_float(F) when is_float(F) -> F;
104to_float(L) when is_list(L) -> 
105    case lists:member($., L) of
106        true -> list_to_float(L);
107        false -> list_to_float(L++".0")  %% list_to_float("1") gives a badarg
108    end.
109
110
111%% @doc Quite loose conversion of values to boolean
112to_bool("false") -> false;
113to_bool("FALSE") -> false;
114to_bool("n") -> false;
115to_bool("N") -> false;
116to_bool("NO") -> false;
117to_bool(<<"false">>) -> false;
118to_bool(<<"FALSE">>) -> false;
119to_bool(<<"n">>) -> false;
120to_bool(<<"N">>) -> false;
121to_bool(<<"NO">>) -> false;
122to_bool("disabled") -> false;
123to_bool(<<"disabled">>) -> false;
124to_bool("DISABLED") -> false;
125to_bool(<<"DISABLED">>) -> false;
126to_bool([0]) -> false;
127to_bool(V) -> to_bool_strict(V).
128
129% @doc Convert values to boolean values according to the Django rules
130to_bool_strict(undefined) -> false;
131to_bool_strict(false) -> false;
132to_bool_strict(0) -> false;
133to_bool_strict(0.0) -> false;
134to_bool_strict(<<>>) -> false;
135to_bool_strict(<<0>>) -> false;
136to_bool_strict([]) -> false;
137to_bool_strict({rsc_list, []}) -> false;
138to_bool_strict(#m{value=V}) -> to_bool(V);
139to_bool_strict(#m_search_result{result=V}) -> to_bool(V);
140to_bool_strict(#search_result{result=[]}) -> false;
141to_bool_strict("0") -> false;
142to_bool_strict(<<"0">>) -> false;
143to_bool_strict(_) -> true.
144
145
146%% @doc Convert a local date time to utc
147to_utc(undefined) ->
148    undefined;
149to_utc({{9999,_,_}, _}) ->
150    ?ST_JUTTEMIS;
151to_utc(D) ->
152    case catch calendar:local_time_to_universal_time_dst(D) of
153        [] -> D;    % This time never existed in the local time, just take it as-is
154        [UTC] -> UTC;
155        [DstUTC, _UTC] -> DstUTC;
156        {'EXIT', _} -> D
157    end.
158
159
160%% @doc Convert a utc date time to local
161to_localtime(undefined) ->
162    undefined;
163to_localtime({{9999,_,_},_}) ->
164    ?ST_JUTTEMIS;
165to_localtime(D) ->
166    case catch calendar:universal_time_to_local_time(D) of
167        {'EXIT', _} -> D;
168        LocalD -> LocalD
169    end.
170
171%% @doc Convert an input to a datetime, using to_date/1 and to_time/1.
172to_datetime({{_,_,_},{_,_,_}} = DT) -> DT;
173to_datetime({_,_,_} = D) -> {D, {0,0,0}};
174to_datetime(L) when is_list(L) ->
175	try
176		case string:tokens(L, " T") of
177			[Date,Time] ->
178                WithTZ = fun(Tm, Tz, Mul) ->
179                                 TZTime = to_time(Tz),
180                                 Add = calendar:datetime_to_gregorian_seconds({{0,1,1},TZTime}),
181                                 Secs = calendar:datetime_to_gregorian_seconds({to_date(Date), to_time(Tm)}),
182                                 calendar:universal_time_to_local_time(calendar:gregorian_seconds_to_datetime(Secs+(Mul*Add)))
183                         end,
184                case string:tokens(Time, "+") of
185                    [Time1, TZ] ->
186                        %% Timestamp with positive time zone
187                        WithTZ(Time1, TZ, -1);
188                    _ ->
189                        case string:tokens(Time, "-") of
190                            [Time1, TZ] ->
191                                %% Timestamp with negative time zone
192                                WithTZ(Time1, TZ, 1);
193                            _ ->
194                                case lists:reverse(Time) of
195                                    [$Z|Rest] ->
196                                        %% Timestamp ending on Z (= UTC)
197                                        calendar:universal_time_to_local_time({to_date(Date), to_time(lists:reverse(Rest))});
198                                    _ ->
199                                        %% Timestamp without time zone
200                                        {to_date(Date), to_time(Time)}
201                                end
202                        end
203                end;
204			[Date] ->
205                {to_date(Date), {0,0,0}}
206        end
207	catch
208		_:_ -> undefined
209	end;
210to_datetime(undefined) ->
211	undefined.
212
213%% @doc Convert an input to a date.
214to_date({_,_,_} = D) -> D;
215to_date(L) when is_list(L) ->
216    case string:tokens(L, "-/") of
217        [D,M,Y] when length(Y) =:= 4 ->
218            {to_integer(Y),to_integer(M),to_integer(D)};
219        [Y,M,D] ->
220            {to_integer(Y),to_integer(M),to_integer(D)}
221    end.
222
223%% @doc Convert an input to a time.
224to_time({_,_,_} = D) -> D;
225to_time(L) when is_list(L) ->
226    [H,I,S|_] = lists:flatten([[to_integer(X) ||X <-  string:tokens(L, ":.")], 0, 0]),
227    {H,I,S}.
228
229%% @doc Convert a datetime (in local time) to an ISO time string (in universal time).
230%% @spec to_isotime(DateTime) -> string()
231to_isotime(DateTime) ->
232    z_convert:to_list(erlydtl_dateformat:format(hd(calendar:local_time_to_universal_time_dst(DateTime)), "Y-m-d\\TH:i:s\\Z", #context{})).
233
234
235%%
236%% @doc Convert an Erlang structure to a format that can be serialized by mochijson.
237%%
238
239%% Simple values
240to_json(undefined) ->
241    null;
242to_json(X) when is_atom(X) ->
243    X;
244to_json(X) when is_integer(X) ->
245    X;
246to_json(X) when is_binary(X) ->
247    X;
248
249%% Tuple values
250to_json({{Y,M,D},{H,I,S}} = DateTime)
251    when is_integer(Y), is_integer(M), is_integer(D),
252         is_integer(H), is_integer(I), is_integer(S) ->
253    erlydtl_dateformat:format(DateTime, "Y-m-d H:i:s", en);
254to_json({array, X}) ->
255    %% Explicit request for array (to prevent string conversion for some lists)
256    {array, [to_json(V) || V <- X]};
257to_json({X, Y}) ->
258    {struct, to_json_struct([{X, Y}])};
259to_json(X) when is_tuple(X) ->
260    {array, [to_json(V) || V <- tuple_to_list(X)]};
261
262%% List values
263to_json([{X, Y}]) when is_atom(X) ->
264    {struct, to_json_struct([{X, Y}])};
265to_json([{X, Y} | Z]) when is_atom(X) ->
266    {struct, to_json_struct([{X, Y} | Z])};
267to_json(X) when is_list(X) ->
268    case z_string:is_string(X) of
269        true ->
270            X;
271        false ->
272            {array, [to_json(V) || V <- X]}
273    end.
274
275%% Handle structs specially
276to_json_struct([]) ->
277    [];
278to_json_struct([{X,Y}|T]) ->
279    [{to_json_struct_key(X), to_json(Y)} | to_json_struct(T)].
280to_json_struct_key(X) when is_atom(X) orelse is_integer(X) orelse is_binary(X) ->
281    X;
282to_json_struct_key(X) when is_list(X) ->
283    case z_string:is_string(X) of
284        true ->
285            X;
286        false ->
287            invalid_key
288    end;
289to_json_struct_key(_) ->
290    invalid_key.
291    
292
293
294ip_to_list({IP,Port}) when is_tuple(IP), is_integer(Port) ->
295    ip_to_list(IP);
296ip_to_list({N1,N2,N3,N4} ) ->
297    lists:flatten([integer_to_list(N1), $., integer_to_list(N2), $., integer_to_list(N3), $., integer_to_list(N4)]);
298ip_to_list({_K1,_K2,_K3,_K4,_K5,_K6,_K7,_K8} = IPv6) ->
299    L = lists:map(fun(0) -> "";
300                     (N) -> io_lib:format("~.16b", [N])
301                  end,
302                  tuple_to_list(IPv6)),
303    lists:flatten(string:join(L, ":")).
304