I have the following function which I’m struggling with a bit. What it has to do is check for the existence of the following values as a comma-separated string, then convert that string to a list. So, simple enough. I’m just struggling a bit with how to write it in a correct form in elixir. Below is what I have, which runs, but it rightly raises a compile warning.
Any help in how to better structure this is much appreciated
defp convert_outcodes(changeset) do
zone_a_string = get_change(changeset, :zone_a_outcode_string)
zone_b_string = get_change(changeset, :zone_b_outcode_string)
if zone_a_string do
split = zone_a_string |> String.split(",")
changeset = put_change(changeset, :zone_a_outcodes, split)
end
if zone_b_string do
split = zone_b_string |> String.split(",")
changeset = put_change(changeset, :zone_b_outcodes, split)
end
changeset
end
def convert_outcodes(changeset) do
changeset
|> split_outcode(:zone_a_outcode_string, :zone_a_outcode)
|> split_outcode(:zone_b_outcode_string, :zone_b_outcode)
end
defp split_outcode(changeset, from_atom, to_atom) do
case get_change(changeset, from_atom) do
nil -> changeset
change ->
split = String.split(change, ",")
put_change(changeset, to_atom, split)
end
end
# somewhere in your code
zone_codes = [zone_a_outcode_string: :zone_a_outcodes,
zone_b_outcode_string: :zone_b_outcodes]
defp convert_outcodes(changeset, zone_codes) do
Enum.reduce(zone_codes, changeset, fn {string_key, codes_key}, cset ->
string = get_change(cset, string_key)
if string do
put_change(cset, codes_key, String.split(string, ","))
else
cset
end
end)
end
and if you didn’t need the :zone_X_outcode string after processing (maybe) you could even do it with recursion and pattern matching by removing that change.
The reason why is that your if’s do not have an else block, you must always have an else block. A fine way to do it (although breaking it up in to more functions is probably better) is just to fix that, then it should be fine:
defp convert_outcodes(changeset) do
zone_a_string = get_change(changeset, :zone_a_outcode_string)
zone_b_string = get_change(changeset, :zone_b_outcode_string)
changeset =
if zone_a_string do
split = zone_a_string |> String.split(",")
put_change(changeset, :zone_a_outcodes, split)
else
changeset
end
changeset =
if zone_b_string do
split = zone_b_string |> String.split(",")
put_change(changeset, :zone_b_outcodes, split)
else
changeset
end
changeset
end
But still, more functions is better, especially with how repeatable that code is:
defp convert_outcodes(changeset) do
changeset
|> convert_outcodes_change(:zone_a_outcode_string, :zone_a_outcodes)
|> convert_outcodes_change(:zone_b_outcode_string, :zone_b_outcodes)
end
defp convert_outcodes_change(changeset, in_tag, out_tag) do
case get_change(changeset, in_tag) do
nil -> changeset
string ->
split = String.split(string, ",")
put_change(changeset, out_tag, split)
end
end
Or something like that. (EDIT: Which is basically what some of the above did ^.^; )
Er yes, split needs to be two different names in each one, Elixir has this really annoying scope leakage, just uniquely name variables and all is good. ^.^