Current section
Files
Jump to
Current section
Files
lib/guardsafe.ex
defmodule Guardsafe do
@vsn "0.3.0"
@doc false
def version, do: @vsn
@moduledoc """
Provides readability-enhancing macros that can safely be used in guard clauses.
## Examples
defmodule MacrofyAllTheThings do
import Guardsafe
require Integer
def magic(number) when number |> nil? do
"Staring into the void..."
end
def magic(number) when number |> even? do
"That's not odd."
end
def magic(number) when number |> divisible_by? 5 do
"High five!"
end
end
iex> MacrofyAllTheThings.magic(8)
"That's not odd."
"""
@doc """
Expands `divisible_by?(number, divisor)` into `rem(number, divisor) == 0`
## Examples
iex> 25 |> divisible_by? 5
true
"""
defmacro divisible_by?(number, divisor) do
quote do
rem(unquote(number), unquote(divisor)) == 0
end
end
require_warning = fn(module) ->
unless module == Kernel, do: "\n\nRemember to `require #{module}` before use."
end
generate_predicates = fn({module, types}) ->
@module String.to_atom "Elixir.#{module}"
types
|> Enum.each fn(type) ->
@predicate String.to_atom("#{type}?")
@function String.to_atom("is_#{type}")
@doc """
Expands `#{@predicate}(term)` into `#{module}.#{@function}(term)`.
#{require_warning.(@module)}
## Examples
iex> some_#{type}_variable |> #{@predicate}
true
"""
defmacro unquote(@predicate)(term) do
quote do
unquote(@module) . unquote(@function)(unquote(term))
end
end
end
end
[
Kernel: ~w(atom binary bitstring boolean float function integer list map nil number pid port reference tuple),
Integer: ~w(even odd),
]
|> Enum.each generate_predicates
@doc """
Expands `function?(term, arity)` into `is_function(term, arity)`
## Examples
iex> &String.to_integer/1 |> function?(2)
false
"""
defmacro function?(term, arity) do
quote do
is_function(unquote(term), unquote(arity))
end
end
end