mirror of
https://github.com/samsonjs/grape-active_model_serializers.git
synced 2026-04-26 14:47:42 +00:00
Merge pull request #60 from drn/namespace-inference
Namespace inferred serializer resolution.
This commit is contained in:
commit
eb43f68af8
13 changed files with 198 additions and 22 deletions
|
|
@ -1,5 +1,9 @@
|
||||||
inherit_from: .rubocop_todo.yml
|
inherit_from: .rubocop_todo.yml
|
||||||
|
|
||||||
AllCops:
|
AllCops:
|
||||||
Exclude:
|
Exclude:
|
||||||
- Guardfile
|
- Guardfile
|
||||||
- grape-active_model_serializers.gemspec
|
- grape-active_model_serializers.gemspec
|
||||||
|
|
||||||
|
Style/BlockDelimiters:
|
||||||
|
Enabled: false
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,3 @@ Style/Documentation:
|
||||||
# Configuration parameters: Exclude.
|
# Configuration parameters: Exclude.
|
||||||
Style/FileName:
|
Style/FileName:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 4
|
|
||||||
Style/RegexpLiteral:
|
|
||||||
MaxSlashes: 0
|
|
||||||
|
|
|
||||||
|
|
@ -24,5 +24,5 @@ Gem::Specification.new do |gem|
|
||||||
gem.add_development_dependency 'rack-test'
|
gem.add_development_dependency 'rack-test'
|
||||||
gem.add_development_dependency 'rake'
|
gem.add_development_dependency 'rake'
|
||||||
gem.add_development_dependency 'guard-rspec'
|
gem.add_development_dependency 'guard-rspec'
|
||||||
gem.add_development_dependency 'rubocop', '0.28.0'
|
gem.add_development_dependency 'rubocop'
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ module Grape
|
||||||
attr_accessor :controller_name
|
attr_accessor :controller_name
|
||||||
|
|
||||||
def namespace_options
|
def namespace_options
|
||||||
if self.respond_to?(:inheritable_setting)
|
if respond_to?(:inheritable_setting)
|
||||||
inheritable_setting.namespace
|
inheritable_setting.namespace
|
||||||
else
|
else
|
||||||
settings[:namespace] ? settings[:namespace].options : {}
|
settings[:namespace] ? settings[:namespace].options : {}
|
||||||
|
|
@ -17,7 +17,7 @@ module Grape
|
||||||
end
|
end
|
||||||
|
|
||||||
def route_options
|
def route_options
|
||||||
if self.respond_to?(:inheritable_setting)
|
if respond_to?(:inheritable_setting)
|
||||||
inheritable_setting.route
|
inheritable_setting.route
|
||||||
else
|
else
|
||||||
options[:route_options]
|
options[:route_options]
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ module Grape
|
||||||
def options
|
def options
|
||||||
@options ||= (
|
@options ||= (
|
||||||
options = endpoint_options
|
options = endpoint_options
|
||||||
options.merge!(scope: endpoint) unless options.key?(:scope)
|
options[:scope] = endpoint unless options.key?(:scope)
|
||||||
options.merge!(default_root_options) unless options.key?(:root)
|
options.merge!(default_root_options) unless options.key?(:root)
|
||||||
options.merge!(meta_options)
|
options.merge!(meta_options)
|
||||||
options
|
options
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ module Grape
|
||||||
|
|
||||||
def serializer
|
def serializer
|
||||||
@serializer ||= (
|
@serializer ||= (
|
||||||
serializer_klass.new(resource, options) if serializer_klass
|
serializer_class.new(resource, options) if serializer_class
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -16,26 +16,57 @@ module Grape
|
||||||
|
|
||||||
attr_accessor :resource, :options
|
attr_accessor :resource, :options
|
||||||
|
|
||||||
def serializer_klass
|
def serializer_class
|
||||||
serializer_klass = options[:serializer]
|
serializer_class = resource_defined_class
|
||||||
serializer_klass ||= namespaced_resource_serializer_klass
|
serializer_class ||= collection_class
|
||||||
serializer_klass
|
serializer_class ||= options[:serializer]
|
||||||
|
serializer_class ||= namespace_inferred_class
|
||||||
|
serializer_class ||= version_inferred_class
|
||||||
|
serializer_class ||= resource_serializer_class
|
||||||
|
serializer_class
|
||||||
end
|
end
|
||||||
|
|
||||||
def namespaced_resource_serializer_klass
|
def resource_defined_class
|
||||||
"#{namespace}::#{resource_serializer_klass}".constantize
|
resource.serializer_class if resource.respond_to?(:serializer_class)
|
||||||
rescue NameError
|
|
||||||
resource_serializer_klass
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def namespace
|
def collection_class
|
||||||
|
return nil unless resource.respond_to?(:to_ary)
|
||||||
|
ActiveModel::Serializer.config.collection_serializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def namespace_inferred_class
|
||||||
|
return nil unless options[:for]
|
||||||
|
namespace = options[:for].to_s.deconstantize
|
||||||
|
"#{namespace}::#{resource_serializer_klass}".safe_constantize
|
||||||
|
end
|
||||||
|
|
||||||
|
def version_inferred_class
|
||||||
|
"#{version}::#{resource_serializer_klass}".safe_constantize
|
||||||
|
end
|
||||||
|
|
||||||
|
def version
|
||||||
options[:version].try(:classify)
|
options[:version].try(:classify)
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_serializer_klass
|
def resource_serializer_klass
|
||||||
@resource_serializer_klass ||= ActiveModel::Serializer.serializer_for(
|
@resource_serializer_klass ||= [
|
||||||
resource
|
resource_namespace,
|
||||||
)
|
"#{resource_klass}Serializer"
|
||||||
|
].compact.join('::')
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_klass
|
||||||
|
resource.class.name.demodulize
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_namespace
|
||||||
|
klass = resource.class.name.deconstantize
|
||||||
|
klass.empty? ? nil : klass
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_serializer_class
|
||||||
|
ActiveModel::Serializer.serializer_for(resource)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
module Grape
|
module Grape
|
||||||
module ActiveModelSerializers
|
module ActiveModelSerializers
|
||||||
VERSION = '1.4.0'
|
VERSION = '1.4.0'.freeze
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
102
spec/grape/active_model_serializers/serializer_resolver_spec.rb
Normal file
102
spec/grape/active_model_serializers/serializer_resolver_spec.rb
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
# asserts serializer resolution order:
|
||||||
|
# 1. resource_defined_class # V1::UserSerializer
|
||||||
|
# 2. collection_class # CollectionSerializer
|
||||||
|
# 3. options[:serializer] # V2::UserSerializer
|
||||||
|
# 4. namespace_inferred_class # V3::UserSerializer
|
||||||
|
# 5. version_inferred_class # V4::UserSerializer
|
||||||
|
# 6. resource_serializer_class # UserSerializer
|
||||||
|
# 7. missing resource # nil
|
||||||
|
|
||||||
|
describe Grape::ActiveModelSerializers::SerializerResolver do
|
||||||
|
let(:resolver) { described_class.new(resource, options) }
|
||||||
|
let(:resource) { User.new }
|
||||||
|
let(:options) {
|
||||||
|
{
|
||||||
|
serializer: options_serializer_class, # options defined
|
||||||
|
for: V3::UsersApi, # namespace inference
|
||||||
|
version: 'v4' # version inference
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# resource defined
|
||||||
|
let(:resource_defined?) { true }
|
||||||
|
let(:defined_serializer_class) { V1::UserSerializer }
|
||||||
|
# options defined
|
||||||
|
let(:options_serializer_class) { V2::UserSerializer }
|
||||||
|
|
||||||
|
let(:serializer) { resolver.serializer }
|
||||||
|
|
||||||
|
before do
|
||||||
|
if resource_defined?
|
||||||
|
allow(resource).to receive(:respond_to?).and_call_original
|
||||||
|
allow(resource).to receive(:respond_to?).with(:to_ary) { true }
|
||||||
|
allow(resource).to receive(:serializer_class) { defined_serializer_class }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'resource defined' do
|
||||||
|
it 'returns serializer' do
|
||||||
|
expect(serializer).to be_kind_of(defined_serializer_class)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'not resource defined' do
|
||||||
|
let(:resource_defined?) { false }
|
||||||
|
|
||||||
|
context 'resource collection' do
|
||||||
|
let(:resource) { [User.new] }
|
||||||
|
let(:serializer_class) { ActiveModel::Serializer::CollectionSerializer }
|
||||||
|
|
||||||
|
it 'returns serializer' do
|
||||||
|
expect(serializer).to be_kind_of(serializer_class)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'not resource collection' do
|
||||||
|
context 'specified by options' do
|
||||||
|
it 'returns specified serializer' do
|
||||||
|
expect(serializer).to be_kind_of(V2::UserSerializer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'not specified by options' do
|
||||||
|
let(:options) { super().except(:serializer) }
|
||||||
|
|
||||||
|
context 'namespace inferred' do
|
||||||
|
it 'returns inferred serializer' do
|
||||||
|
expect(serializer).to be_kind_of(V3::UserSerializer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'not namespace inferred' do
|
||||||
|
let(:options) { super().except(:for) }
|
||||||
|
|
||||||
|
context 'version inferred' do
|
||||||
|
it 'returns inferred serializer' do
|
||||||
|
expect(serializer).to be_kind_of(V4::UserSerializer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'not version inferred' do
|
||||||
|
let(:options) { super().except(:version) }
|
||||||
|
|
||||||
|
context 'ASM resolved' do
|
||||||
|
it 'returns serializer' do
|
||||||
|
expect(serializer).to be_kind_of(UserSerializer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'not ASM resolved' do
|
||||||
|
let(:resource) { nil }
|
||||||
|
|
||||||
|
it 'returns nil' do
|
||||||
|
expect(serializer).to eq(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
13
spec/support/api/users_api.rb
Normal file
13
spec/support/api/users_api.rb
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
class UsersApi < Grape::API
|
||||||
|
resource :users do
|
||||||
|
desc 'all users'
|
||||||
|
get do
|
||||||
|
[User.new]
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'specified user'
|
||||||
|
get '/:id' do
|
||||||
|
User.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
15
spec/support/api/v3/users_api.rb
Normal file
15
spec/support/api/v3/users_api.rb
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
module V3
|
||||||
|
class UsersApi < Grape::API
|
||||||
|
resource :users do
|
||||||
|
desc 'all users'
|
||||||
|
get do
|
||||||
|
[User.new]
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'specified user'
|
||||||
|
get '/:id' do
|
||||||
|
User.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
5
spec/support/serializers/v2/user_serializer.rb
Normal file
5
spec/support/serializers/v2/user_serializer.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
module V2
|
||||||
|
class UserSerializer < ActiveModel::Serializer
|
||||||
|
attributes :first_name, :last_name, :email
|
||||||
|
end
|
||||||
|
end
|
||||||
5
spec/support/serializers/v3/user_serializer.rb
Normal file
5
spec/support/serializers/v3/user_serializer.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
module V3
|
||||||
|
class UserSerializer < ActiveModel::Serializer
|
||||||
|
attributes :first_name, :last_name, :email
|
||||||
|
end
|
||||||
|
end
|
||||||
5
spec/support/serializers/v4/user_serializer.rb
Normal file
5
spec/support/serializers/v4/user_serializer.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
module V4
|
||||||
|
class UserSerializer < ActiveModel::Serializer
|
||||||
|
attributes :first_name, :last_name, :email
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in a new issue