Asserting exact maps

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Asserting exact maps

Technion

Hi,


I'm wondering if there is a simple process I can use to verify a map only contains valid variables. Consider the following example:


2> Checkmaps = fun(M) ->
2> #{"one" := One, "two" := _Two} = M,
2>     One end.
#Fun<erl_eval.6.99386804>

% These crash as expected

5> Checkmaps(#{"test" => one }).
** exception error: no match of right hand side value #{"test" => one}
6> Checkmaps(#{"one" => one }).
** exception error: no match of right hand side value #{"one" => one}


% This works as expected

7> Checkmaps(#{"one" => one, "two" => two }).
one

% This however also runs - I would like it to crash like the first example

8> Checkmaps(#{"one" => one, "two" => two, "three" => test }).

one

The use case here is I'm pulling external data - anything I'm not expecting is not a happy path. Any assistance appreciated.


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Asserting exact maps

Attila Rajmund Nohl
2017-10-11 10:47 GMT+02:00 Technion <[hidden email]>:

> Hi,
>
>
> I'm wondering if there is a simple process I can use to verify a map only
> contains valid variables. Consider the following example:
>
>
> 2> Checkmaps = fun(M) ->
> 2> #{"one" := One, "two" := _Two} = M,
> 2>     One end.
> #Fun<erl_eval.6.99386804>
>
> % These crash as expected
>
> 5> Checkmaps(#{"test" => one }).
> ** exception error: no match of right hand side value #{"test" => one}
> 6> Checkmaps(#{"one" => one }).
> ** exception error: no match of right hand side value #{"one" => one}
>
>
> % This works as expected
>
> 7> Checkmaps(#{"one" => one, "two" => two }).
> one
>
> % This however also runs - I would like it to crash like the first example
>
> 8> Checkmaps(#{"one" => one, "two" => two, "three" => test }).
>
> one
>
> The use case here is I'm pulling external data - anything I'm not expecting
> is not a happy path. Any assistance appreciated.

Check also the size of the map. If it's greater than expected, it has
extra elements.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Asserting exact maps

Alexander Mihajlovic
The function maps:with/2 [1] will get you most of the way there. It lets
you filter a map to only contain keys in your given list. After that
it's only a matter of matching the filtered map against the original, or
you could check their lengths like Attila Rajmund Nohl wrote.

1> X = #{one => "1", two => "2"}.
#{one => "1",two => "2"}
2> X = maps:with([one, two], X).
#{one => "1",two => "2"}
3> Y = #{one => "1", two => "2", three => "3"}.
#{one => "1",three => "3",two => "2"}
4> Y = maps:with([one, two], Y).              
** exception error: no match of right hand side value #{one => "1",two
=> "2"}

[1]: http://erlang.org/doc/man/maps.html#with-2

On Wed, Oct 11, 2017, at 10:50, Attila Rajmund Nohl wrote:

> 2017-10-11 10:47 GMT+02:00 Technion <[hidden email]>:
> > Hi,
> >
> >
> > I'm wondering if there is a simple process I can use to verify a map only
> > contains valid variables. Consider the following example:
> >
> >
> > 2> Checkmaps = fun(M) ->
> > 2> #{"one" := One, "two" := _Two} = M,
> > 2>     One end.
> > #Fun<erl_eval.6.99386804>
> >
> > % These crash as expected
> >
> > 5> Checkmaps(#{"test" => one }).
> > ** exception error: no match of right hand side value #{"test" => one}
> > 6> Checkmaps(#{"one" => one }).
> > ** exception error: no match of right hand side value #{"one" => one}
> >
> >
> > % This works as expected
> >
> > 7> Checkmaps(#{"one" => one, "two" => two }).
> > one
> >
> > % This however also runs - I would like it to crash like the first example
> >
> > 8> Checkmaps(#{"one" => one, "two" => two, "three" => test }).
> >
> > one
> >
> > The use case here is I'm pulling external data - anything I'm not expecting
> > is not a happy path. Any assistance appreciated.
>
> Check also the size of the map. If it's greater than expected, it has
> extra elements.
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Asserting exact maps

zxq9-2
In reply to this post by Technion
On 2017年10月11日 水曜日 08:47:40 Technion wrote:

> Hi,
>
>
> I'm wondering if there is a simple process I can use to verify a map
> only contains valid variables. Consider the following example:
>
>
> 2> Checkmaps = fun(M) ->
> 2> #{"one" := One, "two" := _Two} = M,
> 2>     One end.
> #Fun<erl_eval.6.99386804>
>
> % These crash as expected
>
> 5> Checkmaps(#{"test" => one }).
> ** exception error: no match of right hand side value #{"test" => one}
> 6> Checkmaps(#{"one" => one }).
> ** exception error: no match of right hand side value #{"one" => one}
>
>
> % This works as expected
>
> 7> Checkmaps(#{"one" => one, "two" => two }).
> one
>
> % This however also runs - I would like it to crash like the first example
>
> 8> Checkmaps(#{"one" => one, "two" => two, "three" => test }).
>
> one
>
>
> The use case here is I'm pulling external data - anything I'm not
> expecting is not a happy path. Any assistance appreciated.

I find it easiest (both to write and to prove) to convert the map to a
list and then perform a complete and exact comparison of keys over it.

If I still need the map version then I'll pass the original if it
survived, but almost every time I have an exact set of keys that must
exist (and be the only keys that exist) I actually need a record, not
a map (because the data is semantically a tuple, not a map of variable
{K, V} pairs). The only exception to this is when I am passing the data
on to some external lib that was written by the sort of person who
believes that there is only one data type in the universe.

Another easy to write and easy to prove approach is to incrementally
pack a structure by using maps:take/2, and checking whether the map is
empty at the end or not. If it is empty then your structure should be
passed forward and life goes on as expected.

Any variation of that will work fairly simply.


1> Checkmap =
1>     fun(Map,Keys) ->
1>         Drop = fun(K, M) -> {_, Next} = maps:take(K, M), Next end,
1>         0 = maps:size(lists:foldl(Drop, Map, Keys))
1>     end.
#Fun<erl_eval.12.87737649>
2> Checkmap(#{"one" => 1, "two" => 2}, ["one", "two"]).
0
3> Checkmap(#{"one" => 1, "two" => 2}, ["one", "two", "three"]).
** exception error: no match of right hand side value error
4> Checkmap(#{"one" => 1, "two" => 2}, ["one", "three"]).      
** exception error: no match of right hand side value error
5> Checkmap(#{"one" => 1, "two" => 2}, ["one"]).        
** exception error: no match of right hand side value 1

But I prefer the list version that operates over lists, personally.

-Craig
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Asserting exact maps

zxq9-2
On 2017年10月11日 水曜日 18:20:20 zxq9 wrote:
> On 2017年10月11日 水曜日 08:47:40 Technion wrote:
> > Hi,
> >
> >
> > I'm wondering if there is a simple process I can use to verify a map
> > only contains valid variables.
>
> But I prefer the list version that operates over lists, personally.

... which I totally failed to provide any version of whatsoever.

A super simple one:

1> Checkmap =
1>     fun(Map, Keys) ->
1>         lists:sort(Keys) == lists:sort(maps:keys(Map))
1>     end.
#Fun<erl_eval.12.87737649>
2> Checkmap(#{"one" => 1, "two" => 2}, ["one", "two"]).
true
3> Checkmap(#{"one" => 1, "two" => 2}, ["two", "one"]).
true
4> Checkmap(#{"one" => 1, "two" => 2}, ["two", "one", "three"]).
false
5> Checkmap(#{"one" => 1, "two" => 2}, ["two"]).                
false

Of course, here I am returning a boolean, but I prefer that for assertions
because I can do:

true = checkmap(Map, Keys)

and move on -- and reuse that function somewhere else in a non-crashing
way if I need to.

-Craig
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Asserting exact maps

Danil Zagoskin-2
In reply to this post by Technion
Just to add one more option.
You may use maps:without to ensure the map does not have extra keys:

1> Check = fun(M) -> maps:without(["one", "two"], M) == #{} end.
#Fun<erl_eval.6.99386804>
2> Check(#{"one" => 1}).
true
3> Check(#{"one" => 1, "three" => 3}).
false

On Wed, Oct 11, 2017 at 11:47 AM, Technion <[hidden email]> wrote:

Hi,


I'm wondering if there is a simple process I can use to verify a map only contains valid variables. Consider the following example:


2> Checkmaps = fun(M) ->
2> #{"one" := One, "two" := _Two} = M,
2>     One end.
#Fun<erl_eval.6.99386804>

% These crash as expected

5> Checkmaps(#{"test" => one }).
** exception error: no match of right hand side value #{"test" => one}
6> Checkmaps(#{"one" => one }).
** exception error: no match of right hand side value #{"one" => one}


% This works as expected

7> Checkmaps(#{"one" => one, "two" => two }).
one

% This however also runs - I would like it to crash like the first example

8> Checkmaps(#{"one" => one, "two" => two, "three" => test }).

one

The use case here is I'm pulling external data - anything I'm not expecting is not a happy path. Any assistance appreciated.


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions




--
Danil Zagoskin | [hidden email]

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions