PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/ce/src/ce_lib.erl

http://github.com/gebi/jungerl
Erlang | 219 lines | 100 code | 33 blank | 86 comment | 0 complexity | b9bf2d3396b7ecfc05711cbeee344c86 MD5 | raw file
Possible License(s): AGPL-1.0, JSON, LGPL-2.1, BSD-3-Clause
  1. %%% BEGIN ce_lib.erl %%%
  2. %%%
  3. %%% ce - Miscellaneous Programming Support Libraries for Erlang/OTP
  4. %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
  5. %%%
  6. %%% Redistribution and use in source and binary forms, with or without
  7. %%% modification, are permitted provided that the following conditions
  8. %%% are met:
  9. %%%
  10. %%% Redistributions of source code must retain the above copyright
  11. %%% notice, this list of conditions and the following disclaimer.
  12. %%%
  13. %%% Redistributions in binary form must reproduce the above copyright
  14. %%% notice, this list of conditions and the following disclaimer in
  15. %%% the documentation and/or other materials provided with the
  16. %%% distribution.
  17. %%%
  18. %%% Neither the name of Cat's Eye Technologies nor the names of its
  19. %%% contributors may be used to endorse or promote products derived
  20. %%% from this software without specific prior written permission.
  21. %%%
  22. %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  23. %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
  24. %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  25. %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26. %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
  27. %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  28. %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  29. %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  30. %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  31. %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  32. %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33. %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  34. %%% POSSIBILITY OF SUCH DAMAGE.
  35. %% @doc Miscellaneous spiffy stuff library.
  36. %%
  37. %% @end
  38. -module(ce_lib).
  39. -vsn('JUNGERL').
  40. -author('catseye@catseye.mb.ca').
  41. -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
  42. -export([iterate/4, repeat/2]).
  43. -export([breed/1]).
  44. -export([eval/1]).
  45. -export([call_stack/0]).
  46. -export([clean/2, place/2]).
  47. -export([attempt/2, attempt/3]).
  48. -export([compose/1]).
  49. -export([to_integer/2, to_float/2, to_string/1, to_string/2]).
  50. %% @spec iterate(integer(), integer(), fun(), term()) -> term()
  51. %% @doc Implements iteration with a counter variable.
  52. %% Not dissimilar to 'for loops' in other languages.
  53. iterate(I, Q, Fun, Acc) when Q < I -> Acc;
  54. iterate(I, N, Fun, Acc) ->
  55. Acc0 = Fun(I, Acc),
  56. iterate(I+1, N, Fun, Acc0).
  57. %% @spec repeat(integer(), fun()) -> [term()]
  58. %% @doc Implements opaque finite repetition.
  59. %% Not dissimilar to the 'repeat' loop in LOGO.
  60. %% This version is tail-recursive and returns a list of all
  61. %% evaluated results.
  62. repeat(N, F) when integer(N) -> lists:reverse(repeat(N, F, [])).
  63. repeat(0, F, A) -> A;
  64. repeat(N, F, A) -> repeat(N - 1, F, [F() | A]).
  65. %% @spec breed(term()) -> term()
  66. %% @doc Returns a copy of a deep aggregate of data
  67. %% with each Fun/0 object contained within replaced by
  68. %% the result of running it.
  69. breed([H|T]) -> [breed(H) | breed(T)];
  70. breed(F) when function(F) -> apply(F, []);
  71. breed(T) when tuple(T) -> breed_tuple(T, size(T));
  72. breed(Q) -> Q.
  73. breed_tuple(T, 0) -> {};
  74. breed_tuple(T, N) ->
  75. erlang:append_element(breed_tuple(T, N-1), breed(element(N, T))).
  76. %% @spec eval(string()) -> term()
  77. %% @doc Evaluates a string as an Erlang expression.
  78. %% This adds reflectivity to Erlang with a simple, Perl-like
  79. %% interface.
  80. eval(S) -> eval(S, []).
  81. eval(S, PT) when list(S) ->
  82. {ok, T, _} = erl_scan:string(S),
  83. {ok, C} = erl_parse:parse_exprs(T),
  84. % execute all parse transforms in PT
  85. {value, Y, _} = erl_eval:exprs(C, erl_eval:bindings(erl_eval:new_bindings())),
  86. Y.
  87. %% @spec call_stack() -> [{Module, Function, Arity}]
  88. %% @doc Returns the current Erlang call stack (not including
  89. %% <code>ce_lib:call_stack/0</code>).
  90. call_stack() ->
  91. {'EXIT', {Error, CallStack}} = (catch 1 = 2),
  92. tl(CallStack).
  93. %% @spec place(term(), term()) -> ok
  94. %% @doc Places the given value in the process dictionary iff the given key
  95. %% does not yet exist. Exclusive use of place/2 instead of erlang:put/2
  96. %% imposes the restriction of single-assignment on the process dictionary.
  97. place(Key, Value) ->
  98. case erlang:get(Key, Value) of
  99. undefined ->
  100. put(Key, Value),
  101. ok;
  102. _ ->
  103. throw({error, already_set})
  104. end.
  105. %% @spec clean(fun(), [{key(), value()}]) -> term()
  106. %% @doc Evaluate a given Fun with a new, temporary process dictionary.
  107. %% The new process dictionary will contain only the values given to clean/2,
  108. %% and will be reset to the old process dictionary after the Fun has been
  109. %% evaluated. Simulates local variables with dynamic scope as found in
  110. %% many non-single-assignment languages.
  111. clean(F, L) ->
  112. ProcessDictionary = erase(),
  113. lists:foreach(fun({K,V}) -> put(K,V) end, L),
  114. Result = F(),
  115. erase(),
  116. lists:foreach(fun({K,V}) -> put(K,V) end, ProcessDictionary),
  117. Result.
  118. %% @spec attempt(function(), [term()]) -> {ok, term()} | {error, term()}
  119. %% @doc Catches errors from an error-throwing function.
  120. %% Thanks to Thomas Arts for this code.
  121. attempt(F, Args) ->
  122. case catch apply(F, Args) of
  123. {'EXIT', Why} -> {error, Why};
  124. Other -> {ok, Other}
  125. end.
  126. %% @spec attempt(function(), [term()], term()) -> term()
  127. %% @doc Catches errors and returns a default value if error thrown.
  128. %% Also can be used with functions which return {ok, Result} | {error, Why}.
  129. attempt(F, Args, Default) ->
  130. case catch apply(F, Args) of
  131. {'EXIT', _} -> Default;
  132. {error, _} -> Default;
  133. {ok, Value} -> Value;
  134. Other -> Other
  135. end.
  136. %% @spec compose([function()]) -> function()
  137. %% @doc Composes a function by chaining the results of a list of functions.
  138. %% Thanks to Alex Peake for this code.
  139. compose([Fn]) -> Fn;
  140. compose([Fn | FnTail]) ->
  141. fun(Args) ->
  142. apply(Fn, [apply(compose(FnTail), [Args])])
  143. end.
  144. %% @spec to_integer(term(), integer()) -> integer()
  145. %% @doc Tries to convert any term into an integer, using default value if it
  146. %% cannot be done.
  147. to_integer(F, D) when is_float(F) ->
  148. trunc(F + 0.5);
  149. to_integer(I, D) when is_integer(I) ->
  150. I;
  151. to_integer(S, D) when is_list(S) ->
  152. case catch list_to_integer(S) of
  153. F when integer(F) -> F;
  154. {'EXIT', Reason} -> D
  155. end;
  156. to_integer(X, D) -> D.
  157. %% @spec to_float(term(), float()) -> float()
  158. %% @doc Tries to convert any term into a float, using default value if it
  159. %% cannot be done.
  160. to_float(F, D) when is_float(F) ->
  161. F;
  162. to_float(I, D) when is_integer(I) ->
  163. I * 1.0;
  164. to_float(S, D) when is_list(S) ->
  165. case catch list_to_float(S) of
  166. F when number(F) -> F;
  167. {'EXIT', Reason} ->
  168. case catch list_to_integer(S) of
  169. G when integer(G) -> G * 1.0;
  170. {'EXIT', Reason0} -> D
  171. end
  172. end;
  173. to_float(X, D) -> D.
  174. to_string(X) -> to_string(X, "").
  175. %% @spec to_string(term(), string()) -> string()
  176. %% @doc Tries to convert any term into a string, using default value if it
  177. %% cannot be done.
  178. to_string(F, D) when is_float(F) ->
  179. float_to_list(F);
  180. to_string(I, D) when is_integer(I) ->
  181. integer_to_list(I);
  182. to_string(A, D) when is_atom(A) ->
  183. atom_to_list(A);
  184. to_string(S, D) when is_list(S) -> S;
  185. to_string(X, D) -> io_lib:format("~w", [X]).
  186. %%% END of ce_lib.erl %%%