📜 ⬆️ ⬇️

JSON serialization library for Erlang

Since we are very actively using opensource solutions in our activities, the reverse process is also quite natural - publishing under free licenses of libraries and components created in our company.

This time we publish the serialization library in Erlang JSON data types, authored by si14 under the BSD 2-clause license. Those projects for which this library was written are not yet ready (wait for announcements for the fall), but the library has already become completely independent and can be used in many other cases. Traditionally, we look forward to cooperation in improvement, with interest we will hear about the use in other projects.

In the wilds of Erlang

Unlike many dynamic languages, Erlang has optional type annotations for functions and records. At the moment, they are used by at least 3 utilities: edoc (generates documentation from source; an example of the resulting documentation can be seen, for example, here ), more importantly, dialyzer (analyzes existing information about types and reports type mismatch errors, including discrepancies and the derived types) and PropEr (a system for automatically generating tests based on information about the types and declaratively defined properties of functions). The use of these declarations has become the rule of good taste, so almost all quality projects at Erlang have them. Is it possible to use type information anywhere else?
')

Jane

In the process of developing one of the projects, an idea arose: why not use existing type information directly in JS (for example, to draw forms or validate data)? A survey survey of familiar developers confirmed that the idea is “hanging in the air”, but there is no standard solution. Then JANE appeared: an attempt to describe the standard for coding information about record using JSON, with which it is quite convenient to work from JS. JANE is especially well combined with BERT , allowing you to work almost transparently in JS with Erlang's terms.

Format and current implementation

The current format implementation is an executable escript that accepts paths to .hrl files with record descriptions and writes the resulting .json files to the priv / records folder. Each definition of a record in the file is encoded as an element of the top-level dictionary with a key equal to the name of the record and a dictionary describing the given record as a value.
The description of a specific record is a dictionary with the name of the field as a key and the description of this field as a value.
The field description is a dictionary with the required type key, containing the type specification, and the optional default key, specified if the default record is specified in the record specification for the field.
A type specification is a dictionary with a key equal to the type name and a value equal to the type argument list (which may also contain type specifications).
By default, all types of fields in a record are defined as a union of their specified type and atom undefined. This is not always convenient, so the current implementation takes the ignore_undefined parameter, ignoring if it is undefined.
An example of using a rebar hook as a post-compile:
{post_hooks, [{'compile', './priv/recordparser ignore_undefined include/test.hrl'}]}. 

Examples

Definition of record:
 -record(params_ping, {host :: nonempty_string()}). -record(params_tcp, {host :: list(atom()), port = 80 :: pos_integer(), timeout :: pos_integer()}). 

The result of the broadcast in .json (with ignore_undefined):
 { "params_ping": { "host": { "type": { "nonempty_string": [] } } }, "params_tcp": { "host": { "type": { "list": [ { "atom": [] } ] } }, "port": { "type": { "pos_integer": [] }, "default": 80 }, "timeout": { "type": { "pos_integer": [] } } } } 

The same, but without ignore_undefined:
 { "params_ping": { "host": { "type": { "union": [ { "atom": [ "undefined" ] }, { "nonempty_string": [] } ] } } }, "params_tcp": { "host": { "type": { "union": [ { "atom": [ "undefined" ] }, { "nonempty_string": [] } ] } }, "port": { "type": { "pos_integer": [] }, "default": 80 }, "timeout": { "type": { "union": [ { "atom": [ "undefined" ] }, { "pos_integer": [] } ] } } } } 


Links and people

Library code in our repository on Github: github.com/selectel/jane
Library author: si14 .
Traditionally, thanks akme for agreeing to a BSD-license.

Source: https://habr.com/ru/post/123979/


All Articles