jsonapi-object-mapper 0.4.0 → 0.5.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 +4 -4
- data/Gemfile.lock +1 -1
- data/{jsonapi_object_mapper.gemspec → jsonapi-object-mapper.gemspec} +1 -1
- data/lib/jsonapi-object-mapper/deserializer/collection.rb +36 -0
- data/lib/{jsonapi_object_mapper → jsonapi-object-mapper}/deserializer/dsl.rb +12 -9
- data/lib/{jsonapi_object_mapper → jsonapi-object-mapper}/deserializer/resource.rb +37 -24
- data/lib/jsonapi-object-mapper/parser/document.rb +26 -0
- data/lib/jsonapi-object-mapper/parser/errors.rb +20 -0
- data/lib/{jsonapi_object_mapper/deserializer → jsonapi-object-mapper/parser}/included_resources.rb +5 -4
- data/lib/{jsonapi_object_mapper → jsonapi-object-mapper}/version.rb +1 -1
- data/lib/jsonapi-object-mapper.rb +9 -0
- data/spec/deserializer/resource_spec.rb +18 -16
- data/spec/spec_helper.rb +1 -1
- metadata +11 -8
- data/lib/jsonapi_object_mapper.rb +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f1ffe31b2bc6266364e9ce22de8f3326fe91d7b6209f421a12a70d9cbe68cdc
|
4
|
+
data.tar.gz: 8603e6c43ae05a4159811a64fe041e2470cdb011b24223b759d405ddbf2e8e01
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d6a3abc3c030e77d4ca61c26610c46772e3fa1f98b7add1f486502e42036998d7f76a7c7896375efd76f336558b6e0e6d0c1bec7611a76727b7cb6101194a27
|
7
|
+
data.tar.gz: 05226150aac758f77f1d8e0af7b13624b97194e42dd075f4e80b544cb674414563a69ed3fc609c42f44585bd47f44c1c8440320c5f79860f15e716d5eb7f02f1
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "jsonapi-object-mapper/parser/errors"
|
4
|
+
|
5
|
+
module JsonAPIObjectMapper
|
6
|
+
module Deserializer
|
7
|
+
class Collection
|
8
|
+
include Enumerable
|
9
|
+
include JsonAPIObjectMapper::Parser::Errors
|
10
|
+
|
11
|
+
attr_accessor :collection_data
|
12
|
+
|
13
|
+
def initialize(parser, klass:)
|
14
|
+
raise ArgumentError, "Must provide a valid resource klass" unless klass.is_a?(Class)
|
15
|
+
raise ArgumentError, "Must provide a parsed document" unless parser.is_a?(JsonAPIObjectMapper::Parser::Document)
|
16
|
+
@errors = parser.errors
|
17
|
+
@collection_data =
|
18
|
+
if document_invalid?
|
19
|
+
[]
|
20
|
+
else
|
21
|
+
Array(parser.document["data"]).map do |doc|
|
22
|
+
klass.new(parser, document: doc)
|
23
|
+
end
|
24
|
+
end.freeze
|
25
|
+
|
26
|
+
freeze
|
27
|
+
end
|
28
|
+
|
29
|
+
def each
|
30
|
+
@collection_data.each do |data|
|
31
|
+
yield data
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "jsonapi_object_mapper/deserializer/included_resources"
|
4
|
-
|
5
3
|
module JsonAPIObjectMapper
|
6
4
|
module Deserializer
|
7
5
|
module DSL
|
@@ -43,13 +41,16 @@ module JsonAPIObjectMapper
|
|
43
41
|
|
44
42
|
module ClassMethods
|
45
43
|
def initialize(*args)
|
46
|
-
super
|
47
44
|
@_class_attributes = {}
|
48
45
|
@_class_relationships = {}
|
46
|
+
super
|
49
47
|
end
|
50
48
|
|
51
49
|
def to_hash
|
52
|
-
|
50
|
+
hashed_relationships = @_class_relationships.map do |key, value|
|
51
|
+
{ key => value.respond_to?(:to_hash) ? value.to_hash : value }
|
52
|
+
end
|
53
|
+
[@_class_attributes, *hashed_relationships].reduce({}, :merge)
|
53
54
|
end
|
54
55
|
alias to_h to_hash
|
55
56
|
|
@@ -73,13 +74,15 @@ module JsonAPIObjectMapper
|
|
73
74
|
end
|
74
75
|
|
75
76
|
def assign_relationship(key, value)
|
76
|
-
block
|
77
|
-
rel_embed_class
|
77
|
+
block = self.class.rel_blocks[key.to_s] || DEFAULT_ATTR_BLOCK
|
78
|
+
rel_embed_class = self.class.rel_options[key.to_s]
|
79
|
+
rel_value = @includes.fetch(value)
|
80
|
+
|
78
81
|
@_class_relationships[key.to_s] =
|
79
|
-
if rel_embed_class.respond_to?(:embed!)
|
80
|
-
block.call(rel_embed_class.embed!(
|
82
|
+
if rel_value != value && rel_embed_class.respond_to?(:embed!)
|
83
|
+
block.call(rel_embed_class.embed!(rel_value))
|
81
84
|
else
|
82
|
-
block.call(
|
85
|
+
block.call(rel_value)
|
83
86
|
end
|
84
87
|
end
|
85
88
|
|
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
4
|
-
require "
|
3
|
+
require "jsonapi-object-mapper/deserializer/dsl"
|
4
|
+
require "jsonapi-object-mapper/deserializer/collection"
|
5
|
+
require "jsonapi-object-mapper/parser/errors"
|
5
6
|
|
6
7
|
module JsonAPIObjectMapper
|
7
8
|
module Deserializer
|
8
9
|
class Resource
|
10
|
+
include JsonAPIObjectMapper::Parser::Errors
|
9
11
|
extend DSL
|
10
12
|
|
11
13
|
class << self
|
@@ -24,37 +26,48 @@ module JsonAPIObjectMapper
|
|
24
26
|
klass.instance_variable_set("@type_block", type_block)
|
25
27
|
end
|
26
28
|
|
27
|
-
def self.
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
parsed_document = document.is_a?(Hash) ? document : ::Oj.load(document)
|
35
|
-
parsed_includes ||= IncludedResources.load(parsed_document["included"])
|
36
|
-
new(parsed_document["data"], parsed_includes)
|
29
|
+
def self.call(document)
|
30
|
+
parser = JsonAPIObjectMapper::Parser::Document.new(document)
|
31
|
+
if parser.document["data"].is_a?(Array) || parser.invalid?
|
32
|
+
Collection.new(parser, klass: self)
|
33
|
+
else
|
34
|
+
new(parser)
|
35
|
+
end
|
37
36
|
end
|
38
37
|
|
39
38
|
def self.embed!(attributes)
|
40
|
-
new("attributes" => attributes)
|
39
|
+
parser = JsonAPIObjectMapper::Parser::Document.new("attributes" => attributes)
|
40
|
+
new(parser)
|
41
41
|
end
|
42
42
|
|
43
|
-
def initialize(
|
43
|
+
def initialize(parser, document: nil)
|
44
44
|
super()
|
45
|
-
|
46
|
-
@
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
45
|
+
raise ArgumentError, "Must provide a parsed document" unless parser.is_a?(JsonAPIObjectMapper::Parser::Document)
|
46
|
+
@errors = parser.errors
|
47
|
+
|
48
|
+
if document_valid?
|
49
|
+
@includes = parser.includes
|
50
|
+
@data = document_data(parser, document)
|
51
|
+
@id = @data["id"]
|
52
|
+
@type = @data["type"]
|
53
|
+
@attributes = @data.fetch("attributes", {})
|
54
|
+
@relationships = @data.fetch("relationships", {})
|
55
|
+
deserialize!
|
56
|
+
end
|
52
57
|
|
53
58
|
freeze
|
54
59
|
end
|
55
60
|
|
61
|
+
def each
|
62
|
+
yield self
|
63
|
+
end
|
64
|
+
|
56
65
|
private
|
57
66
|
|
67
|
+
def document_data(parser, document)
|
68
|
+
document.nil? ? (parser.document["data"] || parser.document) : (document["data"] || document)
|
69
|
+
end
|
70
|
+
|
58
71
|
def deserialize!
|
59
72
|
deserialize_id_type!
|
60
73
|
deserialize_attributes!
|
@@ -62,8 +75,8 @@ module JsonAPIObjectMapper
|
|
62
75
|
end
|
63
76
|
|
64
77
|
def deserialize_id_type!
|
65
|
-
assign_attribute("id", self.class.id_block
|
66
|
-
assign_attribute("type", self.class.type_block
|
78
|
+
assign_attribute("id", self.class.id_block.call(@id)) if self.class.id_block
|
79
|
+
assign_attribute("type", self.class.type_block.call(@type)) if self.class.type_block
|
67
80
|
end
|
68
81
|
|
69
82
|
def deserialize_attributes!
|
@@ -83,7 +96,7 @@ module JsonAPIObjectMapper
|
|
83
96
|
|
84
97
|
def initialize_relationship(rel_type, rel_value)
|
85
98
|
return unless include_relationship?(rel_type)
|
86
|
-
assign_relationship(rel_type,
|
99
|
+
assign_relationship(rel_type, rel_value["data"])
|
87
100
|
end
|
88
101
|
end
|
89
102
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "jsonapi-object-mapper/parser/included_resources"
|
4
|
+
require "jsonapi-object-mapper/parser/errors"
|
5
|
+
|
6
|
+
module JsonAPIObjectMapper
|
7
|
+
module Parser
|
8
|
+
class Document
|
9
|
+
include Errors
|
10
|
+
|
11
|
+
attr_accessor :document, :includes
|
12
|
+
|
13
|
+
def initialize(document)
|
14
|
+
@document = document.is_a?(Hash) ? document : ::Oj.load(document)
|
15
|
+
@includes = IncludedResources.load(@document["included"])
|
16
|
+
@errors = deserialize_errors!.freeze
|
17
|
+
freeze
|
18
|
+
end
|
19
|
+
|
20
|
+
def deserialize_errors!
|
21
|
+
return [] unless @document.key?("errors")
|
22
|
+
Set.new(@document["errors"]) { |error| OpenStruct.new(error) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JsonAPIObjectMapper
|
4
|
+
module Parser
|
5
|
+
module Errors
|
6
|
+
attr_accessor :errors
|
7
|
+
|
8
|
+
def valid?
|
9
|
+
@errors.nil? || @errors.empty?
|
10
|
+
end
|
11
|
+
alias document_valid? valid?
|
12
|
+
|
13
|
+
def invalid?
|
14
|
+
!valid?
|
15
|
+
end
|
16
|
+
alias errors? invalid?
|
17
|
+
alias document_invalid? invalid?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/{jsonapi_object_mapper/deserializer → jsonapi-object-mapper/parser}/included_resources.rb
RENAMED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module JsonAPIObjectMapper
|
4
|
-
module
|
4
|
+
module Parser
|
5
5
|
class IncludedResources
|
6
6
|
extend Forwardable
|
7
7
|
|
@@ -15,14 +15,15 @@ module JsonAPIObjectMapper
|
|
15
15
|
|
16
16
|
def initialize(included_resources = [])
|
17
17
|
included_resources ||= []
|
18
|
-
|
19
18
|
@resource = included_resources.each_with_object({}) do |include, hash|
|
20
19
|
hash[format_key(include)] = include["attributes"]
|
21
20
|
end
|
21
|
+
|
22
|
+
freeze
|
22
23
|
end
|
23
24
|
|
24
|
-
def fetch(relationship)
|
25
|
-
@resource.fetch(format_key(relationship), relationship)
|
25
|
+
def fetch(relationship, fallback = nil)
|
26
|
+
@resource.fetch(format_key(relationship), fallback || relationship)
|
26
27
|
end
|
27
28
|
|
28
29
|
def included?(relationship)
|
@@ -21,7 +21,7 @@ module JsonAPIObjectMapper
|
|
21
21
|
attribute :baz
|
22
22
|
end
|
23
23
|
|
24
|
-
actual = klass.
|
24
|
+
actual = klass.call(payload)
|
25
25
|
expect(actual.foo).to eq("bar")
|
26
26
|
expect(actual.baz).to eq("nas")
|
27
27
|
end
|
@@ -34,7 +34,7 @@ module JsonAPIObjectMapper
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
actual = klass.
|
37
|
+
actual = klass.call(payload)
|
38
38
|
expect(actual.baz).to eq("THIS IS THE REAL DEAL!")
|
39
39
|
end
|
40
40
|
end
|
@@ -55,13 +55,15 @@ module JsonAPIObjectMapper
|
|
55
55
|
|
56
56
|
context "Has included Resource" do
|
57
57
|
let(:included_payload) do
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
58
|
+
payload.merge(
|
59
|
+
"included" => [
|
60
|
+
{
|
61
|
+
"id" => "1",
|
62
|
+
"type" => "photo",
|
63
|
+
"attributes" => { "image" => "good_day_sir.jpg" },
|
64
|
+
},
|
65
|
+
],
|
66
|
+
)
|
65
67
|
end
|
66
68
|
|
67
69
|
it "Should embed the included resource into the relationship" do
|
@@ -69,7 +71,7 @@ module JsonAPIObjectMapper
|
|
69
71
|
has_one :photo
|
70
72
|
end
|
71
73
|
|
72
|
-
actual = klass.
|
74
|
+
actual = klass.call(included_payload)
|
73
75
|
expect(actual.photo).to eq("image" => "good_day_sir.jpg")
|
74
76
|
end
|
75
77
|
|
@@ -82,7 +84,7 @@ module JsonAPIObjectMapper
|
|
82
84
|
has_one :photo, embed_with: photo_klass
|
83
85
|
end
|
84
86
|
|
85
|
-
actual = core_klass.
|
87
|
+
actual = core_klass.call(included_payload)
|
86
88
|
expect(actual.photo).to be_a(photo_klass)
|
87
89
|
expect(actual.photo.image).to eq("good_day_sir.jpg")
|
88
90
|
end
|
@@ -94,11 +96,11 @@ module JsonAPIObjectMapper
|
|
94
96
|
has_one :photo
|
95
97
|
end
|
96
98
|
|
97
|
-
actual = klass.
|
99
|
+
actual = klass.call(payload)
|
98
100
|
expect(actual.photo).to eq("id" => "1", "type" => "photo")
|
99
101
|
end
|
100
102
|
|
101
|
-
it "Should set the
|
103
|
+
it "Should set the default relationship values if no includes can be found" do
|
102
104
|
photo_klass = Class.new(described_class) do
|
103
105
|
attribute :image
|
104
106
|
end
|
@@ -107,9 +109,9 @@ module JsonAPIObjectMapper
|
|
107
109
|
has_one :photo, embed_with: photo_klass
|
108
110
|
end
|
109
111
|
|
110
|
-
actual = core_klass.
|
111
|
-
expect(actual.photo).to be_a(
|
112
|
-
expect(actual.photo
|
112
|
+
actual = core_klass.call(payload)
|
113
|
+
expect(actual.photo).to be_a(Hash)
|
114
|
+
expect(actual.photo).to eq("id" => "1", "type" => "photo")
|
113
115
|
end
|
114
116
|
end
|
115
117
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "bundler/setup"
|
4
|
-
require "
|
4
|
+
require "jsonapi-object-mapper"
|
5
5
|
|
6
6
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require File.expand_path(f) }
|
7
7
|
Dir["#{File.dirname(__FILE__)}/**/*examples.rb"].each { |f| require f }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonapi-object-mapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- George Protacio-Karaszi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-07-
|
11
|
+
date: 2018-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: oj
|
@@ -89,12 +89,15 @@ files:
|
|
89
89
|
- Rakefile
|
90
90
|
- bin/console
|
91
91
|
- bin/setup
|
92
|
-
-
|
93
|
-
- lib/
|
94
|
-
- lib/
|
95
|
-
- lib/
|
96
|
-
- lib/
|
97
|
-
- lib/
|
92
|
+
- jsonapi-object-mapper.gemspec
|
93
|
+
- lib/jsonapi-object-mapper.rb
|
94
|
+
- lib/jsonapi-object-mapper/deserializer/collection.rb
|
95
|
+
- lib/jsonapi-object-mapper/deserializer/dsl.rb
|
96
|
+
- lib/jsonapi-object-mapper/deserializer/resource.rb
|
97
|
+
- lib/jsonapi-object-mapper/parser/document.rb
|
98
|
+
- lib/jsonapi-object-mapper/parser/errors.rb
|
99
|
+
- lib/jsonapi-object-mapper/parser/included_resources.rb
|
100
|
+
- lib/jsonapi-object-mapper/version.rb
|
98
101
|
- spec/deserializer/resource_spec.rb
|
99
102
|
- spec/jsonapi_object_mapper_spec.rb
|
100
103
|
- spec/spec_helper.rb
|