erlydtl_runtime.erl 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. -module(erlydtl_runtime).
  2. -compile(export_all).
  3. -define(IFCHANGED_CONTEXT_VARIABLE, erlydtl_ifchanged_context).
  4. find_value(Key, Data, _, _) ->
  5. find_value(Key, Data).
  6. find_value(_, undefined) ->
  7. undefined;
  8. find_value(Key, Fun) when is_function(Fun, 1) ->
  9. Fun(Key);
  10. find_value(Key, L) when is_atom(Key), is_list(L) ->
  11. case lists:keyfind(Key, 1, L) of
  12. false -> find_value(atom_to_list(Key), L);
  13. {Key, Value} -> Value
  14. end;
  15. find_value(Key, L) when is_list(Key), is_list(L) ->
  16. case lists:keyfind(Key, 1, L) of
  17. false -> find_value(list_to_binary(Key), L);
  18. {Key, Value} -> Value
  19. end;
  20. find_value(Key, L) when is_binary(Key), is_list(L) ->
  21. case lists:keyfind(Key, 1, L) of
  22. false -> undefined;
  23. {Key, Value} -> Value
  24. end;
  25. find_value(Key, {GBSize, GBData}) when is_integer(GBSize) ->
  26. case gb_trees:lookup(Key, {GBSize, GBData}) of
  27. {value, Val} ->
  28. Val;
  29. _ ->
  30. undefined
  31. end;
  32. find_value(Key, Tuple) when is_tuple(Tuple) ->
  33. case element(1, Tuple) of
  34. dict ->
  35. case dict:find(Key, Tuple) of
  36. {ok, Val} ->
  37. Val;
  38. _ ->
  39. undefined
  40. end;
  41. Module ->
  42. case lists:member({Key, 1}, Module:module_info(exports)) of
  43. true ->
  44. case Tuple:Key() of
  45. Val when is_tuple(Val) ->
  46. case element(1, Val) of
  47. 'Elixir.Ecto.Associations.BelongsTo' -> Val:get();
  48. 'Elixir.Ecto.Associations.HasOne' -> Val:get();
  49. _ -> Val
  50. end;
  51. Val -> Val
  52. end;
  53. _ ->
  54. undefined
  55. end
  56. end.
  57. find_deep_value([Key|Rest],Item) ->
  58. case find_value(Key,Item) of
  59. undefined -> undefined;
  60. NewItem -> find_deep_value(Rest,NewItem)
  61. end;
  62. find_deep_value([],Item) -> Item.
  63. fetch_value(Key, Data, _FileName, _Pos) ->
  64. case find_value(Key, Data) of
  65. undefined -> [];
  66. Val -> Val
  67. end.
  68. regroup(List, Attribute) ->
  69. regroup(List, Attribute, []).
  70. regroup([], _, []) ->
  71. [];
  72. regroup([], _, [[{grouper, LastGrouper}, {list, LastList}]|Acc]) ->
  73. lists:reverse([[{grouper, LastGrouper}, {list, lists:reverse(LastList)}]|Acc]);
  74. regroup([Item|Rest], Attribute, []) ->
  75. regroup(Rest, Attribute, [[{grouper, find_deep_value(Attribute, Item)}, {list, [Item]}]]);
  76. regroup([Item|Rest], Attribute, [[{grouper, PrevGrouper}, {list, PrevList}]|Acc]) ->
  77. case find_deep_value(Attribute, Item) of
  78. Value when Value =:= PrevGrouper ->
  79. regroup(Rest, Attribute, [[{grouper, PrevGrouper}, {list, [Item|PrevList]}]|Acc]);
  80. Value ->
  81. regroup(Rest, Attribute, [[{grouper, Value}, {list, [Item]}], [{grouper, PrevGrouper}, {list, lists:reverse(PrevList)}]|Acc])
  82. end.
  83. translate(_, none, Default) ->
  84. Default;
  85. translate(String, TranslationFun, Default) when is_function(TranslationFun) ->
  86. case TranslationFun(String) of
  87. undefined -> Default;
  88. <<"">> -> Default;
  89. "" -> Default;
  90. Str -> Str
  91. end.
  92. are_equal(Arg1, Arg2) when Arg1 =:= Arg2 ->
  93. true;
  94. are_equal(Arg1, Arg2) when is_binary(Arg1) ->
  95. are_equal(binary_to_list(Arg1), Arg2);
  96. are_equal(Arg1, Arg2) when is_binary(Arg2) ->
  97. are_equal(Arg1, binary_to_list(Arg2));
  98. are_equal(Arg1, Arg2) when is_integer(Arg1) ->
  99. are_equal(integer_to_list(Arg1), Arg2);
  100. are_equal(Arg1, Arg2) when is_integer(Arg2) ->
  101. are_equal(Arg1, integer_to_list(Arg2));
  102. are_equal(Arg1, Arg2) when is_atom(Arg1), is_list(Arg2) ->
  103. are_equal(atom_to_list(Arg1), Arg2);
  104. are_equal(Arg1, Arg2) when is_list(Arg1), is_atom(Arg2) ->
  105. are_equal(Arg1, atom_to_list(Arg2));
  106. are_equal(_, _) ->
  107. false.
  108. is_false("") ->
  109. true;
  110. is_false(false) ->
  111. true;
  112. is_false(undefined) ->
  113. true;
  114. is_false("0") ->
  115. true;
  116. is_false(<<"0">>) ->
  117. true;
  118. is_false(<<>>) ->
  119. true;
  120. is_false(_) ->
  121. false.
  122. is_true(V) ->
  123. not is_false(V).
  124. 'in'(Sublist, [Sublist|_]) ->
  125. true;
  126. 'in'(Sublist, List) when is_atom(List) ->
  127. 'in'(Sublist, atom_to_list(List));
  128. 'in'(Sublist, List) when is_binary(Sublist) ->
  129. 'in'(binary_to_list(Sublist), List);
  130. 'in'(Sublist, List) when is_binary(List) ->
  131. 'in'(Sublist, binary_to_list(List));
  132. 'in'(Sublist, [C|Rest]) when is_list(Sublist) andalso is_binary(C) ->
  133. 'in'(Sublist, [binary_to_list(C)|Rest]);
  134. 'in'(Sublist, [C|Rest]) when is_list(Sublist) andalso is_list(C) ->
  135. 'in'(Sublist, Rest);
  136. 'in'(Sublist, List) when is_list(Sublist) andalso is_list(List) ->
  137. string:str(List, Sublist) > 0;
  138. 'in'(Element, List) when is_list(List) ->
  139. lists:member(Element, List);
  140. 'in'(_, _) ->
  141. false.
  142. 'not'(Value) ->
  143. not is_true(Value).
  144. 'or'(Value1, Value2) ->
  145. is_true(Value1) or is_true(Value2).
  146. 'and'(Value1, Value2) ->
  147. is_true(Value1) and is_true(Value2).
  148. 'eq'(Value1, Value2) ->
  149. are_equal(Value1, Value2).
  150. 'ne'(Value1, Value2) ->
  151. not are_equal(Value1, Value2).
  152. 'le'(Value1, Value2) ->
  153. not 'gt'(Value1, Value2).
  154. 'ge'(Value1, Value2) ->
  155. not 'lt'(Value1, Value2).
  156. 'gt'(Value1, Value2) when is_list(Value1) ->
  157. 'gt'(list_to_integer(Value1), Value2);
  158. 'gt'(Value1, Value2) when is_list(Value2) ->
  159. 'gt'(Value1, list_to_integer(Value2));
  160. 'gt'(Value1, Value2) when Value1 > Value2 ->
  161. true;
  162. 'gt'(_, _) ->
  163. false.
  164. 'lt'(Value1, Value2) when is_list(Value1) ->
  165. 'lt'(list_to_integer(Value1), Value2);
  166. 'lt'(Value1, Value2) when is_list(Value2) ->
  167. 'lt'(Value1, list_to_integer(Value2));
  168. 'lt'(Value1, Value2) when Value1 < Value2 ->
  169. true;
  170. 'lt'(_, _) ->
  171. false.
  172. stringify_final(In, BinaryStrings) ->
  173. stringify_final(In, [], BinaryStrings).
  174. stringify_final([], Out, _) ->
  175. lists:reverse(Out);
  176. stringify_final([El | Rest], Out, false = BinaryStrings) when is_atom(El) ->
  177. stringify_final(Rest, [atom_to_list(El) | Out], BinaryStrings);
  178. stringify_final([El | Rest], Out, true = BinaryStrings) when is_atom(El) ->
  179. stringify_final(Rest, [atom_to_binary(El, latin1) | Out], BinaryStrings);
  180. stringify_final([El | Rest], Out, BinaryStrings) when is_list(El) ->
  181. stringify_final(Rest, [stringify_final(El, BinaryStrings) | Out], BinaryStrings);
  182. stringify_final([El | Rest], Out, false = BinaryStrings) when is_tuple(El) ->
  183. stringify_final(Rest, [io_lib:print(El) | Out], BinaryStrings);
  184. stringify_final([El | Rest], Out, true = BinaryStrings) when is_tuple(El) ->
  185. stringify_final(Rest, [list_to_binary(io_lib:print(El)) | Out], BinaryStrings);
  186. stringify_final([El | Rest], Out, BinaryStrings) ->
  187. stringify_final(Rest, [El | Out], BinaryStrings).
  188. to_list(Value, true) ->
  189. lists:reverse(to_list(Value, false));
  190. to_list(Value, false) when is_list(Value) ->
  191. Value;
  192. to_list(Value, false) when is_tuple(Value) ->
  193. case element(1, Value) of
  194. 'Elixir.Ecto.Associations.HasMany' ->
  195. Value:to_list();
  196. _ ->
  197. tuple_to_list(Value)
  198. end.
  199. init_counter_stats(List) ->
  200. init_counter_stats(List, undefined).
  201. init_counter_stats(List, Parent) when is_list(List) ->
  202. [{counter, 1},
  203. {counter0, 0},
  204. {revcounter, length(List)},
  205. {revcounter0, length(List) - 1},
  206. {first, true},
  207. {last, length(List) =:= 1},
  208. {parentloop, Parent}].
  209. increment_counter_stats([{counter, Counter}, {counter0, Counter0}, {revcounter, RevCounter},
  210. {revcounter0, RevCounter0}, {first, _}, {last, _}, {parentloop, Parent}]) ->
  211. [{counter, Counter + 1},
  212. {counter0, Counter0 + 1},
  213. {revcounter, RevCounter - 1},
  214. {revcounter0, RevCounter0 - 1},
  215. {first, false}, {last, RevCounter0 =:= 1},
  216. {parentloop, Parent}].
  217. forloop(Fun, Acc0, Values) ->
  218. push_ifchanged_context(),
  219. Result = lists:mapfoldl(Fun, Acc0, Values),
  220. pop_ifchanged_context(),
  221. Result.
  222. push_ifchanged_context() ->
  223. IfChangedContextStack = case get(?IFCHANGED_CONTEXT_VARIABLE) of
  224. undefined -> [];
  225. Stack -> Stack
  226. end,
  227. put(?IFCHANGED_CONTEXT_VARIABLE, [[]|IfChangedContextStack]).
  228. pop_ifchanged_context() ->
  229. [_|Rest] = get(?IFCHANGED_CONTEXT_VARIABLE),
  230. put(?IFCHANGED_CONTEXT_VARIABLE, Rest).
  231. ifchanged(Expressions) ->
  232. [IfChangedContext|Rest] = get(?IFCHANGED_CONTEXT_VARIABLE),
  233. {Result, NewContext} = lists:foldl(fun (Expr, {ProvResult, Context}) when ProvResult == true ->
  234. {_, NContext} = ifchanged2(Expr, Context),
  235. {true, NContext};
  236. (Expr, {_ProvResult, Context}) ->
  237. ifchanged2(Expr, Context)
  238. end, {false, IfChangedContext}, Expressions),
  239. put(?IFCHANGED_CONTEXT_VARIABLE, [NewContext|Rest]),
  240. Result.
  241. ifchanged2({Key, Value}, IfChangedContext) ->
  242. PreviousValue = proplists:get_value(Key, IfChangedContext),
  243. if
  244. PreviousValue =:= Value ->
  245. {false, IfChangedContext};
  246. true ->
  247. NewContext = [{Key, Value}|proplists:delete(Key, IfChangedContext)],
  248. {true, NewContext}
  249. end.
  250. cycle(NamesTuple, Counters) when is_tuple(NamesTuple) ->
  251. element(find_value(counter0, Counters) rem size(NamesTuple) + 1, NamesTuple).
  252. widthratio(Numerator, Denominator, Scale) ->
  253. round(Numerator / Denominator * Scale).
  254. spaceless(Contents) ->
  255. Contents1 = lists:flatten(Contents),
  256. Contents2 = re:replace(Contents1, "^\\s+<", "<", [{return,list}]),
  257. Contents3 = re:replace(Contents2, ">\\s+$", ">", [{return,list}]),
  258. Contents4 = re:replace(Contents3, ">\\s+<", "><", [global, {return,list}]),
  259. Contents4.
  260. read_file(Module, Function, DocRoot, FileName) ->
  261. AbsName = case filename:absname(FileName) of
  262. FileName -> FileName;
  263. _ -> filename:join([DocRoot, FileName])
  264. end,
  265. {ok, Binary} = Module:Function(AbsName),
  266. binary_to_list(Binary).