simple_jsonapi 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rubocop.yml +131 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile +5 -0
- data/Jenkinsfile +92 -0
- data/LICENSE.txt +22 -0
- data/README.md +532 -0
- data/Rakefile +10 -0
- data/lib/simple_jsonapi.rb +112 -0
- data/lib/simple_jsonapi/definition/attribute.rb +45 -0
- data/lib/simple_jsonapi/definition/base.rb +50 -0
- data/lib/simple_jsonapi/definition/concerns/has_links_object.rb +36 -0
- data/lib/simple_jsonapi/definition/concerns/has_meta_object.rb +36 -0
- data/lib/simple_jsonapi/definition/error.rb +70 -0
- data/lib/simple_jsonapi/definition/error_source.rb +29 -0
- data/lib/simple_jsonapi/definition/link.rb +27 -0
- data/lib/simple_jsonapi/definition/meta.rb +27 -0
- data/lib/simple_jsonapi/definition/relationship.rb +60 -0
- data/lib/simple_jsonapi/definition/resource.rb +104 -0
- data/lib/simple_jsonapi/error_serializer.rb +76 -0
- data/lib/simple_jsonapi/errors/bad_request.rb +11 -0
- data/lib/simple_jsonapi/errors/exception_serializer.rb +6 -0
- data/lib/simple_jsonapi/errors/wrapped_error.rb +35 -0
- data/lib/simple_jsonapi/errors/wrapped_error_serializer.rb +35 -0
- data/lib/simple_jsonapi/helpers/exceptions.rb +39 -0
- data/lib/simple_jsonapi/helpers/serializer_inferrer.rb +136 -0
- data/lib/simple_jsonapi/helpers/serializer_methods.rb +36 -0
- data/lib/simple_jsonapi/node/attributes.rb +51 -0
- data/lib/simple_jsonapi/node/base.rb +91 -0
- data/lib/simple_jsonapi/node/data/collection.rb +25 -0
- data/lib/simple_jsonapi/node/data/singular.rb +26 -0
- data/lib/simple_jsonapi/node/document/base.rb +62 -0
- data/lib/simple_jsonapi/node/document/collection.rb +17 -0
- data/lib/simple_jsonapi/node/document/errors.rb +17 -0
- data/lib/simple_jsonapi/node/document/singular.rb +17 -0
- data/lib/simple_jsonapi/node/error.rb +55 -0
- data/lib/simple_jsonapi/node/error_source.rb +40 -0
- data/lib/simple_jsonapi/node/errors.rb +28 -0
- data/lib/simple_jsonapi/node/included.rb +45 -0
- data/lib/simple_jsonapi/node/object_links.rb +40 -0
- data/lib/simple_jsonapi/node/object_meta.rb +40 -0
- data/lib/simple_jsonapi/node/relationship.rb +79 -0
- data/lib/simple_jsonapi/node/relationship_data/base.rb +53 -0
- data/lib/simple_jsonapi/node/relationship_data/collection.rb +32 -0
- data/lib/simple_jsonapi/node/relationship_data/singular.rb +33 -0
- data/lib/simple_jsonapi/node/relationships.rb +60 -0
- data/lib/simple_jsonapi/node/resource/base.rb +21 -0
- data/lib/simple_jsonapi/node/resource/full.rb +49 -0
- data/lib/simple_jsonapi/node/resource/linkage.rb +25 -0
- data/lib/simple_jsonapi/parameters/fields_spec.rb +45 -0
- data/lib/simple_jsonapi/parameters/include_spec.rb +57 -0
- data/lib/simple_jsonapi/parameters/sort_spec.rb +107 -0
- data/lib/simple_jsonapi/serializer.rb +89 -0
- data/lib/simple_jsonapi/version.rb +3 -0
- data/simple_jsonapi.gemspec +29 -0
- data/test/errors/bad_request_test.rb +34 -0
- data/test/errors/error_serializer_test.rb +229 -0
- data/test/errors/exception_serializer_test.rb +25 -0
- data/test/errors/wrapped_error_serializer_test.rb +91 -0
- data/test/errors/wrapped_error_test.rb +44 -0
- data/test/parameters/fields_spec_test.rb +56 -0
- data/test/parameters/include_spec_test.rb +58 -0
- data/test/parameters/sort_spec_test.rb +65 -0
- data/test/resources/attributes_test.rb +109 -0
- data/test/resources/extras_test.rb +70 -0
- data/test/resources/id_and_type_test.rb +76 -0
- data/test/resources/inclusion_test.rb +134 -0
- data/test/resources/links_test.rb +63 -0
- data/test/resources/meta_test.rb +49 -0
- data/test/resources/relationships_test.rb +262 -0
- data/test/resources/sorting_test.rb +79 -0
- data/test/resources/sparse_fieldset_test.rb +160 -0
- data/test/root_objects_test.rb +165 -0
- data/test/test_helper.rb +31 -0
- metadata +235 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
# Represents a single relationship on a resource
|
2
|
+
#
|
3
|
+
# @!attribute [r] name
|
4
|
+
# @return [Symbol]
|
5
|
+
# @!attribute [r] cardinality
|
6
|
+
# @return [:singular,:collection]
|
7
|
+
# @!attribute [r] serializer_inferrer
|
8
|
+
# @return [SerializerInferrer]
|
9
|
+
# @!attribute [r] description
|
10
|
+
# @return [String]
|
11
|
+
# @!attribute [r] data_definition
|
12
|
+
# @return [Proc]
|
13
|
+
class SimpleJsonapi::Definition::Relationship < SimpleJsonapi::Definition::Base
|
14
|
+
include SimpleJsonapi::Definition::Concerns::HasLinksObject
|
15
|
+
include SimpleJsonapi::Definition::Concerns::HasMetaObject
|
16
|
+
|
17
|
+
attr_reader :name, :cardinality, :serializer_inferrer, :description, :data_definition
|
18
|
+
|
19
|
+
# @param name [Symbol]
|
20
|
+
# @param cardinality [Symbol] +:singular+, +:collection+
|
21
|
+
# @param description [String]
|
22
|
+
# @yieldparam resource [Object]
|
23
|
+
# @yieldreturn [Object,Array<Object>] The related resource or resources
|
24
|
+
# @option (see Definition::Base#initialize)
|
25
|
+
def initialize(name, cardinality:, description: nil, **options, &block)
|
26
|
+
super
|
27
|
+
|
28
|
+
unless %i[singular collection].include?(cardinality)
|
29
|
+
raise ArgumentError, "Cardinality must be :singular or :collection"
|
30
|
+
end
|
31
|
+
|
32
|
+
@name = name.to_sym
|
33
|
+
@cardinality = cardinality.to_sym
|
34
|
+
@description = description.to_s.presence
|
35
|
+
@serializer_inferrer = SimpleJsonapi::SerializerInferrer.wrap(options[:serializer])
|
36
|
+
|
37
|
+
instance_eval(&block) if block_given?
|
38
|
+
|
39
|
+
data { |resource| resource.public_send(name) } unless data_definition
|
40
|
+
end
|
41
|
+
|
42
|
+
private def initialize_dup(new_def)
|
43
|
+
super
|
44
|
+
# name and cardinality are symbols, can't be duped
|
45
|
+
# serializer_inferrer doesn't need to be duped?
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [void]
|
49
|
+
def data(&block)
|
50
|
+
@data_definition = block
|
51
|
+
end
|
52
|
+
|
53
|
+
def singular?
|
54
|
+
cardinality == :singular
|
55
|
+
end
|
56
|
+
|
57
|
+
def collection?
|
58
|
+
cardinality == :collection
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# Represents a single resource object.
|
2
|
+
#
|
3
|
+
# @!attribute [r] id_definition
|
4
|
+
# @return [Proc]
|
5
|
+
# @!attribute [r] type_definition
|
6
|
+
# @return [Proc]
|
7
|
+
# @!attribute [r] attribute_definitions
|
8
|
+
# @return [Hash{Symbol => Attribute}]
|
9
|
+
# @!attribute [r] relationship_definitions
|
10
|
+
# @return [Hash{Symbol => Relationship}]
|
11
|
+
class SimpleJsonapi::Definition::Resource < SimpleJsonapi::Definition::Base
|
12
|
+
include SimpleJsonapi::Definition::Concerns::HasLinksObject
|
13
|
+
include SimpleJsonapi::Definition::Concerns::HasMetaObject
|
14
|
+
|
15
|
+
attr_reader :id_definition, :type_definition, :attribute_definitions, :relationship_definitions
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
super
|
19
|
+
@id_definition = wrap_in_proc(&:id)
|
20
|
+
@type_definition = wrap_in_proc do |resource|
|
21
|
+
resource.class.name.demodulize.underscore.pluralize
|
22
|
+
end
|
23
|
+
|
24
|
+
@attribute_definitions = {}
|
25
|
+
@relationship_definitions = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
private def initialize_dup(new_def)
|
29
|
+
super
|
30
|
+
new_def.instance_variable_set(:@id_definition, @id_definition.dup) unless @id_definition.nil?
|
31
|
+
new_def.instance_variable_set(:@type_definition, @type_definition.dup) unless @type_definition.nil?
|
32
|
+
|
33
|
+
unless @attribute_definitions.nil?
|
34
|
+
new_def.instance_variable_set(:@attribute_definitions, @attribute_definitions.dup)
|
35
|
+
end
|
36
|
+
|
37
|
+
unless @relationship_definitions.nil?
|
38
|
+
new_def.instance_variable_set(:@relationship_definitions, @relationship_definitions.dup)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# @overload id(&block)
|
43
|
+
# @overload id(value)
|
44
|
+
# @yieldparam resource [Object]
|
45
|
+
# @yieldreturn [String]
|
46
|
+
# @return [void]
|
47
|
+
def id(*args, &block)
|
48
|
+
@id_definition = wrap_in_proc(*args, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
# @overload type(&block)
|
52
|
+
# @overload type(value)
|
53
|
+
# @yieldparam resource [Object]
|
54
|
+
# @yieldreturn [String]
|
55
|
+
# @return [void]
|
56
|
+
def type(*args, &block)
|
57
|
+
@type_definition = wrap_in_proc(*args, &block)
|
58
|
+
end
|
59
|
+
|
60
|
+
# @overload attribute(name, type: nil, description: nil, **options)
|
61
|
+
# @overload attribute(name, type: nil, description: nil, **options, &block)
|
62
|
+
# @option (see Definition::Base#initialize)
|
63
|
+
# @option options [Symbol] type data type
|
64
|
+
# @option options [String] description
|
65
|
+
# @yieldparam resource [Object]
|
66
|
+
# @yieldreturn [#to_json] the value
|
67
|
+
# @return [void]
|
68
|
+
def attribute(name, **options, &block)
|
69
|
+
# Allow type attribute to be defined before throwing error to support non-compliant data_comleteness/v1
|
70
|
+
attribute_definitions[name.to_sym] = SimpleJsonapi::Definition::Attribute.new(name, **options, &block)
|
71
|
+
|
72
|
+
if %w[id type].include?(name.to_s)
|
73
|
+
raise ArgumentError, "`#{name}` is not allowed as an attribute name"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# @overload has_one(name, description: nil, **options, &block)
|
78
|
+
# @param name [Symbol]
|
79
|
+
# @option (see Definition::Relationship#initialize)
|
80
|
+
# @option options [String] description
|
81
|
+
# @yieldparam (see Definition::Relationship#initialize)
|
82
|
+
# @yieldreturn (see Definition::Relationship#initialize)
|
83
|
+
# @return [void]
|
84
|
+
def has_one(name, **options, &block)
|
85
|
+
relationship(name, cardinality: :singular, **options, &block)
|
86
|
+
end
|
87
|
+
|
88
|
+
# @overload has_many(name, description: nil, **options, &block)
|
89
|
+
# @param name [Symbol]
|
90
|
+
# @option (see Definition::Relationship#initialize)
|
91
|
+
# @option options [String] description
|
92
|
+
# @yieldparam (see Definition::Relationship#initialize)
|
93
|
+
# @yieldreturn (see Definition::Relationship#initialize)
|
94
|
+
# @return [void]
|
95
|
+
def has_many(name, **options, &block)
|
96
|
+
relationship(name, cardinality: :collection, **options, &block)
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def relationship(name, **options, &block)
|
102
|
+
relationship_definitions[name.to_sym] = SimpleJsonapi::Definition::Relationship.new(name, options, &block)
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Subclass {ErrorSerializer} to create serializers for specific types of errors.
|
2
|
+
class SimpleJsonapi::ErrorSerializer
|
3
|
+
include SimpleJsonapi::SerializerMethods
|
4
|
+
|
5
|
+
class << self
|
6
|
+
# @overload (see Definition::Error#id)
|
7
|
+
# @return (see Definition::Error#id)
|
8
|
+
def id(*args, **options, &block)
|
9
|
+
definition.id(*args, **options, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
# @overload (see Definition::Error#status)
|
13
|
+
# @return (see Definition::Error#status)
|
14
|
+
def status(*args, **options, &block)
|
15
|
+
definition.status(*args, **options, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @overload (see Definition::Error#code)
|
19
|
+
# @return (see Definition::Error#code)
|
20
|
+
def code(*args, **options, &block)
|
21
|
+
definition.code(*args, **options, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @overload (see Definition::Error#title)
|
25
|
+
# @return (see Definition::Error#title)
|
26
|
+
def title(*args, **options, &block)
|
27
|
+
definition.title(*args, **options, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
# @overload (see Definition::Error#detail)
|
31
|
+
# @return (see Definition::Error#detail)
|
32
|
+
def detail(*args, **options, &block)
|
33
|
+
definition.detail(*args, **options, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @overload (see Definition::Error#source)
|
37
|
+
# @return (see Definition::Error#source)
|
38
|
+
def source(*args, &block)
|
39
|
+
definition.source(*args, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @overload (see Definition::Error#about_link)
|
43
|
+
# @return (see Definition::Error#about_link)
|
44
|
+
def about_link(*args, **options, &block)
|
45
|
+
definition.about_link(*args, **options, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
# @overload (see Definition::Concerns::HasMetaObject#meta)
|
49
|
+
# @return (see Definition::Concerns::HasMetaObject#meta)
|
50
|
+
def meta(name, *args, **options, &block)
|
51
|
+
definition.meta(name, *args, **options, &block)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
self.definition = SimpleJsonapi::Definition::Error.new
|
56
|
+
|
57
|
+
# @return (see Definition::Error#member_definitions)
|
58
|
+
def member_definitions
|
59
|
+
definition.member_definitions
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return (see Definition::Error#source_definitions)
|
63
|
+
def source_definition
|
64
|
+
definition.source_definition
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return (see Definition::Concerns::HasLinksObject#link_definitions)
|
68
|
+
def link_definitions
|
69
|
+
definition.link_definitions
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return (see Definition::Concerns::HasMetaObject#meta_definitions)
|
73
|
+
def meta_definitions
|
74
|
+
definition.meta_definitions
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative 'wrapped_error'
|
2
|
+
|
3
|
+
class SimpleJsonapi::Errors::BadRequest < SimpleJsonapi::Errors::WrappedError
|
4
|
+
def initialize(_cause = nil, **attributes)
|
5
|
+
super attributes.merge(
|
6
|
+
status: "400",
|
7
|
+
code: "bad_request",
|
8
|
+
title: "Bad request",
|
9
|
+
)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module SimpleJsonapi::Errors
|
2
|
+
# A generic serializable error class.
|
3
|
+
class WrappedError
|
4
|
+
# @!attribute [rw] cause
|
5
|
+
# The original error.
|
6
|
+
# @return [Object]
|
7
|
+
# @!attribute [rw] id
|
8
|
+
# @return [String]
|
9
|
+
# @!attribute [rw] status
|
10
|
+
# @return [String]
|
11
|
+
# @!attribute [rw] code
|
12
|
+
# @return [String]
|
13
|
+
# @!attribute [rw] title
|
14
|
+
# @return [String]
|
15
|
+
# @!attribute [rw] detail
|
16
|
+
# @return [String]
|
17
|
+
# @!attribute [rw] source_pointer
|
18
|
+
# @return [String]
|
19
|
+
# @!attribute [rw] source_parameter
|
20
|
+
# @return [String]
|
21
|
+
# @!attribute [rw] about_link
|
22
|
+
# @return [String]
|
23
|
+
attr_accessor :cause, :id, :status, :code, :title, :detail, :source_pointer, :source_parameter, :about_link
|
24
|
+
|
25
|
+
# @param cause [Object] The underlying error
|
26
|
+
# @param attributes [Hash{Symbol => String}]
|
27
|
+
def initialize(cause = nil, **attributes)
|
28
|
+
self.cause = cause
|
29
|
+
|
30
|
+
attributes.each do |name, value|
|
31
|
+
send("#{name}=", value) if respond_to?("#{name}=")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# A serializer for {WrappedError} objects.
|
2
|
+
class SimpleJsonapi::Errors::WrappedErrorSerializer < SimpleJsonapi::ErrorSerializer
|
3
|
+
id(if: ->(err) { err.id.to_s.present? }) do |err|
|
4
|
+
err.id.to_s.presence
|
5
|
+
end
|
6
|
+
|
7
|
+
status(if: ->(err) { err.status.to_s.present? }) do |err|
|
8
|
+
err.status.to_s.presence
|
9
|
+
end
|
10
|
+
|
11
|
+
code(if: ->(err) { err.code.to_s.present? }) do |err|
|
12
|
+
err.code.to_s.presence
|
13
|
+
end
|
14
|
+
|
15
|
+
title(if: ->(err) { err.title.to_s.present? }) do |err|
|
16
|
+
err.title.to_s.presence
|
17
|
+
end
|
18
|
+
|
19
|
+
detail(if: ->(err) { err.detail.to_s.present? }) do |err|
|
20
|
+
err.detail.to_s.presence
|
21
|
+
end
|
22
|
+
|
23
|
+
source do
|
24
|
+
pointer(if: ->(err) { err.source_pointer.to_s.present? }) do |err|
|
25
|
+
err.source_pointer.to_s.presence
|
26
|
+
end
|
27
|
+
parameter(if: ->(err) { err.source_parameter.to_s.present? }) do |err|
|
28
|
+
err.source_parameter.to_s.presence
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
about_link(if: ->(err) { err.about_link.to_s.present? }) do |err|
|
33
|
+
err.about_link.to_s.presence
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module SimpleJsonapi
|
2
|
+
# The error raised when a document does not have a valid JSONAPI structure.
|
3
|
+
class InvalidJsonStructureError < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
# The error raised when the same resource is added to the +included+ member twice.
|
7
|
+
class DuplicateResourceError < StandardError
|
8
|
+
attr_reader :type, :id
|
9
|
+
|
10
|
+
# @param type [String]
|
11
|
+
# @param id [String]
|
12
|
+
# @param msg [String]
|
13
|
+
def initialize(type, id, msg = nil)
|
14
|
+
@type = type
|
15
|
+
@id = id
|
16
|
+
@msg = msg
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
@msg.present? ? @msg : "Resource with type #{type} and id #{id} is already included"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# The error raised when a {SerializerInferrer} cannot find the serializer for a resource or error.
|
25
|
+
class SerializerInferenceError < StandardError
|
26
|
+
attr_reader :object
|
27
|
+
|
28
|
+
# @param object [Object] the resource or error
|
29
|
+
# @param msg [String]
|
30
|
+
def initialize(object, msg = nil)
|
31
|
+
@object = object
|
32
|
+
@msg = msg
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
@msg.present? ? @msg : "Unable to infer serializer for #{object.class}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module SimpleJsonapi
|
2
|
+
# Identifies the serializer class that should be used for a resource or error object.
|
3
|
+
class SerializerInferrer
|
4
|
+
# @!attribute [r] namespace
|
5
|
+
# @return [String]
|
6
|
+
attr_reader :namespace
|
7
|
+
|
8
|
+
# # A {SerializerInferrer} that always returns the serializer class provided in the constructor.
|
9
|
+
# class Constant
|
10
|
+
# # @param serializer_class [Serializer,ErrorSerializer]
|
11
|
+
# def initialize(serializer_class)
|
12
|
+
# @serializer_class = case serializer_class
|
13
|
+
# when Class then serializer_class
|
14
|
+
# else serializer_class.to_s.constantize
|
15
|
+
# end
|
16
|
+
|
17
|
+
# super { |resource| @serializer_class }
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
21
|
+
# @param serializer [SerializerInferrer,Serializer,ErrorSerializer,nil]
|
22
|
+
# @return [SerializerInferrer]
|
23
|
+
def self.wrap(serializer)
|
24
|
+
if serializer.is_a?(SerializerInferrer)
|
25
|
+
serializer
|
26
|
+
elsif serializer.present?
|
27
|
+
klass = serializer_class(serializer)
|
28
|
+
SerializerInferrer.new { |_resource| klass }
|
29
|
+
else
|
30
|
+
SimpleJsonapi.serializer_inferrer
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param explicit_mappings [Hash{Class => Class}] A mapping of resource classes to serializer classes
|
35
|
+
# @param namespace [String] A namespace in which to search for serializer classes
|
36
|
+
# @yieldparam object [Object] The resource or error
|
37
|
+
# @yieldreturn [Class] A serializer class
|
38
|
+
def initialize(explicit_mappings: nil, namespace: nil, &block)
|
39
|
+
@explicit_mappings = {}
|
40
|
+
@explicit_mappings.merge!(explicit_mappings) if explicit_mappings
|
41
|
+
|
42
|
+
@namespace = namespace
|
43
|
+
@infer_proc = block
|
44
|
+
end
|
45
|
+
|
46
|
+
delegate :each, to: :@explicit_mappings
|
47
|
+
|
48
|
+
# @param explicit_mappings [Hash{Class => Class}]
|
49
|
+
# @return [self]
|
50
|
+
def merge(explicit_mappings)
|
51
|
+
explicit_mappings.each do |resource_class, serializer_class|
|
52
|
+
add(resource_class, serializer_class)
|
53
|
+
end
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param resource_class [Class]
|
58
|
+
# @param serializer_class [Class]
|
59
|
+
# @return [void]
|
60
|
+
def add(resource_class, serializer_class)
|
61
|
+
@explicit_mappings[resource_class.name] = serializer_class
|
62
|
+
end
|
63
|
+
|
64
|
+
# @param resource [Object]
|
65
|
+
# @return [Class] A serializer class
|
66
|
+
# @raise [SerializerInferenceError] if a serializer isn't found
|
67
|
+
def infer(resource)
|
68
|
+
serializer = (@infer_proc || default_infer_proc).call(resource)
|
69
|
+
raise SerializerInferenceError.new(resource) unless serializer
|
70
|
+
serializer
|
71
|
+
end
|
72
|
+
|
73
|
+
# @return [Class,nil]
|
74
|
+
def default_serializer
|
75
|
+
unless defined?(@default_serializer)
|
76
|
+
begin
|
77
|
+
@default_serializer = infer(nil)
|
78
|
+
rescue SerializerInferenceError
|
79
|
+
@default_serializer = nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
@default_serializer
|
83
|
+
end
|
84
|
+
|
85
|
+
def default_serializer?
|
86
|
+
default_serializer != nil
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def default_infer_proc
|
92
|
+
@default_infer_proc ||= proc do |resource|
|
93
|
+
serializer = nil
|
94
|
+
|
95
|
+
resource.class.ancestors.find do |ancestor|
|
96
|
+
serializer = find_serializer_by_name(ancestor.name)
|
97
|
+
end
|
98
|
+
|
99
|
+
serializer
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def find_serializer_by_name(name)
|
104
|
+
if @explicit_mappings.key?(name)
|
105
|
+
@explicit_mappings[name]
|
106
|
+
else
|
107
|
+
serializer_name_for_class_name(name).safe_constantize
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def serializer_name_for_class_name(resource_class_name)
|
112
|
+
"#{prefix(resource_class_name)}#{resource_class_name}Serializer"
|
113
|
+
end
|
114
|
+
|
115
|
+
def prefix(resource_class_name)
|
116
|
+
if namespace.blank?
|
117
|
+
""
|
118
|
+
elsif resource_class_name.starts_with?("#{namespace}::")
|
119
|
+
""
|
120
|
+
else
|
121
|
+
"#{namespace}::"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.serializer_class(serializer)
|
126
|
+
case serializer
|
127
|
+
when Class
|
128
|
+
serializer
|
129
|
+
else
|
130
|
+
serializer.to_s.constantize
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
private_class_method :serializer_class
|
135
|
+
end
|
136
|
+
end
|