Общий паттерн для работы с записями (erlang)?

Вступление: модуль получает данные в виде списка
Input = [{c,CValue},{a,AValue},{b,BValue}]

Задача — распихать данные по записи #rec, в соответствии с описанием записи. В случае, если бы в erlang работа с записями осуществлялась в рантайме, функция была бы примерно такой:

-record(rec, {a,b,c}).<br/>
<br/>
build_rec_dynamic(Input) -&gt;<br/>
 Fields = record_info(fields, rec),<br/>
 build_payload(Input, Fields, #rec{}).<br/>
<br/>
build_rec_dynamic(Input, [Field|Fields], Result) -&gt;<br/>
 case lists:keyfind(Field, 1, Input) of<br/>
 {Field, Value} -&gt;<br/>
 build_payload(Input, Fields, Result#rec{Field = Value});<br/>
 false -&gt;<br/>
 {error, {undefined_field, Field}}<br/>
 end;<br/>
<br/>
build_rec_dynamic(Input, [], Result) -&gt;<br/>
 Result.



Из-за особенностей работы с записями такой фокус, конечно, не пройдет:
field 'Field' is not an atom or _ in record rec


Есть ли какой-нибудь общий паттерн для обработки динамических данных и представления их в записи? Сразу отмечу, что данные могут приходить в неверном порядке, поэтому просто спихнуть все в кортеж не пойдет, да и вытаскивать нужно только необходимые поля.
  • Вопрос задан
  • 3358 просмотров
Пригласить эксперта
Ответы на вопрос 3
5HT
@5HT
Erlang
Вот parse transform, который превращает proplists в records и обратно.
https://github.com/5HT/n2o/blob/master/src/n2o_rest.erl
В контексте задачи применительно к JSON транформациям.
Вот пример использования:
https://github.com/synrc/n2o_sample/blob/master/src/users.erl
Вы просто пишете

-rest_record(user).

И для рекорда #user{} автоматически генерируют функции трансформации в proplists и обратно (from_json и to_json).

Если parse_transform по каким-то причинам не устраивает.
То вот в образовательных целях минимальный код (map и unmap):

hunmap([],O,_,_) -> O;
hunmap([{BK,V}|T],O,Keys,0) -> O;
hunmap([{BK,V}|T],O,Keys,L) ->
    K = wf:to_atom(BK),
    hunmap(T, setelement(
         wf_utils:indexof(K,Keys),O,wf:to_list(V)), Keys--[K],L-1).

-define(unmap(Record), unmap(P,R) -> 
                     hunmap(P,R,record_info(fields, Record),size(R)-1)).
-define(map(Record), map(O) ->
    Y = [ try N=lists:nth(1,B), if is_number(N) -> 
            wf:to_binary(B); true -> B end catch _:_ -> B end
          || B <- tl(tuple_to_list(O)) ],
    lists:zip(record_info(fields, Record), Y)).
Ответ написан
Комментировать
@Shizz Автор вопроса
Нашел костыль от Ульфа Вигера: forum.trapexit.org/viewtopic.php?p=21790#21790
Как вариант, можно использовать этот модуль.
Ответ написан
Комментировать
stolen
@stolen
gist.github.com/3793122
state_from_pl (после выкидывания хака над вторым элементом) — то, что вам нужно.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы