erlydtl_runtime.erl 9.2 KB

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