Current section
Files
Jump to
Current section
Files
lib/case_style.ex
defmodule CaseStyle do
@moduledoc """
Library from converting to different `CaseSyle`s
Currently implemented:
- `CaseStyle.CamelCase`
- `CaseStyle.SnakeCase`
- `CaseStyle.KebabCase`
"""
defstruct tokens: [], from_type: nil
@type t :: %__MODULE__{tokens: CaseStyle.Tokens.t(), from_type: module}
@type nimble_parsec_error ::
{:error, binary, binary, map, {pos_integer, pos_integer}, pos_integer}
@type parser_output :: {:ok, list, binary, map, {pos_integer, pos_integer}, pos_integer}
@callback parse(input :: binary) :: parser_output | nimble_parsec_error
@callback matches?(input :: binary) :: boolean
@callback to_string(CaseStyle.t()) :: binary
@doc """
parse given input with the given module
```elixir
iex> CaseStyle.from_string("snake_case", CaseStyle.SnakeCase)
{:ok,
%CaseStyle{
from_type: CaseStyle.SnakeCase,
tokens: [
%CaseStyle.Tokens.Start{},
%CaseStyle.Tokens.FirstLetter{value: ~c"s"},
%CaseStyle.Tokens.Char{value: ~c"n"},
%CaseStyle.Tokens.Char{value: ~c"a"},
%CaseStyle.Tokens.Char{value: ~c"k"},
%CaseStyle.Tokens.Char{value: ~c"e"},
%CaseStyle.Tokens.Spacing{},
%CaseStyle.Tokens.AfterSpacingChar{value: ~c"c"},
%CaseStyle.Tokens.Char{value: ~c"a"},
%CaseStyle.Tokens.Char{value: ~c"s"},
%CaseStyle.Tokens.Char{value: ~c"e"},
%CaseStyle.Tokens.End{}
]
}
}
```
"""
@spec from_string(binary, module) :: {:ok, CaseStyle.t()} | parser_output | nimble_parsec_error
def from_string(input, module) do
case module.parse(input) do
{:ok, tokens, "", _, _, _} ->
{:ok, %__MODULE__{from_type: module, tokens: tokens}}
{:ok, _, left_over, ctx, line, byte_offset} ->
{:error, "tokens leftover", left_over, ctx, line, byte_offset}
e ->
e
end
end
@doc """
dump given input with the given module
```elixir
iex> input = %CaseStyle{
...> from_type: CaseStyle.SnakeCase,
...> tokens: [
...> %CaseStyle.Tokens.Start{},
...> %CaseStyle.Tokens.FirstLetter{value: ~c"s"},
...> %CaseStyle.Tokens.Char{value: ~c"n"},
...> %CaseStyle.Tokens.Char{value: ~c"a"},
...> %CaseStyle.Tokens.Char{value: ~c"k"},
...> %CaseStyle.Tokens.Char{value: ~c"e"},
...> %CaseStyle.Tokens.Spacing{},
...> %CaseStyle.Tokens.AfterSpacingChar{value: ~c"c"},
...> %CaseStyle.Tokens.Char{value: ~c"a"},
...> %CaseStyle.Tokens.Char{value: ~c"s"},
...> %CaseStyle.Tokens.Char{value: ~c"e"},
...> %CaseStyle.Tokens.End{}
...> ]
...> }
iex> CaseStyle.to_string(input, CaseStyle.CamelCase)
"snakeCase"
```
"""
@spec to_string(CaseStyle.t(), module) :: binary
def to_string(%CaseStyle{} = input, module) do
module.to_string(input)
end
### convenience functions
[
{:snake_to_camel, CaseStyle.SnakeCase, CaseStyle.CamelCase},
{:snake_to_graphql, CaseStyle.SnakeCase, CaseStyle.GraphQLCase},
{:snake_to_kebab, CaseStyle.SnakeCase, CaseStyle.KebabCase},
{:snake_to_pascal, CaseStyle.SnakeCase, CaseStyle.PascalCase},
{:camel_to_snake, CaseStyle.CamelCase, CaseStyle.SnakeCase},
{:camel_to_kebab, CaseStyle.CamelCase, CaseStyle.KebabCase},
{:camel_to_pascal, CaseStyle.CamelCase, CaseStyle.PascalCase},
{:graphql_to_snake, CaseStyle.GraphQLCase, CaseStyle.SnakeCase},
{:kebab_to_snake, CaseStyle.KebabCase, CaseStyle.SnakeCase},
{:kebab_to_camel, CaseStyle.KebabCase, CaseStyle.CamelCase},
{:kebab_to_pascal, CaseStyle.KebabCase, CaseStyle.PascalCase},
{:pascal_to_snake, CaseStyle.PascalCase, CaseStyle.SnakeCase},
{:pascal_to_camel, CaseStyle.PascalCase, CaseStyle.CamelCase},
{:pascal_to_kebab, CaseStyle.PascalCase, CaseStyle.KebabCase}
]
|> Enum.map(fn {func_name, from, to} ->
@spec unquote(func_name)(binary) :: {:ok, binary} | nimble_parsec_error
@doc "Converts from `#{from |> Module.split() |> Enum.join(".")}` to `#{to |> Module.split() |> Enum.join(".")}`"
def unquote(func_name)(input) do
case from_string(input, unquote(from)) do
{:ok, casing} ->
{:ok, to_string(casing, unquote(to))}
e ->
e
end
end
@spec unquote(:"#{func_name}!")(binary) :: binary
@doc "same as `#{func_name}` but return a string on success and raises on error on failure"
def unquote(:"#{func_name}!")(input) do
case from_string(input, unquote(from)) do
{:ok, casing} ->
to_string(casing, unquote(to))
_ ->
raise "Unable to convert #{input}"
end
end
end)
end