@@ -191,9 +191,13 @@ defmodule Access do
191191 case __STACKTRACE__ do
192192 [ unquote ( top ) | _ ] ->
193193 reason =
194- "#{ inspect ( unquote ( module ) ) } does not implement the Access behaviour. " <>
195- "If you are using get_in/put_in/update_in, you can specify the field " <>
196- "to be accessed using Access.key!/1"
194+ """
195+ #{ inspect ( unquote ( module ) ) } does not implement the Access behaviour
196+
197+ You can use the "struct.field" syntax to access struct fields. \
198+ You can also use Access.key!/1 to access struct fields dynamically \
199+ inside get_in/put_in/update_in\
200+ """
197201
198202 % { unquote ( exception ) | reason: reason }
199203
@@ -326,9 +330,23 @@ defmodule Access do
326330 end
327331 end
328332
333+ def get ( list , key , _default ) when is_list ( list ) and is_integer ( key ) do
334+ raise ArgumentError , """
335+ the Access module does not support accessing lists by index, got: #{ inspect ( key ) }
336+
337+ Accessing a list by index is typically discouraged in Elixir, \
338+ instead we prefer to use the Enum module to manipulate lists \
339+ as a whole. If you really must access a list element by index, \
340+ you can Enum.at/1 or the functions in the List module\
341+ """
342+ end
343+
329344 def get ( list , key , _default ) when is_list ( list ) do
330- raise ArgumentError ,
331- "the Access calls for keywords expect the key to be an atom, got: " <> inspect ( key )
345+ raise ArgumentError , """
346+ the Access module supports only keyword lists (with atom keys), got: #{ inspect ( key ) }
347+
348+ If you want to search lists of tuples, use List.keyfind/3\
349+ """
332350 end
333351
334352 def get ( nil , _key , default ) do
@@ -377,10 +395,26 @@ defmodule Access do
377395 Map . get_and_update ( map , key , fun )
378396 end
379397
380- def get_and_update ( list , key , fun ) when is_list ( list ) do
398+ def get_and_update ( list , key , fun ) when is_list ( list ) and is_atom ( key ) do
381399 Keyword . get_and_update ( list , key , fun )
382400 end
383401
402+ def get_and_update ( list , key , _fun ) when is_list ( list ) and is_integer ( key ) do
403+ raise ArgumentError , """
404+ the Access module does not support accessing lists by index, got: #{ inspect ( key ) }
405+
406+ Accessing a list by index is typically discouraged in Elixir, \
407+ instead we prefer to use the Enum module to manipulate lists \
408+ as a whole. If you really must mostify a list element by index, \
409+ you can Access.at/1 or the functions in the List module\
410+ """
411+ end
412+
413+ def get_and_update ( list , key , _fun ) when is_list ( list ) do
414+ raise ArgumentError ,
415+ "the Access module supports only keyword lists (with atom keys), got: " <> inspect ( key )
416+ end
417+
384418 def get_and_update ( nil , key , _fun ) do
385419 raise ArgumentError , "could not put/update key #{ inspect ( key ) } on a nil value"
386420 end
@@ -507,6 +541,21 @@ defmodule Access do
507541 iex> get_in(map, [Access.key!(:user), Access.key!(:unknown)])
508542 ** (KeyError) key :unknown not found in: %{name: \" john\" }
509543
544+ The examples above could be partially written as:
545+
546+ iex> map = %{user: %{name: "john"}}
547+ iex> map.user.name
548+ "john"
549+ iex> get_and_update_in(map.user.name, fn prev ->
550+ ...> {prev, String.upcase(prev)}
551+ ...> end)
552+ {"john", %{user: %{name: "JOHN"}}}
553+
554+ However, it is not possible to remove fields using the dot notation,
555+ as it is implified those fields must also be present. In any case,
556+ `Access.key!/1` is useful when the key is not known in advance
557+ and must be accessed dynamically.
558+
510559 An error is raised if the accessed structure is not a map/struct:
511560
512561 iex> get_in([], [Access.key!(:foo)])
0 commit comments