Skip to content
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

Add CacheCrispies::Base#transform_keys method #55

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,28 @@ end

Put serializer files in `app/serializers/`. For instance this file should be at `app/serializers/cereal_serializer.rb`.

### Snakecase to lower camel case
You can pass a method to `transform_keys` in a serializer which will transform the keys for each attribute unless a `from` attribute was specified for that attribute.
The configuration for `transform_keys` can be inherited, and overridden in the serializers that inherit from another.
```ruby
# app/serializers/base_serializer.rb
class BaseSerializer < CacheCrispies::Base
transform_keys lambda { |key| key.to_s.camelize(:lower) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use a block here rather than a lambda argument?

It just reads a bit better and is a bit more consistent to me to have

transform_keys lambda { |key| key.to_s.camelize(:lower) }

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you just repeated the line I have there... accident yes?
You're meaning to have something like this instead?

transform_keys do |key|
  key.to_s.camelize(:lower)
end

end

# app/serializers/crispy_serializer.rb
class CrispySerializer < BaseSerializer
serialize :id, :created_at
end
```
This will format the keys for each attribute using the passed in lambda like so:
```json
{
"id": "123",
"createdAt": "somedate"
}
```

### In your Rails controller
```ruby
class CerealsController
Expand Down
25 changes: 23 additions & 2 deletions lib/cache_crispies/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,16 @@ def self.file_hashes
).uniq.sort
end

# Sets a method or Proc to transform keys by
#
# @param proc [Proc] a Proc to execute on serializable keys
# @return [Proc] a Proc to execute on the keys
def self.transform_keys(proc = nil)
return @transform_keys ||= proc if proc.present? || @transform_keys.present?

self.superclass.transform_keys if self.superclass.respond_to?(:transform_keys)
end

private

def self.file_hash
Expand Down Expand Up @@ -241,13 +251,14 @@ def self.serialize(
)
attribute_names.flat_map do |attrib|
attrib = attrib&.to_sym
key = attrib
current_nesting = Array(@nesting).dup
current_conditions = Array(@conditions).dup

@attributes <<
Attribute.new(
attrib,
from: from,
transform_key(attrib),
from: from || attrib,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the || attrib needed here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not great at seeing GH notifications, sorry.
I plan to check out your comments here and address in the next week or two.

I'll need to get back in the code here to recall correctly, but I believe this was meant as an improvement.
It seems like it calls for adding a comment to explain why, lol

with: with,
through: through,
to: to,
Expand All @@ -265,5 +276,15 @@ def self.merge(attribute = nil, with: nil)
serialize(nil, from: attribute, with: with)
end
private_class_method :merge

# Transforms an attribute key using a specified Proc
#
# @param key [String] the key for an attribute
# @return [String] a transformed key
def self.transform_key(key)
return key if transform_keys.blank?

transform_keys.call(key)
end
end
end
33 changes: 32 additions & 1 deletion spec/cache_crispies/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@ def visible?
end
end

class BaseSerializer < CacheCrispies::Base
transform_keys lambda { |key| key.to_s.camelize(:lower) }
end

class InheritingSerializer < BaseSerializer
serialize :id, :snake_case
end

class OverriddenSerializer < BaseSerializer
transform_keys lambda { |key| key.to_s.upcase }

serialize :id, :snake_case
end

class MyEngine
def self.root
end
Expand All @@ -56,7 +70,8 @@ class CacheCrispiesEngineTestSerializer < CacheCrispiesTestSerializer
deeply_nested: true,
nutrition_info: OpenStruct.new(calories: 1_000),
organic: 'true',
legal: OpenStruct.new(parent_company: 'Disney probably')
legal: OpenStruct.new(parent_company: 'Disney probably'),
snake_case: 'i was snakecased'
)
end

Expand Down Expand Up @@ -105,6 +120,22 @@ class CacheCrispiesEngineTestSerializer < CacheCrispiesTestSerializer
end
end

describe '.transform_keys' do
let(:serializer) { InheritingSerializer }

it 'transforms attribute keys' do
expect(subject.as_json.keys).to eq(%w[id snakeCase])
end

describe 'overridden serializers' do
let(:serializer) { OverriddenSerializer }

it 'transforms attribute keys' do
expect(subject.as_json.keys).to eq(%w[ID SNAKE_CASE])
end
end
end

describe '.key' do
it 'underscores the demodulized class name by default' do
expect(serializer.key).to eq :cache_crispies_test
Expand Down