mirror of
https://github.com/samsonjs/grape-active_model_serializers.git
synced 2026-04-27 14:57:43 +00:00
Merge pull request #59 from drn/refactor
Refactor option and serializer resolution.
This commit is contained in:
commit
f76ec6dcff
6 changed files with 129 additions and 79 deletions
|
|
@ -2,4 +2,6 @@ require 'active_model_serializers'
|
||||||
require 'grape'
|
require 'grape'
|
||||||
require 'grape-active_model_serializers/endpoint_extension'
|
require 'grape-active_model_serializers/endpoint_extension'
|
||||||
require 'grape-active_model_serializers/formatter'
|
require 'grape-active_model_serializers/formatter'
|
||||||
|
require 'grape-active_model_serializers/serializer_resolver'
|
||||||
|
require 'grape-active_model_serializers/options_builder'
|
||||||
require 'grape-active_model_serializers/version'
|
require 'grape-active_model_serializers/version'
|
||||||
|
|
|
||||||
|
|
@ -11,80 +11,20 @@ module Grape
|
||||||
serializer, options
|
serializer, options
|
||||||
).to_json
|
).to_json
|
||||||
else
|
else
|
||||||
Grape::Formatter::Json.call resource, env
|
Grape::Formatter::Json.call(resource, env)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_options(resource, env)
|
def build_options(resource, env)
|
||||||
endpoint = env['api.endpoint']
|
Grape::ActiveModelSerializers::OptionsBuilder.new(
|
||||||
options = build_options_from_endpoint(endpoint)
|
resource, env
|
||||||
|
).options
|
||||||
options[:scope] = endpoint unless options.key?(:scope)
|
|
||||||
|
|
||||||
# ensure we have a root to fallback on
|
|
||||||
if resource.respond_to?(:to_ary) && !options.key?(:root)
|
|
||||||
options[:root] = default_root(endpoint)
|
|
||||||
end
|
|
||||||
|
|
||||||
options.merge(meta_options(env))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_serializer(resource, options)
|
def fetch_serializer(resource, options)
|
||||||
# use serializer specified by options
|
Grape::ActiveModelSerializers::SerializerResolver.new(
|
||||||
serializer = options[:serializer]
|
resource, options
|
||||||
|
).serializer
|
||||||
if serializer.nil?
|
|
||||||
# fetch serializer leverage AMS lookup
|
|
||||||
serializer = ActiveModel::Serializer.serializer_for(resource)
|
|
||||||
# if grape version exists, attempt to apply version namespacing
|
|
||||||
serializer = namespace_serializer(serializer, options[:version])
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil unless serializer
|
|
||||||
|
|
||||||
serializer.new(resource, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
def namespace_serializer(serializer, namespace)
|
|
||||||
"#{namespace.try(:classify)}::#{serializer}".constantize
|
|
||||||
rescue NameError
|
|
||||||
serializer
|
|
||||||
end
|
|
||||||
|
|
||||||
def meta_options(env)
|
|
||||||
options = {}
|
|
||||||
ams_meta = env['ams_meta'] || {}
|
|
||||||
meta = ams_meta.delete(:meta)
|
|
||||||
meta_key = ams_meta.delete(:meta_key)
|
|
||||||
options[:meta_key] = meta_key if meta && meta_key
|
|
||||||
options[:meta] = meta if meta
|
|
||||||
options
|
|
||||||
end
|
|
||||||
|
|
||||||
def build_options_from_endpoint(endpoint)
|
|
||||||
[
|
|
||||||
endpoint.default_serializer_options || {},
|
|
||||||
endpoint.namespace_options,
|
|
||||||
endpoint.route_options,
|
|
||||||
endpoint.options,
|
|
||||||
endpoint.options.fetch(:route_options)
|
|
||||||
].reduce(:merge)
|
|
||||||
end
|
|
||||||
|
|
||||||
# array root is the innermost namespace name ('space') if there is one,
|
|
||||||
# otherwise the route name (e.g. get 'name')
|
|
||||||
def default_root(endpoint)
|
|
||||||
innermost_scope = if endpoint.respond_to?(:namespace_stackable)
|
|
||||||
endpoint.namespace_stackable(:namespace).last
|
|
||||||
else
|
|
||||||
endpoint.settings.peek[:namespace]
|
|
||||||
end
|
|
||||||
|
|
||||||
if innermost_scope
|
|
||||||
innermost_scope.space
|
|
||||||
else
|
|
||||||
endpoint.options[:path][0].to_s.split('/')[-1]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
68
lib/grape-active_model_serializers/options_builder.rb
Normal file
68
lib/grape-active_model_serializers/options_builder.rb
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
module Grape
|
||||||
|
module ActiveModelSerializers
|
||||||
|
class OptionsBuilder
|
||||||
|
def initialize(resource, env)
|
||||||
|
self.resource = resource
|
||||||
|
self.env = env
|
||||||
|
end
|
||||||
|
|
||||||
|
def options
|
||||||
|
@options ||= (
|
||||||
|
options = endpoint_options
|
||||||
|
options.merge!(scope: endpoint) unless options.key?(:scope)
|
||||||
|
options.merge!(default_root_options) unless options.key?(:root)
|
||||||
|
options.merge!(meta_options)
|
||||||
|
options
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_accessor :resource, :env
|
||||||
|
|
||||||
|
def endpoint_options
|
||||||
|
[
|
||||||
|
endpoint.default_serializer_options || {},
|
||||||
|
endpoint.namespace_options,
|
||||||
|
endpoint.route_options,
|
||||||
|
endpoint.options,
|
||||||
|
endpoint.options.fetch(:route_options)
|
||||||
|
].reduce(:merge)
|
||||||
|
end
|
||||||
|
|
||||||
|
def endpoint
|
||||||
|
@endpoint ||= env['api.endpoint']
|
||||||
|
end
|
||||||
|
|
||||||
|
# array root is the innermost namespace name ('space') if there is one,
|
||||||
|
# otherwise the route name (e.g. get 'name')
|
||||||
|
def default_root_options
|
||||||
|
return {} unless resource.respond_to?(:to_ary)
|
||||||
|
|
||||||
|
if innermost_scope
|
||||||
|
{ root: innermost_scope.space }
|
||||||
|
else
|
||||||
|
{ root: endpoint.options[:path].first.to_s.split('/').last }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def innermost_scope
|
||||||
|
if endpoint.respond_to?(:namespace_stackable)
|
||||||
|
endpoint.namespace_stackable(:namespace).last
|
||||||
|
else
|
||||||
|
endpoint.settings.peek[:namespace]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def meta_options
|
||||||
|
options = {}
|
||||||
|
ams_meta = env['ams_meta'] || {}
|
||||||
|
meta = ams_meta[:meta]
|
||||||
|
meta_key = ams_meta[:meta_key]
|
||||||
|
options[:meta] = meta if meta
|
||||||
|
options[:meta_key] = meta_key if meta && meta_key
|
||||||
|
options
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
42
lib/grape-active_model_serializers/serializer_resolver.rb
Normal file
42
lib/grape-active_model_serializers/serializer_resolver.rb
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
module Grape
|
||||||
|
module ActiveModelSerializers
|
||||||
|
class SerializerResolver
|
||||||
|
def initialize(resource, options)
|
||||||
|
self.resource = resource
|
||||||
|
self.options = options
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializer
|
||||||
|
@serializer ||= (
|
||||||
|
serializer_klass.new(resource, options) if serializer_klass
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_accessor :resource, :options
|
||||||
|
|
||||||
|
def serializer_klass
|
||||||
|
serializer_klass = options[:serializer]
|
||||||
|
serializer_klass ||= namespaced_resource_serializer_klass
|
||||||
|
serializer_klass
|
||||||
|
end
|
||||||
|
|
||||||
|
def namespaced_resource_serializer_klass
|
||||||
|
"#{namespace}::#{resource_serializer_klass}".constantize
|
||||||
|
rescue NameError
|
||||||
|
resource_serializer_klass
|
||||||
|
end
|
||||||
|
|
||||||
|
def namespace
|
||||||
|
options[:version].try(:classify)
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_serializer_klass
|
||||||
|
@resource_serializer_klass ||= ActiveModel::Serializer.serializer_for(
|
||||||
|
resource
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -18,10 +18,11 @@ describe Grape::Formatter::ActiveModelSerializers do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let(:env) { { 'api.endpoint' => app.endpoints.first } }
|
||||||
|
let(:options) { described_class.build_options(nil, env) }
|
||||||
|
|
||||||
it 'should read serializer options like "root"' do
|
it 'should read serializer options like "root"' do
|
||||||
expect(
|
expect(options).to include(:root)
|
||||||
described_class.build_options_from_endpoint(app.endpoints.first)
|
|
||||||
).to include(:root)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -65,9 +66,7 @@ describe Grape::Formatter::ActiveModelSerializers do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should read serializer options like "root"' do
|
it 'should read serializer options like "root"' do
|
||||||
expect(
|
expect(options).to include(:root)
|
||||||
described_class.build_options_from_endpoint(endpoint).keys
|
|
||||||
).to include(:root)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,11 @@ describe Grape::Formatter::ActiveModelSerializers do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let(:env) { { 'api.endpoint' => app.endpoints.first } }
|
||||||
|
let(:options) { described_class.build_options(nil, env) }
|
||||||
|
|
||||||
it 'should read serializer options like "root"' do
|
it 'should read serializer options like "root"' do
|
||||||
expect(
|
expect(options).to include(:root)
|
||||||
described_class.build_options_from_endpoint(app.endpoints.first)
|
|
||||||
).to include(:root)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -72,9 +73,7 @@ describe Grape::Formatter::ActiveModelSerializers do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should read serializer options like "root"' do
|
it 'should read serializer options like "root"' do
|
||||||
expect(
|
expect(options).to include(:root)
|
||||||
described_class.build_options_from_endpoint(endpoint).keys
|
|
||||||
).to include(:root)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue