Awesome
nested
{<sub>{<sub>{<sub>{<sub>{}</sub>}</sub>}{<sub>{<sub>{}</sub>}</sub>}</sub>}</sub>}
a library to handle nested Erlang maps
requirements
Erlang/OTP 17.3 or newer
building
git clone git@github.com:odo/nested.git
cd nested
./rebar compile
erl -pz ebin
usage
get
get the value of an existing key:
1> Map = #{two => #{one => target, one_side => 1}, two_side => 2}.
#{two => #{one => target,one_side => 1},two_side => 2}
2> nested:get([two, one], Map).
target
or use a default in case the key does not exist:
1> Map = #{two => #{one => target, one_side => 1}, two_side => 2}.
#{two => #{one => target,one_side => 1},two_side => 2}
2> nested:get([two, some_unknown_key], Map, default).
default
put
put some value under a key that might or might not exist:
1> Map = #{two => #{one => target, one_side => 1}, two_side => 2}.
#{two => #{one => target,one_side => 1},two_side => 2}
2> nested:put([two, one], i_got_you, Map).
#{two => #{one => i_got_you,one_side => 1},two_side => 2}
If there are more keys than in the original map, nested maps are created:
3> nested:put([two, down, the, rabbit, hole], 42, Map).
#{two => #{down => #{the => #{rabbit => #{hole => 42}}},one => target,one_side => 1},
two_side => 2}
update
replace an exiting value:
1> Map = #{two => #{one => target, one_side => 1}, two_side => 2}.
#{two => #{one => target,one_side => 1},two_side => 2}
2> nested:update([two, one_side], 7, Map).
#{two => #{one => target,one_side => 7},two_side => 2}
instead of a value, you can pass a function with arity 1 which is passed the old value:
3> nested:update([two_side], fun(E) -> E*2 end, Map).
#{two => #{one => target,one_side => 1},two_side => 4}
If you really mean to set the value to a fun you have to wrap it in an update fun:
4> nested:update([two_side], fun(_) -> fun(A, B) -> {A, B} end end, Map).
#{two => #{one => target,one_side => 1},
two_side => #Fun<erl_eval.12.106461118>}
remove
delete a key:
1> Map = #{two => #{one => target, one_side => 1}, two_side => 2}.
#{two => #{one => target,one_side => 1},two_side => 2}
2> nested:remove([two, one_side], Map).
#{two => #{one => target},two_side => 2}
if the path does not exist, nothing changes:
1> Map = #{two => #{one => target, one_side => 1}, two_side => 2}.
#{two => #{one => target,one_side => 1},two_side => 2}
2> nested:remove([two, unknow, path], Map).
#{two => #{one => target,one_side => 1},two_side => 2}
keys
list the keys in a sup map:
1> Map = #{two => #{one => target, one_side => 1}, two_side => 2}.
#{two => #{one => target,one_side => 1},two_side => 2}
2> nested:keys([two], Map).
[one,one_side]
getf/1, getf/2, updatef/1, putf/1, removef/1, keysf/1
you can use this variants to get a function with the path in the context:
1> Map = #{two => #{one => target, one_side => 1}, two_side => 2}.
#{two => #{one => target,one_side => 1},two_side => 2}
2> TwoOneSelector = nested:getf([two, one]).
#Fun<nested.0.8958893>
3> TwoOneSelector(Map).
target
4> TwoOneUpdater = nested:updatef([two, one]).
#Fun<nested.1.8958893>
5> TwoOneUpdater(new_value, Map).
#{two => #{one => new_value,one_side => 1},two_side => 2}
tests
./rebar eunit