@@ -140,8 +140,10 @@ defmodule Record do
140
140
there is more work happening at runtime.
141
141
142
142
The above calls (new and update) can interchangeably accept both
143
- atom and string keys for field names. Please note, however, that
144
- atom keys are faster.
143
+ atom and string keys for field names, however not both at the same time.
144
+ Please also note that atom keys are faster. This feature allows to
145
+ "sanitize" untrusted dictionaries and initialize/update records without
146
+ using `binary_to_existing_atom/1`.
145
147
146
148
To sum up, `defrecordp` should be used when you don't want
147
149
to expose the record information while `defrecord` should be used
@@ -628,16 +630,15 @@ defmodule Record do
628
630
# an ordered dict of options (opts) and it will try to fetch
629
631
# the given key from the ordered dict, falling back to the
630
632
# default value if one does not exist.
631
- selective = lc { k, v } inlist values do
632
- string_k = atom_to_binary(k)
633
- quote do
633
+ atom_selective = lc { k, v } inlist values do
634
+ quote do: Keyword.get(opts, unquote(k), unquote(v))
635
+ end
636
+ string_selective = lc { k, v } inlist values do
637
+ k = atom_to_binary(k)
638
+ quote do
634
639
case :lists.keyfind(unquote(k), 1, opts) do
635
- false ->
636
- case :lists.keyfind(unquote(string_k), 1, opts) do
637
- false -> unquote(v)
638
- {_, value} -> value
639
- end
640
- {_, value} -> value
640
+ false -> unquote(v)
641
+ {_, v} -> v
641
642
end
642
643
end
643
644
end
@@ -648,7 +649,8 @@ defmodule Record do
648
649
649
650
@doc false
650
651
def new([]), do: { __MODULE__, unquote_splicing(defaults) }
651
- def new(opts) when is_list(opts), do: { __MODULE__, unquote_splicing(selective) }
652
+ def new([{key, _}|_] = opts) when is_atom(key), do: { __MODULE__, unquote_splicing(atom_selective) }
653
+ def new([{key, _}|_] = opts) when is_binary(key), do: { __MODULE__, unquote_splicing(string_selective) }
652
654
end
653
655
end
654
656
@@ -739,32 +741,38 @@ defmodule Record do
739
741
# Define an updater method that receives a
740
742
# keyword list and updates the record.
741
743
defp updater(values) do
742
- fields =
744
+ atom_fields =
743
745
lc {key, _default} inlist values do
744
- string_key = atom_to_binary(key)
745
746
index = find_index(values, key, 1)
747
+ quote do: Keyword.get(keywords, unquote(key), elem(record, unquote(index)))
748
+ end
749
+
750
+ string_fields =
751
+ lc {key, _default} inlist values do
752
+ index = find_index(values, key, 1)
753
+ key = atom_to_binary(key)
746
754
quote do
747
755
case :lists.keyfind(unquote(key), 1, keywords) do
748
- false ->
749
- case :lists.keyfind(unquote(string_key), 1, keywords) do
750
- false -> elem(record, unquote(index))
751
- {_, value} -> value
752
- end
756
+ false -> elem(record, unquote(index))
753
757
{_, value} -> value
754
758
end
755
759
end
756
760
end
757
761
758
- contents = quote do: { __MODULE__, unquote_splicing(fields) }
762
+ atom_contents = quote do: { __MODULE__, unquote_splicing(atom_fields) }
763
+ string_contents = quote do: { __MODULE__, unquote_splicing(string_fields) }
759
764
760
765
quote do
761
766
@doc false
762
767
def update([], record) do
763
768
record
764
769
end
765
770
766
- def update(keywords, record) do
767
- unquote(contents)
771
+ def update([{key, _}|_] = keywords, record) when is_atom(key) do
772
+ unquote(atom_contents)
773
+ end
774
+ def update([{key, _}|_] = keywords, record) when is_binary(key) do
775
+ unquote(string_contents)
768
776
end
769
777
end
770
778
end
0 commit comments