JSV.Helpers.Traverse (jsv v0.13.1)
View SourceHelpers to work with nested generic data structures.
Summary
Functions
Updates a data structure in depth-first, post-order traversal.
Updates a JSON-compatible data structure in depth-first, post-order traversal while carrying an accumulator.
Updates a data structure in depth-first, pre-order traversal.
Updates a JSON-compatible data structure in depth-first, pre-order traversal while carrying an accumulator.
Types
Functions
@spec postwalk(data, (postwalk_item() -> data)) :: data when data: term()
Updates a data structure in depth-first, post-order traversal.
Operates like postwalk/3 but without an accumulator. Handling continuations
for structs require to handle the accumulator, whose value MUST be nil.
@spec postwalk(data, acc, (postwalk_item(), acc -> {data, acc})) :: {data, acc} when data: term(), acc: term()
Updates a JSON-compatible data structure in depth-first, post-order traversal while carrying an accumulator.
The callback must return a {new_value, new_acc} tuple.
Nested data structures are given to the callback before their wrappers, and when the wrappers are called, their children are already updated.
JSON-compatible only means that there are restrictions on map keys and struct values:
The callback function will be called for any key but will not traverse the keys. For instance, with data such as
%{{x, y} => "some city"}, the tuple used as key will be passed as-is but the callback will not be called for individual tuple elements.Structs will be passed as
{:struct, value, continuation}. The struct keys and values will NOT have been traversed yet. The callback should extract the struct into another term (for instance usingMap.from_struct/1) and call the continuation.To normalize this new term you MUST call the conitnuation function manually. To respect the post-order of traversal, it SHOULD be called before further transformation of the struct:
Traverse.postwalk(%MyStruct, [], fn {:struct, my_struct, cont}, acc -> {map, acc} = cont.(Map.from_struct(my_struct), acc) {struct!(MyStruct, do_something_with_map(map)), acc} {:val, ...} -> ... end)Note that if a map is given to the continuation function, the map itself will not be passed to your callback as
{:val, map}, each key and value will be normalized directly.Since key normalization does not support structs, the keys must be already normalized and JSON-encodable when giving a map to the continuation function.
General data is accepted: tuples, pid, refs, etc. *
@spec prewalk(data, (prewalk_item() -> data)) :: data when data: term()
Updates a data structure in depth-first, pre-order traversal.
Operates like prewalk/3 but without an accumulator.
@spec prewalk(data, acc, (prewalk_item(), acc -> {data, acc})) :: {data, acc} when data: term(), acc: term()
Updates a JSON-compatible data structure in depth-first, pre-order traversal while carrying an accumulator.
The callback must return a {new_value, new_acc} tuple.
Nested data structures are given iterated after the parent data has been given to the function. So it is possible to accept a container (map, list, tuple) and return another one from the callback before the children are iterated.
JSON-compatible only means that there are restrictions on map keys and struct values:
- The callback function will be called for any key but will not traverse the
keys. For instance, with data such as
%{{x, y} => "some city"}, the tuple used as key will be passed as-is but the callback will not be called for individual tuple elements. - Structs are passed as a
{:struct, struct}tuple. - General data is accepted: tuples, pid, refs, etc. *