Return statement in Elixir

后端 未结 8 1411
野趣味
野趣味 2020-12-14 00:38

I need a function with some kind of a step-by-step logic and I wonder how I can make one. Let\'s take a log in process on a site as an example, so I need the following logic

8条回答
  •  天涯浪人
    2020-12-14 01:13

    This is an interesting problem because you need to perform multiple checks, exit early, and in the process transform some state (connection). I typically approach this problem as follows:

    • I implement each check as a function which takes state as an input and returns {:ok, new_state} or {:error, reason}.
    • Then, I build a generic function that will invoke a list of check functions, and return either the first encountered {:error, reason} or {:ok, last_returned_state} if all checks succeeded.

    Let's see the generic function first:

    defp perform_checks(state, []), do: {:ok, state}
    defp perform_checks(state, [check_fun | remaining_checks]) do
      case check_fun.(state) do
        {:ok, new_state} -> perform_checks(new_state, remaining_checks)
        {:error, _} = error -> error
      end
    end
    

    Now, we can use it as follows:

    perform_checks(conn, [
      # validate mail presence
      fn(conn) -> if (...), do: {:error, "Invalid mail"}, else: {:ok, new_conn} end,
    
      # validate mail format
      fn(conn) -> if (...), do: {:error, "Invalid mail"}, else: {:ok, new_conn} end,
    
      ...
    ])
    |> case do
      {:ok, state} -> do_something_with_state(...)
      {:error, reason} -> do_something_with_error(...)
    end
    

    Or alternatively move all checks to named private functions and then do:

    perform_checks(conn, [
      &check_mail_presence/1,
      &check_mail_format/1,
      ...
    ])
    

    You could also look into the elixir-pipes which might help you express this with pipeline.

    Finally, in the context of Phoenix/Plug, you could declare your checks as a series of plugs and halt on first error.

提交回复
热议问题