@@ -191,9 +191,13 @@ defmodule Access do
191
191
case __STACKTRACE__ do
192
192
[ unquote ( top ) | _ ] ->
193
193
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
+ """
197
201
198
202
% { unquote ( exception ) | reason: reason }
199
203
@@ -326,9 +330,23 @@ defmodule Access do
326
330
end
327
331
end
328
332
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
+
329
344
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
+ """
332
350
end
333
351
334
352
def get ( nil , _key , default ) do
@@ -377,10 +395,26 @@ defmodule Access do
377
395
Map . get_and_update ( map , key , fun )
378
396
end
379
397
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
381
399
Keyword . get_and_update ( list , key , fun )
382
400
end
383
401
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
+
384
418
def get_and_update ( nil , key , _fun ) do
385
419
raise ArgumentError , "could not put/update key #{ inspect ( key ) } on a nil value"
386
420
end
@@ -507,6 +541,21 @@ defmodule Access do
507
541
iex> get_in(map, [Access.key!(:user), Access.key!(:unknown)])
508
542
** (KeyError) key :unknown not found in: %{name: \" john\" }
509
543
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
+
510
559
An error is raised if the accessed structure is not a map/struct:
511
560
512
561
iex> get_in([], [Access.key!(:foo)])
0 commit comments