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

[Feat] Add the ability to change key for metadata #362

Merged
merged 2 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,65 @@ UserResource.new([user]).serialize

UserResource.new([user]).serialize(meta: {foo: :bar})
# => '{"users":[{"id":1,"name":"Masafumi OKURA"}],"meta":{"size":1,"foo":"bar"}}'
```

You can change the key for metadata. If you change the key, it also affects the key when you pass `meta` option.

```ruby
# You can change meta key
class UserResourceWithDifferentMetaKey
include Alba::Resource

root_key :user, :users

attributes :id, :name

meta :my_meta do
{foo: :bar}
end
end

UserResourceWithDifferentMetaKey.new([user]).serialize
# => '{"users":[{"id":1,"name":"Masafumi OKURA"}],"my_meta":{"foo":"bar"}}'

UserResourceWithDifferentMetaKey.new([user]).serialize(meta: {extra: 42})
# => '{"users":[{"id":1,"name":"Masafumi OKURA"}],"meta":{"size":1,"extra":42}}'

class UserResourceChangingMetaKeyOnly
include Alba::Resource

root_key :user, :users

attributes :id, :name

meta :my_meta
end

UserResourceChangingMetaKeyOnly.new([user]).serialize
# => '{"users":[{"id":1,"name":"Masafumi OKURA"}]}'

UserResourceChangingMetaKeyOnly.new([user]).serialize(meta: {extra: 42})
# => '{"users":[{"id":1,"name":"Masafumi OKURA"}],"my_meta":{"extra":42}}'
```

It's also possible to remove the key for metadata, resulting a flat structure.

```ruby
class UserResourceRemovingMetaKey
include Alba::Resource

root_key :user, :users

attributes :id, :name

meta nil
end

UserResourceRemovingMetaKey.new([user]).serialize
# => '{"users":[{"id":1,"name":"Masafumi OKURA"}]}'

UserResourceRemovingMetaKey.new([user]).serialize(meta: {extra: 42})
# => '{"users":[{"id":1,"name":"Masafumi OKURA"}],"extra":42}'

# You can set metadata with `meta` option alone

Expand Down
21 changes: 15 additions & 6 deletions lib/alba/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module Resource
# @private
def self.included(base) # rubocop:disable Metrics/MethodLength
super
setup_method_body = 'private def _setup;'
setup_method_body = +'private def _setup;'
base.class_eval do
# Initialize
INTERNAL_VARIABLES.each do |name, initial|
Expand Down Expand Up @@ -111,13 +111,22 @@ def serialize_with(hash)
end

def hash_with_metadata(hash, meta)
return hash if meta.empty? && @_meta.nil?
return hash if meta.empty? && @_meta&.last.nil?

metadata = @_meta ? instance_eval(&@_meta).merge(meta) : meta
hash[:meta] = metadata
key, block = @_meta || :meta

if key
hash[key] = _metadata(block, meta)
else
_metadata(block, meta).each { |k, v| hash[k] = v }
end
hash
end

def _metadata(block, meta)
block ? instance_eval(&block).merge(meta) : meta
end

def serializable_hash_for_collection
if @_collection_key
@object.to_h do |item|
Expand Down Expand Up @@ -446,8 +455,8 @@ def root_key!
end

# Set metadata
def meta(&block)
@_meta = block
def meta(key = :meta, &block)
@_meta = [key, block]
end

# Set layout
Expand Down
85 changes: 85 additions & 0 deletions test/usecases/meta_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,89 @@ def test_it_includes_meta_with_given_meta_option_without_meta_dsl
UserResourceWithoutMeta.new([@user]).serialize(meta: {class: 'MetaTest'})
)
end

class UserResource2
include Alba::Resource

root_key :user, :users

attributes :id, :name

meta :my_meta do
if object.is_a?(Enumerable)
{size: object.size}
else
{foo: :bar}
end
end
end

def test_changing_meta_key
assert_equal(
'{"users":[{"id":1,"name":"Masafumi OKURA"}],"my_meta":{"size":1}}',
UserResource2.new([@user]).serialize
)
end

def test_changing_meta_key_with_meta_ooption
assert_equal(
'{"users":[{"id":1,"name":"Masafumi OKURA"}],"my_meta":{"size":1,"extra":42}}',
UserResource2.new([@user]).serialize(meta: {extra: 42})
)
end

def test_changing_meta_keu_and_overriding_meta
assert_equal(
'{"users":[{"id":1,"name":"Masafumi OKURA"}],"my_meta":{"size":42}}',
UserResource2.new([@user]).serialize(meta: {size: 42})
)
end

class UserResource3
include Alba::Resource

root_key :user, :users

attributes :id, :name

meta :my_meta # Change meta key only
end

def test_changing_meta_key_only
assert_equal(
'{"users":[{"id":1,"name":"Masafumi OKURA"}],"my_meta":{"extra":42}}',
UserResource3.new([@user]).serialize(meta: {extra: 42})
)
end

def test_changing_meta_key_and_eventually_no_meta
assert_equal(
'{"users":[{"id":1,"name":"Masafumi OKURA"}]}',
UserResource3.new([@user]).serialize
)
end

class UserResource4
include Alba::Resource

root_key :user, :users

attributes :id, :name

meta nil # Do not nest meta key
end

def test_meta_without_nesting
assert_equal(
'{"users":[{"id":1,"name":"Masafumi OKURA"}],"extra":42}',
UserResource4.new([@user]).serialize(meta: {extra: 42})
)
end

def test_meta_without_nesting_but_eventually_no_meta
assert_equal(
'{"users":[{"id":1,"name":"Masafumi OKURA"}]}',
UserResource4.new([@user]).serialize
)
end
end