-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide camelized option according to v1.1 spec #158
Conversation
camelCase fields: | ||
|
||
``` | ||
config :jsonapi, field_transformation: :camelize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ought this to be the default going forward, or do you think that explicit configuration is more ideal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kind of goes back to this discussion but I agree it probably should be the default going forward. Other libraries like ja_serializer also assume the default according to the jsonapi spec. I'll wait for @doomspork's thoughts as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is the JSONAPI default, we should follow suit 👌
lib/jsonapi/utils/string.ex
Outdated
def camelize(value) when is_binary(value) do | ||
case Regex.split(~r{([a-zA-Z0-9])(?<delimeter>[-_])([a-zA-Z0-9])}, to_string(value), on: [:delimeter]) do | ||
words -> | ||
[h | t] = words |> Enum.filter(&(&1 != "")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we please find another way to express this block of code? The use of pipelines and lists is making this very difficult to grok. It's also strange that we have a case
but don't actually pattern match on things.
Also, do we need Enum.filter(&(&1 != "")
? What example would leave you with an extra empty string? If this is something that occurs I think trim: true
in Regex.split/2
would be a better option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defmodule Example do
@camelize_regex ~r/([a-zA-Z0-9])(?<delimeter>[-_])([a-zA-Z0-9])/
def camelize(value) when is_binary(value) do
with [h | t] when length(t) > 0 <- Regex.split(@camelize_regex, value, on: [:delimeter], trim: true),
capitalized <- Enum.map(t, &String.capitalize/1),
downcased <- String.downcase(h)
do
Enum.join([downcased | capitalized])
else
_ -> value
end
end
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated my example above to use the length(t) > 0
guard because I found an issue with the original code (and mine) using this regex:
Utils.String.camelize("exampleName")
"examplename"
I do not believe we want to downcase strings that are already camelcased.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can also update our regex here to avoid the need for the on: [:delimeter]
(delimiter is spelled wrong in the regex also):
~r/(?<=[a-zA-Z0-9])[-_](?=[a-zA-Z0-9])/
iex> Regex.split(~r/(?<=[a-zA-Z0-9])[-_](?=[a-zA-Z0-9])/, "example_name")
["example", "name"]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@snewcomer / @jherdman I feel this file as gotten to be a bit complicated with lots of functions for each style of formatting. What do you think about simplifying this module a bit?
defmodule Example do
def underscore(value) do
value
|> tokenize()
|> join("_")
end
def dasherize(value) do
value
|> tokenize()
|> join("-")
end
def camelize(value) do
with [h | t] when length(t) > 0 <- tokenize(value),
capitalized <- Enum.map(t, &String.capitalize/1),
downcased <- String.downcase(h)
do
Enum.join([downcased | capitalized])
else
_ -> value
end
end
defp join(value, joiner), do: Enum.join(value, joiner)
defp tokenize(value) do
replaced_value = String.replace(value, ~r/([a-z])(?=[A-Z])/, "\\1_\\2")
tokens = Regex.split(~r/(?<=[a-zA-Z0-9])[-_](?=[a-zA-Z0-9])/, replaced_value, trim: true)
Enum.map(tokens, &String.downcase/1)
end
end
iex> Example.underscore("example_name")
"example_name"
iex> Example.underscore("example-name")
"example_name"
iex> Example.underscore("exampleName")
"example_name"
iex> Example.dasherize("example-name")
"example-name"
iex> Example.dasherize("example_name")
"example-name"
iex> Example.dasherize("exampleName")
"example-name"
iex> Example.camelize("example_name")
"exampleName"
iex> Example.camelize("example-name")
"exampleName"
iex> Example.camelize("exampleName")
"exampleName"
Happy to open a PR to clean up this util 👍
camelCase fields: | ||
|
||
``` | ||
config :jsonapi, field_transformation: :camelize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is the JSONAPI default, we should follow suit 👌
lib/jsonapi/utils/string.ex
Outdated
Enum.into(value, %{}, &camelize/1) | ||
end | ||
|
||
def camelize({key, value}) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Elsewhere we make use of guards yet with this function we go the if/else
route. Is there a reason we didn't use guards here as well?
def camelize({key, value}) do | |
def camelize({key, value}) when is_map(value) do | |
{camelize(key), camelize(value)} | |
end | |
def camelize({key, value}) | |
{camelize(key), value} | |
end | |
end |
@doomspork @jherdman Lmk what you think about this PR to merge into this base branch. Essentially introduces |
@@ -6,7 +6,7 @@ A project that will render your data models into [JSONAPI Documents](http://json | |||
|
|||
## JSONAPI Support | |||
|
|||
This library implements [version 1.0](https://jsonapi.org/format/1.0/) | |||
This library implements [version 1.1](https://jsonapi.org/format/1.1/) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe this is strictly true, so it may be a bit misleading.
I'll start open a project board that has issues for new JSON:API v1.1 features.
@snewcomer after we merge do you want me to open a PR to refactor the String utils? |
@doomspork Yeah that would work! Just looking for some feedback on this PR before tying this one up. Basically consolidates duplicated logic to get at the value to transform. |
Oh I missed that PR, let me look |
@jherdman Did you want 0.9 released before this PR goes in? |
Yeah, let's do that. I can't seem to find any issues that need to be addressed before a 0.9 release. |
35b1b7c
to
fd14f81
Compare
Alrighty up to date with master and passing tests! All good to merge? |
https://jsonapi.org/format/1.1/
Profile links to follow in another PR.