I notice that there are a few little helper functions I seem to always wind up writing given different contexts. In Erlang one of these is an inverse function for
file:consult/1, which I have to write any time I use a text file to store config data*.
write_terms(Filename, List) -> Format = fun(Term) -> io_lib:format("~tp.~n", [Term]) end, Text = unicode:characters_to_binary(lists:map(Format, List)), file:write_file(Filename, Text).
[NOTE 1: This should return the atom
'ok' — and if you want to check and assertion or crash on failure, you want to do
ok = write_terms(Filename, List) in your code.]
[NOTE 2: The Erlang runtime will need to be started with the
+pc unicode flag if you want to print UTF-8 characters in a string as characters instead of printing a list of their codepoints into a file.]
This separates each term in a list by a period in the text file, which causes
file:consult/1 to return the same list back (in order — though this detail usually does not matter because most conf files are used as proplists and are keysearched anyway).
An annoyance with most APIs is a lack of inverse functions where they could easily be written. Even if the original authors of the library don’t conceive of a use for an inverse of some particular function, whenever there is an opportunity for this leaving it out just makes an API feel incomplete (and don’t get me started on “web APIs”… ugh). This is just one case of that. Why does Erlang have a
file:consult/1 but not a
file:write_terms/2 (or “
file:deconsult/2” or whatever)? I don’t know. But this bugs me in most libs in most languages — this is the way I usually deal with this particular situation in Erlang.
binary_to_term/1 is not an acceptable solution for config data!]