[Proposal] operator =~ should support maps

93 views
Skip to first unread message

jer...@companykitchen.com

unread,
Oct 17, 2017, 11:01:48 PM10/17/17
to elixir-lang-core
I think it would be useful if =~ supported maps.  =~ would return true if the key/values in the right hand map were also contained in the left-hand map.  I think this would be especially useful for testing, as you could check that the result matched a subset of the map, rather than the whole map.

e.g.
data = Repo.insert!(src)
# data = %Data{id: 25, field1: "foo", field2: "bar", inserted_at: ~N[2017-01-01], updated_at: ~N[2017-01-01]}
assert data =~ %{field1: "foo", field2: "bar"}  # true

Andrew Timberlake

unread,
Oct 18, 2017, 1:14:00 AM10/18/17
to elixir-lang-core
You can do that with pattern matching,

assert %{field1: "foo", field2: "bar"} = data
--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/7eaabb77-6c7a-4fcb-a74a-fc303f5ace26%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

jer...@companykitchen.com

unread,
Oct 18, 2017, 8:43:51 AM10/18/17
to elixir-lang-core
Yes, but that throws a MatchError exception if not satisfied, not a true/false.  Ideally, in the assertion results, it would highlight the failing key/values as well.  Primarily for testing, but also a quick way to test for the presence of multiple key/values in larger maps.

Louis Pilfold

unread,
Oct 18, 2017, 9:03:05 AM10/18/17
to elixir-lang-core
Hey

The `assert` macro handles MatchError as well as true/false.

>  Ideally, in the assertion results, it would highlight the failing key/values as well.

This would be a nice addition to ExUnit. I would rather see this than any addition to =~

Cheers,
Louis

jer...@companykitchen.com

unread,
Oct 18, 2017, 9:19:20 AM10/18/17
to elixir-lang-core
Wouldn't it be more difficult to determine the right thing to print based on a MatchError, than the operator and operands?  Maybe not all that harder, but I do prefer the explicitness of saying "I'm comparing a subset", rather than "attempting an assignment" 

Allen Madsen

unread,
Oct 18, 2017, 9:46:20 AM10/18/17
to elixir-l...@googlegroups.com
If you want a boolean value for a match, you can use: https://hexdocs.pm/elixir/Kernel.html#match?/2
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/67f18c62-08e9-4e68-b8c7-e7d3e8dcf36b%40googlegroups.com.

José Valim

unread,
Oct 18, 2017, 9:53:09 AM10/18/17
to elixir-l...@googlegroups.com
Use match?/2:

assert match?(%{field1: "foo", field2: "bar"}, data)

The operator =~ was designed to focus exclusively on strings and we don't plan to relax those constraints.


José Valim
Founder and 
Director of R&D

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/fb23650e-c3f4-4694-86e1-62cdc2b9e103%40googlegroups.com.

jer...@companykitchen.com

unread,
Oct 18, 2017, 10:16:07 PM10/18/17
to elixir-lang-core
What would you all think of changing the assert output when the argument to assert is match?(map, map) so that it shows the difference similar to if we did an ==, except the extra fields in the right-hand map would be omitted?  This is what we currently see when using "assert match?(%{field1: "foo", field2: "bar"}, data)":
  1) test map1 (MapPropsalTest)
     test/map_propsal_test.exs:10
     match (match?) failed
     code:  assert match?(%{field1: "foo", field2: "bar", field3: "not-there"}, map)
     right: %{
              field1: "foo",
              field2: "bar",
              inserted_at: ~N[2017-10-19 02:10:25.254692]
            }
     stacktrace:
       test/map_propsal_test.exs:12: (test)

How I think it should read instead when the args to match? are both maps :
  2) test map2 (MapPropsalTest)
     test/map_propsal_test.exs:15
     match (match?) failed
     code:  assert match?(%{field1: "foo", field2: "bar", field3: "not-there"}, map)
     left:  %{field1: "foo", field2: "bar", <red>field3: "not-there"</red>}
     right: %{field1: "foo", field2: "bar"}
     stacktrace:
       test/map_propsal_test.exs:17: (test)

I'd be happy to do the work.

José Valim

unread,
Oct 19, 2017, 3:59:37 AM10/19/17
to elixir-l...@googlegroups.com
There is already an open issue for that in the form of doing something similar for assert_receive but that's actually very complex since the left side is a *pattern* and not a value. So we would need to have a "pattern evaluator" or similar.



José Valim
Founder and 
Director of R&D

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/708c63d3-4dd8-41d3-a5fd-2b304f7ccba4%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages