Current section
Files
Jump to
Current section
Files
src/optic_proplists.erl
%%%-------------------------------------------------------------------
%%% @doc
%%% A set of optics specific to proplists.
%%% @end
%%%-------------------------------------------------------------------
-module(optic_proplists).
%% API
-export([all/0,
all/1,
keys/0,
keys/1,
values/0,
values/1,
properties/0,
properties/1,
key/1,
key/2,
property/1,
property/2]).
%%%===================================================================
%%% API
%%%===================================================================
%% @see values/1
-spec all() -> optic:optic().
all() ->
values(#{}).
%% @see values/1
-spec all(optic:variations()) -> optic:optic().
all(Options) ->
values(Options).
%% @see keys/1
-spec keys() -> optic:optic().
keys() ->
keys(#{}).
%% @doc
%% Focus on all keys of a list of properties. Duplicate keys are
%% preserved.
%%
%% Example:
%%
%% ```
%% > optic:get([optic_proplists:keys()], [{first, 1}, {second, 2}]).
%% {ok,[first,second]}
%% '''
%% @end
%% @param Options Common optic options.
%% @returns An opaque optic record.
-spec keys(optic:variations()) -> optic:optic().
keys(Options) ->
Fold =
fun (Fun, Acc, List) when is_list(List) ->
{ok, lists:foldl(
fun ({Key, _Value}, InnerAcc) ->
Fun(Key, InnerAcc)
end,
Acc,
proplists:unfold(List))};
(_Fun, _Acc, _Data) ->
{error, undefined}
end,
MapFold =
fun (Fun, Acc, List) when is_list(List) ->
{NewList, NewAcc} = lists:foldl(
fun ({Key, Value}, {InnerList, InnerAcc}) ->
{NewKey, NewAcc} = Fun(Key, InnerAcc),
{[{NewKey, Value} | InnerList], NewAcc}
end,
{[], Acc},
proplists:unfold(List)),
{ok, {lists:reverse(NewList), NewAcc}};
(_Fun, _Acc, _Data) ->
{error, undefined}
end,
New =
fun (_Data, _Template) ->
[]
end,
Optic = optic:new(MapFold, Fold),
optic:variations(Optic, Options, New).
%% @see values/1
-spec values() -> optic:optic().
values() ->
values(#{}).
%% @doc
%% Focus on all values of a list of properties.
%%
%% Example:
%%
%% ```
%% > optic:get([optic_proplists:values()], [{first, 1}, {second, 2}]).
%% {ok,[1,2]}
%% '''
%% @end
%% @param Options Common optic options.
%% @returns An opaque optic record.
-spec values(optic:variations()) -> optic:optic().
values(Options) ->
Fold =
fun (Fun, Acc, List) when is_list(List) ->
{ok, lists:foldl(
fun ({_Key, Value}, InnerAcc) ->
Fun(Value, InnerAcc)
end,
Acc,
proplists:unfold(List))};
(_Fun, _Acc, _Data) ->
{error, undefined}
end,
MapFold =
fun (Fun, Acc, List) when is_list(List) ->
{NewList, NewAcc} = lists:foldl(
fun ({Key, Value}, {InnerList, InnerAcc}) ->
{NewValue, NewAcc} = Fun(Value, InnerAcc),
{[{Key, NewValue} | InnerList], NewAcc}
end,
{[], Acc},
proplists:unfold(List)),
{ok, {lists:reverse(NewList), NewAcc}};
(_Fun, _Acc, _Data) ->
{error, undefined}
end,
New =
fun (_Data, _Template) ->
[]
end,
Optic = optic:new(MapFold, Fold),
optic:variations(Optic, Options, New).
%% @see properties/1
-spec properties() -> optic:optic().
properties() ->
properties(#{}).
%% @doc
%% Focus on all properties of a list of properties. A propety is a
%% tuple of a key and value. If a value was not given, it defaults to
%% the atom `true'.
%%
%% Example:
%%
%% ```
%% > optic:get([optic_proplists:properties()], [{first, 1}, {second, 2}]).
%% {ok,[{first,1},{second,2}]}
%% '''
%% @end
%% @param Options Common optic options.
%% @returns An opaque optic record.
-spec properties(optic:variations()) -> optic:optic().
properties(Options) ->
Fold =
fun (Fun, Acc, List) when is_list(List) ->
{ok, lists:foldl(Fun, Acc, proplists:unfold(List))};
(_Fun, _Acc, _Data) ->
{error, undefined}
end,
MapFold =
fun (Fun, Acc, List) when is_list(List) ->
{NewList, NewAcc} = lists:foldl(
fun (Tuple, {InnerList, InnerAcc}) ->
{NewTuple, NewAcc} = Fun(Tuple, InnerAcc),
{[NewTuple | InnerList], NewAcc}
end,
{[], Acc},
proplists:unfold(List)),
{ok, {lists:reverse(NewList), NewAcc}};
(_Fun, _Acc, _Data) ->
{error, undefined}
end,
New =
fun (_Data, _Template) ->
[]
end,
Optic = optic:new(MapFold, Fold),
optic:variations(Optic, Options, New).
%% @see key/2
-spec key(term()) -> optic:optic().
key(Key) ->
key(Key, #{}).
%% @doc
%% Focus on the value of a property list key. As keys may be
%% duplicated, this may be multiple values. If the value is not given,
%% it defaults to the atom `true'.
%%
%% Example:
%%
%% ```
%% > optic:get([optic_proplists:key(first)], [{first, 1}, {second, 2}]).
%% {ok,[1]}
%% '''
%% @end
%% @param Key The key to focus on.
%% @param Options Common optic options.
%% @returns An opaque optic record.
-spec key(term(), optic:variations()) -> optic:optic().
key(Key, Options) ->
Fold =
fun (Fun, Acc, List) when is_list(List) ->
case proplists:get_all_values(Key, List) of
[] ->
{error, undefined};
Values ->
{ok, lists:foldl(
fun (Value, InnerAcc) ->
Fun(Value, InnerAcc)
end,
Acc,
Values)}
end;
(_Fun, _Acc, _Data) ->
{error, undefined}
end,
MapFold =
fun (Fun, Acc, List) when is_list(List) ->
case proplists:get_all_values(Key, List) of
[] ->
{error, undefined};
_ ->
{ok, lists:mapfoldl(
fun (Elem, InnerAcc) ->
case proplists:is_defined(Key, [Elem]) of
true ->
Value = proplists:get_value(Key, [Elem]),
{NewValue, NewAcc} = Fun(Value, InnerAcc),
{{Key, NewValue}, NewAcc};
false ->
{Elem, InnerAcc}
end
end,
Acc,
List)}
end;
(_Fun, _Acc, _Data) ->
{error, undefined}
end,
New =
fun (List, Template) when is_list(List) ->
[{Key, Template} | List];
(_Data, Template) ->
[{Key, Template}]
end,
Optic = optic:new(MapFold, Fold),
optic:variations(Optic, Options, New).
%% @see property/2
-spec property(term()) -> optic:optic().
property(Key) ->
property(Key, #{}).
%% @doc
%% Focus on a property in a property list by key. As keys may be
%% duplicated, this may be multiple properties. If the value is not
%% given, it defaults to the atom `true'. If the key is modified, the
%% optic is no longer well behaved.
%%
%% Example:
%%
%% ```
%% > optic:get([optic_proplists:property(first)], [{first, 1}, {second, 2}]).
%% {ok,[{first,1}]}
%% '''
%% @end
%% @param Key The key to focus on.
%% @param Options Common optic options.
%% @returns An opaque optic record.
-spec property(term(), optic:variations()) -> optic:optic().
property(Key, Options) ->
Fold =
fun (Fun, Acc, List) when is_list(List) ->
case proplists:get_all_values(Key, List) of
[] ->
{error, undefined};
Values ->
{ok, lists:foldl(
fun (Value, InnerAcc) ->
Fun({Key, Value}, InnerAcc)
end,
Acc,
Values)}
end;
(_Fun, _Acc, _Data) ->
{error, undefined}
end,
MapFold =
fun (Fun, Acc, List) when is_list(List) ->
case proplists:get_all_values(Key, List) of
[] ->
{error, undefined};
_ ->
{ok, lists:mapfoldl(
fun (Elem, InnerAcc) ->
case proplists:is_defined(Key, [Elem]) of
true ->
Value = proplists:get_value(Key, [Elem]),
{{NewKey, NewValue}, NewAcc} = Fun({Key, Value}, InnerAcc),
{{NewKey, NewValue}, NewAcc};
false ->
{Elem, InnerAcc}
end
end,
Acc,
List)}
end;
(_Fun, _Acc, _Data) ->
{error, undefined}
end,
New =
fun (List, Template) when is_list(List) ->
[{Key, Template} | List];
(_Data, Template) ->
[{Key, Template}]
end,
Optic = optic:new(MapFold, Fold),
optic:variations(Optic, Options, New).