Skip to content

Instantly share code, notes, and snippets.

@danhper
Created January 16, 2016 03:17
Show Gist options
  • Save danhper/7520b87d9fd88d66ad05 to your computer and use it in GitHub Desktop.
Save danhper/7520b87d9fd88d66ad05 to your computer and use it in GitHub Desktop.
Avoiding conditional assignments in Elixir
defmodule Waterfall do
def conditional_chain(value, []), do: value
def conditional_chain(value, [{condition, fun}|rest]) when is_function(fun) do
value = if condition,
do: apply_fun(fun, value, condition),
else: value
conditional_chain(value, rest)
end
defp apply_fun(fun, value, condition) when is_function(fun) do
case :erlang.fun_info(fun)[:arity] do
1 -> fun.(value)
2 -> fun.(value, condition)
_ -> raise ArgumentError, "function should have arity of 1 or 2"
end
end
end
defmodule WaterfallExample do
import Waterfall
def git do
# original code
command = "--git-dir=.git fetch --force"
if {1, 7, 1} <= git_version() do
command = command <> " --progress"
end
if opts[:tag] do
command = command <> " --tags"
end
#
# with waterfall
#
command = conditional_chain("--git-dir=.git fetch --force", [
{{1, 7, 1} <= git_version(), &(&1 <> " --progress")},
{opts[:tag], &(&1 <> " --tags")}
])
end
def hex_conn do
# original code
if ip = List.first get_req_header(conn, "x-forwarded-for") do
conn = %{conn | remote_ip: ip(ip, conn.remote_ip)}
end
if proto = List.first get_req_header(conn, "x-forwarded-proto") do
conn = %{conn | scheme: scheme(proto, conn.scheme)}
end
conn
#
# with waterfall
#
conn = conditional_chain(conn, [
{get_first_header(conn, "x-forwarded-for"), &(%{&1 | remote_ip: ip(&2, &1.remote_ip)})},
{get_first_header(conn, "x-forwarded-proto"), &(%{&1 | scheme: scheme(&2, &1.scheme)})}
])
end
def httpoison do
# original code
if Keyword.has_key?(options, :params) do
url = url <> "?" <> URI.encode_query(options[:params])
end
url = process_url(to_string(url))
#
# with waterfall
#
url
|> conditional_chain([{options[:params], &(&1 <> "?" <> URI.encode_query(&2))}])
|> to_string
|> process_url
end
def phoenix do
# original code
path = Keyword.get(opts, :path)
if path, do: path = Plug.Router.Utils.split(path)
alias = Keyword.get(opts, :alias)
if alias, do: alias = Atom.to_string(alias)
#
# with waterfall
#
path = conditional_chain(nil, [
{Keyword.get(opts, :path), fn {_, path} -> Plug.Router.Utils.split(path) end}
])
alias = conditional_chain(nil, [
{Keyword.get(opts, :alias), fn {_, alias} -> Atom.to_string(alias) end}
])
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment