defmodule Tipo do @doc """ Returns an item indicating the type of the given value ## Examples iex> Tipo.typeof(34) :number iex> Tipo.typeof(self()) :pid """ def typeof(value) do typeof_atom(value) end # boolean type checkers def nil?(v), do: is_nil(v) def number?(v), do: is_number(v) def integer?(v), do: is_integer(v) def float?(v), do: is_float(v) def bitstring?(v), do: is_bitstring(v) def atom?(v), do: is_atom(v) def function?(v), do: is_function(v) def boolean?(v), do: is_boolean(v) def binary?(v), do: is_binary(v) def list?(v), do: is_list(v) def map?(v), do: is_map(v) def tuple?(v), do: is_tuple(v) def pid?(v), do: is_pid(v) def port?(v), do: is_port(v) def reference?(v), do: is_reference(v) # keywords: lists of two element tuples of the form {atom(), any()} def keyword?(v), do: Keyword.keyword?(v) def regex?(v) def regex?(%Regex{}), do: true def regex?(_), do: false def module?(v) do try do :erlang.get_module_info(v) true rescue ArgumentError -> false end end def struct?(v) do if is_map(v) do ret = try do v.__struct__ # attempt to access hidden key true rescue KeyError -> false end ret else false end end # valid or printable binaries are `strings def string?(v) do is_binary(v) and (String.printable?(v) or String.valid?(v)) end defp typeof_atom(v) do cond do is_nil(v) -> nil is_number(v) -> :number regex?(v) -> :regex # must come before atom module?(v) -> :module is_boolean(v) -> :boolean # must come before atom b/c booleans are atoms is_atom(v) -> :atom string?(v) -> :string is_binary(v) -> :binary is_bitstring(v) -> :bitstring is_function(v) -> :function keyword?(v) -> :keyword # must come before tuple and list, catches all tuples that match the keyword spec is_list(v) -> :list is_tuple(v) -> :tuple struct?(v) -> :struct is_map(v) -> :map is_pid(v) -> :pid is_port(v) -> :port is_reference(v) -> :reference true -> :non_primitive end end end