I created a PR to fix it. I think you may want to create a @type field_name :: atom | binary and use that for consistency. Here’s a PR that fixes the dialyzer issue:
Also I’d generally recommend using String.t() instead of binary if you’re expecting to be dealing with UTF8 strings since String.t() is more descriptive to the reader (even though it’s just an alias for binary). Also I’d settle on either keyword or Keyword.t(), you seem to be using both of them.
@axelson - I’m sorry, I am not yet seeing how this can be true:
`Kojin.require_snake/1` said that it returned only `binary` but
sometimes it returns an atom.
How can this return an atom:
@spec require_snake(atom | binary) :: atom | binary
@doc ~s"""
Ensures the name is snake case, raises `ArgumentError` if not.
## Examples
iex> assert_raise(ArgumentError, "Name must be snake: `FooBar`", fn -> Kojin.require_snake(:FooBar) end)
%ArgumentError{message: "Name must be snake: `FooBar`"}
iex> Kojin.require_snake(:foo_bar)
"foo_bar"
"""
def require_snake(name) when is_binary(name) do
if !Kojin.Id.is_snake(name) do
raise ArgumentError, "Name must be snake: `#{name}`"
end
name
end
def require_snake(name) when is_atom(name), do: require_snake(Atom.to_string(name))
The first always returns name, which is binary (unless it raises an ArgumentError). The second only accepts an atom and calls the first which only returns a binary.
I appreciate your help here. I want to love elixir like others do and right now for me @spec seems to be something I need to learn much more about to get that level of comfort.
BTW: I’ll take your suggestions on keyword vs Keyword.t(). My inconsistency stems from not really knowing what I’m doing, but trying things anyway.
Throwing an error has a special type - no_return(), As far as I know, if function possibly could raise - then possible there will be no_return() output.
However, in those cases dialyzer complains with a message saying that “function has no local return”. I wonder if adding no_return() to possible output types helps.