defmodule IfElse do @moduledoc """ Functions providing conditional logic. ```elixir Interactive Elixir (1.14.0) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> import IfElse IfElse iex(2)> is_empty?("") true iex(3)> empty_else("foo", "bar") "foo" iex(4)> empty_else("", "bar") "bar" iex(5)> empty_else("", fn -> "bar" end) "bar" iex(6)> coalesce([false, nil, "true", false]) "true" iex(7)> put_if(%{one: %{two: :three}}, :four, [:one, :two]) %{one: %{two: :four}} iex(8)> put_if(%{one: %{two: :three}}, nil, [:one, :two]) %{one: %{two: :three}} ``` ## Conditional function calls in a pipeline Only call `put_session/3` if `session_value` is not `nil`. ```elixir conn |> call_if(session_value, & put_session(&1, :session_key, &2)) |> ... ``` """ @doc """ Check for empty strings, where empty is `nil` or `""`. """ @spec is_empty?(nil | String.t()) :: true | false def is_empty?(nil), do: true def is_empty?(""), do: true def is_empty?(_), do: false @doc """ If the `value` is `nil` or an empty string, return the `else_value`. Otherwise, return the value. If `else_value` is a function, it is called. """ @spec empty_else(value :: nil | String.t() | any(), else_value :: (() -> any()) | any()) :: any() def empty_else(nil, else_value) when is_function(else_value), do: else_value.() def empty_else("", else_value) when is_function(else_value), do: else_value.() def empty_else(nil, else_value), do: else_value def empty_else("", else_value), do: else_value def empty_else(value, _else_value), do: value @doc """ If the `value` is `nil` or an empty string, return the `else_value`. If `else_value` is a function, it is called. Otherwise, return the `not_empty_value`. If `not_empty_value` is a function, it is called. """ @spec empty_else( value :: nil | String.t() | any(), not_empty_value :: (any() -> any()) | any(), else_value :: (() -> any()) | any() ) :: any() def empty_else(nil, _, else_value) when is_function(else_value), do: else_value.() def empty_else("", _, else_value) when is_function(else_value), do: else_value.() def empty_else(nil, _, else_value), do: else_value def empty_else("", _, else_value), do: else_value def empty_else(value, not_empty_value, _else_value) when is_function(not_empty_value) do not_empty_value.(value) end def empty_else(_value, not_empty_value, _else_value), do: not_empty_value @doc """ Return the first truthy element in the list, otherwise return nil. """ @spec coalesce(list()) :: nil | any() def coalesce([]), do: nil def coalesce([hd | list]), do: hd || coalesce(list) @doc """ If `value` is truthy, put it in the structure at `path` and return the updated structure. Otherwise return the structure unchanged. """ @spec put_if(structure :: Access.t(), value :: function() | any(), path :: list()) :: Access.t() def put_if(structure, nil, _path), do: structure def put_if(structure, false, _path), do: structure def put_if(structure, value, path) when is_function(value), do: put_in(structure, path, value.()) def put_if(structure, value, path), do: put_in(structure, path, value) @doc """ Call the two argument `function` with `arg1` and `arg2` unless `arg2` is falsy. In case `arg2` is a function, call `arg2.(arg1)`. If the result is not empty, pass the result as the second argument in the call, `function.(arg1, arg2_result)`. For example, only call `put_session/3` if `session_value` is not `nil`. ```elixir conn |> call_if(session_value, & put_session(&1, :session_key, &2)) |> ... ``` """ @spec call_if(arg1 :: any(), arg2 :: nil | false | String.t() | any(), function :: (any(), any() -> any())) :: any() def call_if(arg1, nil, _function), do: arg1 def call_if(arg1, false, _function), do: arg1 def call_if(arg1, "", _function), do: arg1 def call_if(arg1, arg2, function) when is_function(arg2) do call_if(arg1, arg2.(arg1), function) end def call_if(arg1, arg2, function), do: function.(arg1, arg2) end