Current section
Files
Jump to
Current section
Files
lib/ex_optional.ex
defmodule ExOptional do
@moduledoc """
`ExOptional` provides a (minimal) set of functions to work with "Optional" types.
In Elixir, Optional types are really just two-element tuples. Success Optionals look like
`{ :ok, value }`
while failed Optionals have some other value for the first element. (`ExOptional` uses `:no` by default, but largely doesn't care.)
Currently, failed Optionals will only have a value of `nil`. In the future, `ExOptional` may support failed values as well.
"""
@doc """
Test if an Optional is successful.
Returns `true` or `false`.
## Examples
iex> ExOptional.success?( { :ok, 123 } )
true
"""
def success?( opt ) do
case opt do
{ :ok, _ } -> true
_ -> false
end
end
@doc """
Test if an Optional is failed.
Returns `true` or `false`.
## Examples
iex> ExOptional.fail?( { :ok, 123 } )
false
"""
def fail?( opt ) do
case opt do
{ :no, _ } -> true
_ -> false
end
end
@doc """
Wrap a value as a success Optional.
Returns `{ :ok, value }`.
## Examples
iex> ExOptional.to_optional( 123 )
{ :ok, 123 }
"""
def to_optional( value ) do
case value do
{ :ok, _ } -> value
{ :no, _ } -> value
_ -> { :ok, value }
end
end
@doc """
Unwrap a value from a success Optional.
## Examples
iex> ExOptional.from_optional( { :ok, 123 } )
123
iex> ExOptional.from_optional( { :no, 123 } )
nil
"""
def from_optional( opt ) do
case opt do
{ :ok, val } -> val
{ :no, _ } -> nil
_ -> opt
end
end
@doc """
Apply an Optional to a function.
## Examples
iex> ExOptional.opt_apply( { :ok, [ 1, 2, 3 ] }, &Enum.map/2, fn x -> x * 2 end )
{ :ok, [ 2, 4, 6 ] }
iex> ExOptional.opt_apply( { :no, nil }, &Enum.map/2, fn x -> x * 2 end )
{ :no, nil }
"""
def opt_apply( opt, fun, args ) do
case opt do
{ :ok, value } ->
adjusted_args = [ value | [ args ] ]
{ :ok, apply( fun, adjusted_args ) }
_ ->
{ :no, nil }
end
end
@doc """
Apply an Optional to a function, specified by Module, Function, and Args (MFA).
## Examples
iex> ExOptional.opt_apply( { :ok, [ 1, 2, 3 ] }, Enum, :map, fn x -> x * 2 end )
{ :ok, [ 2, 4, 6 ] }
iex> ExOptional.opt_apply( { :no, nil }, Enum, :map, fn x -> x * 2 end )
{ :no, nil }
"""
def opt_apply( opt, module, fun_atom, args ) do
case opt do
{ :ok, value } ->
adjusted_args = [ value | [ args ] ]
{ :ok, apply( module, fun_atom, adjusted_args ) }
_ ->
{ :no, nil }
end
end
end