Justin
Justin

Reputation: 4853

Converting records to proplists (and back)

I have a Erlang webapp, based on Mochiweb and Mnesia, which consumes and emits JSON. It makes sense to store records in Mnesia; however Mochiweb/Mochijson require data in proplist format. So I end up with a large amount of boilerplate code:

-record(foobar, {name, value}).

record_to_proplist(Record)->  
  [{name, Record#foobar.name},  
   {value, Record#foobar.value}].  

proplist_to_record(Props)->  
  #foobar{name=proplists:get_value("name", Props),  
          value=proplists:get_value("value", Props)}.  

Fine with a single small record, a pain with lots of large records. Can anyone suggest a way round all this boilerplate code ? I guess I need some way of inspecting a record's fields dynamically; and since records are a compile-time construct, I'm guessing [assuming it's possible] this means injecting code via a macro ..

Thanks!

Upvotes: 10

Views: 7891

Answers (4)

chops
chops

Reputation: 2612

The link in the accepted answer for this has been long dead.

The short answer is to use exprecs from Ulf Wiger.

exprecs is a parse_transform in uwiger/parse_trans

The article on how this works is archived in the web archive at: http://web.archive.org/web/20130729014934/http://forum.trapexit.org/viewtopic.php?p=21790

Upvotes: 0

Roberto Aloi
Roberto Aloi

Reputation: 31015

It sounds like exprecs is what you're looking for:

http://forum.trapexit.org/viewtopic.php?p=21790

Reading from the description:

The module is a parse transform allowing you to export records. The transform adds accessor functions for instantiating, inspecting and modifying records, without having to introduce compile-time dependencies between modules.

See if this helps.

Upvotes: 2

Daniel Luna
Daniel Luna

Reputation: 1979

You should be able to do something like:

-record(foobar, {name, value}).
-record(foo, {other, fields, 'and', stuff}).

record_to_proplist(#foobar{} = Rec) ->
  lists:zip(record_info(fields, foobar), tl(tuple_to_list(Rec)));
record_to_proplist(#foo{} = Rec) ->
  lists:zip(record_info(fields, foo), tl(tuple_to_list(Rec))).

Etc.

(Or as a macro (still creating a function though, the version where the macro is ?R2P(Rec, foobar) is just too ugly):

-define(R2P(Record), record_to_proplist(#Record{} = Rec) ->
           lists:zip(record_info(fields, Record), tl(tuple_to_list(Rec)))).

?R2P(foobar);
?R2P(foo).

)

Upvotes: 24

Lukas
Lukas

Reputation: 5327

Using record_info(fields, foobar) it is possible to do something dynamically. record_info however is also a compile time construct so the record name cannot be a variable, so you need one clause for each record you intend to convert.

Upvotes: 2

Related Questions