http-api-tools 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +18 -0
- data/.rspec +3 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +485 -0
- data/Rakefile +4 -0
- data/http-api-tools.gemspec +29 -0
- data/lib/hat/base_json_serializer.rb +107 -0
- data/lib/hat/expanded_relation_includes.rb +77 -0
- data/lib/hat/identity_map.rb +42 -0
- data/lib/hat/json_serializer_dsl.rb +62 -0
- data/lib/hat/model/acts_like_active_model.rb +16 -0
- data/lib/hat/model/attributes.rb +159 -0
- data/lib/hat/model/has_many_array.rb +47 -0
- data/lib/hat/model/transformers/date_time_transformer.rb +31 -0
- data/lib/hat/model/transformers/registry.rb +55 -0
- data/lib/hat/model.rb +2 -0
- data/lib/hat/nesting/json_serializer.rb +45 -0
- data/lib/hat/nesting/relation_loader.rb +89 -0
- data/lib/hat/relation_includes.rb +140 -0
- data/lib/hat/serializer_registry.rb +27 -0
- data/lib/hat/sideloading/json_deserializer.rb +121 -0
- data/lib/hat/sideloading/json_deserializer_mapping.rb +27 -0
- data/lib/hat/sideloading/json_serializer.rb +125 -0
- data/lib/hat/sideloading/relation_sideloader.rb +79 -0
- data/lib/hat/sideloading/sideload_map.rb +54 -0
- data/lib/hat/type_key_resolver.rb +27 -0
- data/lib/hat/version.rb +3 -0
- data/lib/hat.rb +9 -0
- data/reports/empty.png +0 -0
- data/reports/minus.png +0 -0
- data/reports/plus.png +0 -0
- data/spec/hat/expanded_relation_includes_spec.rb +32 -0
- data/spec/hat/identity_map_spec.rb +31 -0
- data/spec/hat/model/attributes_spec.rb +170 -0
- data/spec/hat/model/has_many_array_spec.rb +48 -0
- data/spec/hat/model/transformers/date_time_transformer_spec.rb +36 -0
- data/spec/hat/model/transformers/registry_spec.rb +53 -0
- data/spec/hat/nesting/json_serializer_spec.rb +173 -0
- data/spec/hat/relation_includes_spec.rb +185 -0
- data/spec/hat/sideloading/json_deserializer_spec.rb +93 -0
- data/spec/hat/sideloading/json_serializer_performance_spec.rb +51 -0
- data/spec/hat/sideloading/json_serializer_spec.rb +185 -0
- data/spec/hat/sideloading/sideload_map_spec.rb +59 -0
- data/spec/hat/support/company_deserializer_mapping.rb +11 -0
- data/spec/hat/support/person_deserializer_mapping.rb +9 -0
- data/spec/hat/support/spec_models.rb +89 -0
- data/spec/hat/support/spec_nesting_serializers.rb +41 -0
- data/spec/hat/support/spec_sideloading_serializers.rb +41 -0
- data/spec/hat/type_key_resolver_spec.rb +19 -0
- data/spec/spec_helper.rb +8 -0
- metadata +214 -0
@@ -0,0 +1,93 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'hat/sideloading/json_deserializer'
|
5
|
+
require 'hat/support/company_deserializer_mapping'
|
6
|
+
require 'hat/support/person_deserializer_mapping'
|
7
|
+
|
8
|
+
module Hat
|
9
|
+
|
10
|
+
module Sideloading
|
11
|
+
|
12
|
+
describe JsonDeserializer do
|
13
|
+
|
14
|
+
let(:json) do
|
15
|
+
{
|
16
|
+
'meta' => {
|
17
|
+
'type' => 'company',
|
18
|
+
'root_key' => 'companies'
|
19
|
+
},
|
20
|
+
'companies' => [{
|
21
|
+
'id' => 1,
|
22
|
+
'name' => "Hooroo",
|
23
|
+
'brand' => "We are travellers or something",
|
24
|
+
'links' => {
|
25
|
+
'employees' => [10, 11, 12],
|
26
|
+
'address' => 20,
|
27
|
+
'suppliers' => [30],
|
28
|
+
'parent_company' => 40
|
29
|
+
}
|
30
|
+
}],
|
31
|
+
'linked' => {
|
32
|
+
'people' => [
|
33
|
+
{'id' => 10, 'first_name' => 'Rob', 'links' => { 'employer' => 1 } },
|
34
|
+
{'id' => 11, 'first_name' => 'Stu', 'links' => { 'employer' => 1 } },
|
35
|
+
{'id' => 12, 'first_name' => 'Dan', 'links' => { 'employer' => 1 } },
|
36
|
+
],
|
37
|
+
'addresses' => [
|
38
|
+
{'id' => 20, 'street_address' => "1 Burke Street"}
|
39
|
+
]
|
40
|
+
}
|
41
|
+
|
42
|
+
}
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
let(:company) do
|
47
|
+
JsonDeserializer.new(json).deserialize.first
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "basic deserialization" do
|
51
|
+
|
52
|
+
it "creates model from the root object" do
|
53
|
+
expect(company.id).to eq json['companies'][0]['id']
|
54
|
+
expect(company.name).to eq json['companies'][0]['name']
|
55
|
+
end
|
56
|
+
|
57
|
+
it "can set read-only attributes" do
|
58
|
+
expect(company.brand).to eq json['companies'][0]['brand']
|
59
|
+
end
|
60
|
+
|
61
|
+
it "includes sideloaded has many relationships" do
|
62
|
+
expect(company.employees.size).to eql 3
|
63
|
+
expect(company.employees.first.first_name).to eq json['linked']['people'].first['first_name']
|
64
|
+
end
|
65
|
+
|
66
|
+
it "includes sideloaded has_one relationships" do
|
67
|
+
expect(company.address.street_address).to eq json['linked']['addresses'].first['street_address']
|
68
|
+
end
|
69
|
+
|
70
|
+
it "includes circular relationships" do
|
71
|
+
expect(company.employees.first.employer.name).to eq json['companies'][0]['name']
|
72
|
+
end
|
73
|
+
|
74
|
+
it "has_many relationships without sideloaded data are set to an empty array" do
|
75
|
+
expect(company.suppliers).to eql []
|
76
|
+
end
|
77
|
+
|
78
|
+
it "has_many relationships without sideloaded data have relation_ids attribute set to the ids of the relationship" do
|
79
|
+
expect(company.supplier_ids).to eql [30]
|
80
|
+
end
|
81
|
+
|
82
|
+
it "has_one relationships without sideloaded data are set to nil" do
|
83
|
+
expect(company.parent_company).to eql nil
|
84
|
+
end
|
85
|
+
|
86
|
+
it "has_one relationships without sideloaded data sets the relation_id attribute set to the id" do
|
87
|
+
expect(company.parent_company_id).to eql 40
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ruby-prof'
|
3
|
+
|
4
|
+
module Hat
|
5
|
+
module Sideloading
|
6
|
+
|
7
|
+
# Rudimentary performance profiler - uncomment to run on demand for now
|
8
|
+
|
9
|
+
|
10
|
+
# describe JsonSerializer do
|
11
|
+
|
12
|
+
# let!(:companies) do
|
13
|
+
# start = Time.now
|
14
|
+
# companies = (1..100).map do |company_id|
|
15
|
+
# company = Company.new(id: company_id, name: "Company #{rand(company_id)}")
|
16
|
+
# people = (1..100).map do |person_id|
|
17
|
+
# person = Person.new(id: person_id, first_name: "First #{rand(person_id)}", last_name: "Last #{rand(person_id)}", dob: Date.today, email: 'user@example.com', employer: company)
|
18
|
+
# skills = (1..20).map do |skill_id|
|
19
|
+
# skill = Skill.new(id: skill_id, name: "Skill #{rand(skill_id)}", description: "abc123" * 500, person: person)
|
20
|
+
# end
|
21
|
+
# person.skills = skills
|
22
|
+
# person
|
23
|
+
# end
|
24
|
+
# company.employees = people
|
25
|
+
# company
|
26
|
+
# end
|
27
|
+
# puts "BUILD MODEL: #{(Time.now - start) * 1000} ms"
|
28
|
+
# companies
|
29
|
+
# end
|
30
|
+
|
31
|
+
# it "serializes" do
|
32
|
+
# RubyProf.start
|
33
|
+
# serialized = CompanySerializer.new(companies).includes(:employer, {employees: [:skills]}).as_json
|
34
|
+
# result = RubyProf.stop
|
35
|
+
# printer = RubyProf::CallStackPrinter.new(result)
|
36
|
+
# report_file = File.open(File.expand_path("../../../reports/profile_report.html", __FILE__), "w")
|
37
|
+
# printer.print(report_file)
|
38
|
+
|
39
|
+
# start = Time.now
|
40
|
+
# serialized = CompanySerializer.new(companies).includes(:employer, {employees: [:skills]}).as_json
|
41
|
+
# puts "SERIALIZE: #{(Time.now - start) * 1000} ms"
|
42
|
+
|
43
|
+
# start = Time.now
|
44
|
+
# JSON.fast_generate(serialized)
|
45
|
+
# puts "TO_JSON: #{(Time.now - start) * 1000} ms"
|
46
|
+
|
47
|
+
# end
|
48
|
+
|
49
|
+
# end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'hat/sideloading/json_serializer'
|
5
|
+
|
6
|
+
module Hat
|
7
|
+
module Sideloading
|
8
|
+
|
9
|
+
describe JsonSerializer do
|
10
|
+
|
11
|
+
let(:company) { Company.new(id: 1, name: 'Hooroo') }
|
12
|
+
let(:person) { Person.new(id: 2, first_name: 'Rob', last_name: 'Monie') }
|
13
|
+
let(:skill) { Skill.new(id: 3, name: "JSON Serialization") }
|
14
|
+
let(:skill2) { Skill.new(id: 4, name: "JSON Serialization 2") }
|
15
|
+
|
16
|
+
before do
|
17
|
+
company.employees = [person]
|
18
|
+
person.employer = company
|
19
|
+
person.skills = [skill, skill2]
|
20
|
+
skill.person = person
|
21
|
+
skill2.person = person
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "serialization of data" do
|
25
|
+
context "with a single top-level serializable object that has relationship names different to model class" do
|
26
|
+
|
27
|
+
context "without any includes" do
|
28
|
+
|
29
|
+
let(:serialized) { PersonSerializer.new(person).as_json.with_indifferent_access }
|
30
|
+
let(:serialized_person) { serialized[:people].first }
|
31
|
+
|
32
|
+
it "serializes basic attributes" do
|
33
|
+
expect(serialized_person[:id]).to eql person.id
|
34
|
+
expect(serialized_person[:first_name]).to eql person.first_name
|
35
|
+
expect(serialized_person[:last_name]).to eql person.last_name
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'expect basic attributes with no value' do
|
39
|
+
expect(serialized_person.has_key?(:dob)).to be_true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "serializes attributes defined as methods on the serializer" do
|
43
|
+
expect(serialized_person[:full_name]).to eql "#{person.first_name} #{person.last_name}"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "serializes relationships as ids" do
|
47
|
+
expect(serialized_person[:links][:employer]).to eql person.employer.id
|
48
|
+
expect(serialized_person[:links][:skills]).to eql person.skills.map(&:id)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "doesn't serialize any relationships" do
|
52
|
+
expect(serialized[:linked][:companies]).to be_nil
|
53
|
+
expect(serialized[:linked][:skills]).to be_nil
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
context "with relations specified as includes" do
|
59
|
+
|
60
|
+
let(:serializer) { PersonSerializer.new(person).includes(:employer, {skills: [:person]}) }
|
61
|
+
|
62
|
+
let(:serialized) do
|
63
|
+
serializer.as_json.with_indifferent_access
|
64
|
+
end
|
65
|
+
|
66
|
+
let(:serialized_person) { serialized[:people].first }
|
67
|
+
|
68
|
+
it "serializes relationships as ids" do
|
69
|
+
expect(serialized_person[:links][:employer]).to eql person.employer.id
|
70
|
+
expect(serialized_person[:links][:skills]).to eql person.skills.map(&:id)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "sideloads has_one relationships" do
|
74
|
+
expect(serialized[:linked][:companies].first[:name]).to eql person.employer.name
|
75
|
+
end
|
76
|
+
|
77
|
+
it "sideloads has_many relationships" do
|
78
|
+
expect(serialized[:linked][:skills].first[:name]).to eql person.skills.first.name
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#includes_for_query" do
|
82
|
+
|
83
|
+
let(:includes_for_query) { serializer.includes_for_query }
|
84
|
+
|
85
|
+
it "expands includes for included relationships and has_many relationships for fetching ids" do
|
86
|
+
expect(includes_for_query.find(:employer)).to eq({ employer: [:employees] })
|
87
|
+
expect(includes_for_query.find(:skills)).to eq({ skills: [{ person: [:skills] }] })
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
context "with an array as the serializable object" do
|
97
|
+
|
98
|
+
let(:relation) do
|
99
|
+
[person, second_person]
|
100
|
+
end
|
101
|
+
|
102
|
+
let(:second_person) { Person.new(id: 5, first_name: 'Stu', last_name: 'Liston') }
|
103
|
+
let(:serialized) { JSON.parse(PersonSerializer.new(relation).to_json).with_indifferent_access }
|
104
|
+
|
105
|
+
before do
|
106
|
+
company.employees = [person, second_person]
|
107
|
+
person.employer = company
|
108
|
+
second_person.employer = company
|
109
|
+
person.skills = [skill]
|
110
|
+
second_person.skills = []
|
111
|
+
skill.person = person
|
112
|
+
end
|
113
|
+
|
114
|
+
it "serializes basic attributes of all items in the array" do
|
115
|
+
expect(serialized[:people][0][:id]).to eql person.id
|
116
|
+
expect(serialized[:people][0][:first_name]).to eql person.first_name
|
117
|
+
expect(serialized[:people][0][:last_name]).to eql person.last_name
|
118
|
+
expect(serialized[:people][0][:id]).to eql person.id
|
119
|
+
|
120
|
+
expect(serialized[:people][1][:id]).to eql second_person.id
|
121
|
+
expect(serialized[:people][1][:first_name]).to eql second_person.first_name
|
122
|
+
expect(serialized[:people][1][:last_name]).to eql second_person.last_name
|
123
|
+
expect(serialized[:people][1][:id]).to eql second_person.id
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "meta data" do
|
129
|
+
|
130
|
+
let(:serializer) { PersonSerializer.new(person) }
|
131
|
+
|
132
|
+
it "adds root key" do
|
133
|
+
expect(serializer.as_json[:meta][:root_key]).to eql 'people'
|
134
|
+
end
|
135
|
+
|
136
|
+
it "adds type" do
|
137
|
+
expect(serializer.as_json[:meta][:type]).to eql 'person'
|
138
|
+
end
|
139
|
+
|
140
|
+
it "allows meta data to be added" do
|
141
|
+
serializer.meta(offset: 0, limit: 10)
|
142
|
+
expect(serializer.as_json[:meta][:offset]).to eql 0
|
143
|
+
expect(serializer.as_json[:meta][:limit]).to eql 10
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
describe "limiting sideloadable data" do
|
149
|
+
|
150
|
+
class LimitedSideloadingPersonSerializer < PersonSerializer
|
151
|
+
includable :employer, :skills
|
152
|
+
end
|
153
|
+
|
154
|
+
let(:unlimited_serialized) { PersonSerializer.new(person).includes(:employer, {skills: [:person]}).as_json.with_indifferent_access }
|
155
|
+
|
156
|
+
let(:limited_serialized) do
|
157
|
+
LimitedSideloadingPersonSerializer.new(person).includes(:employer, {skills: [:person]}).as_json.with_indifferent_access
|
158
|
+
end
|
159
|
+
|
160
|
+
it "does not limit sideloading if not limited in serializer" do
|
161
|
+
expect(unlimited_serialized[:linked][:people].first[:id]).to eq person.id
|
162
|
+
end
|
163
|
+
|
164
|
+
it "allows sideloading of includable relations" do
|
165
|
+
expect(limited_serialized[:linked][:skills].first[:name]).to eql person.skills.first.name
|
166
|
+
end
|
167
|
+
|
168
|
+
it "prevents sideloading of non-includable relations" do
|
169
|
+
expect(limited_serialized[:linked][:people]).to be_nil
|
170
|
+
end
|
171
|
+
|
172
|
+
it "includes what is includables in meta" do
|
173
|
+
expect(limited_serialized[:meta][:includable]).to eq 'employer,skills'
|
174
|
+
end
|
175
|
+
|
176
|
+
it "includes what was included in meta" do
|
177
|
+
expect(limited_serialized[:meta][:included]).to eq 'employer,skills'
|
178
|
+
expect(unlimited_serialized[:meta][:included]).to eq 'employer,skills,skills.person'
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'hat/sideloading/sideload_map'
|
3
|
+
|
4
|
+
module Hat
|
5
|
+
module Sideloading
|
6
|
+
|
7
|
+
describe SideloadMap do
|
8
|
+
|
9
|
+
let(:json) do
|
10
|
+
{
|
11
|
+
'meta' => {
|
12
|
+
'root_key' => 'posts'
|
13
|
+
},
|
14
|
+
'posts' => [{
|
15
|
+
'id' => 1,
|
16
|
+
'title' => 'Post Title'
|
17
|
+
}],
|
18
|
+
'linked' => {
|
19
|
+
'images' => [
|
20
|
+
{'id' => 10, 'url' => '1.png' },
|
21
|
+
{'id' => 11, 'url' => '2.png' }
|
22
|
+
],
|
23
|
+
'comments' => [
|
24
|
+
{'id' => 20, 'text' => 'Comment 1'}
|
25
|
+
]
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:sideload_map) { SideloadMap.new(json, 'posts') }
|
32
|
+
|
33
|
+
describe 'getting sideloaded json from the map' do
|
34
|
+
|
35
|
+
it 'returns object at root key' do
|
36
|
+
expect(sideload_map.get('post', 1)['id']).to eql 1
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'retrieves by singular type' do
|
40
|
+
expect(sideload_map.get('image', 10)['id']).to eql 10
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'retrieves by plural type' do
|
44
|
+
expect(sideload_map.get('images', 11)['id']).to eql 11
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'retrieves with string type' do
|
48
|
+
expect(sideload_map.get('comment', 20)['id']).to eql 20
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'returns nil if object not present' do
|
52
|
+
expect(sideload_map.get('foo', 100)).to be_nil
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'hat/model'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
|
7
|
+
class Person
|
8
|
+
|
9
|
+
include Hat::Model::Attributes
|
10
|
+
|
11
|
+
attribute :id
|
12
|
+
attribute :first_name
|
13
|
+
attribute :last_name
|
14
|
+
attribute :dob
|
15
|
+
attribute :email
|
16
|
+
belongs_to :employer
|
17
|
+
has_many :skills
|
18
|
+
|
19
|
+
def employer_id
|
20
|
+
employer.try(:id)
|
21
|
+
end
|
22
|
+
|
23
|
+
#Act like active record for reflectively interogating type info
|
24
|
+
def self.reflections
|
25
|
+
{
|
26
|
+
employer: OpenStruct.new(class_name: 'Company'),
|
27
|
+
skills: OpenStruct.new(class_name: 'Skill')
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
class Company
|
34
|
+
|
35
|
+
include Hat::Model::Attributes
|
36
|
+
|
37
|
+
attribute :id
|
38
|
+
attribute :name
|
39
|
+
attribute :brand, read_only: true
|
40
|
+
has_many :employees
|
41
|
+
has_many :suppliers
|
42
|
+
belongs_to :parent_company
|
43
|
+
belongs_to :address
|
44
|
+
|
45
|
+
|
46
|
+
#Act like active record for reflectively interogating type info
|
47
|
+
def self.reflections
|
48
|
+
{
|
49
|
+
employees: OpenStruct.new(class_name: 'Person'),
|
50
|
+
suppliers: OpenStruct.new(class_name: 'Company'),
|
51
|
+
parent_company: OpenStruct.new(class_name: 'Company'),
|
52
|
+
address: OpenStruct.new(class_name: 'Address')
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
class Skill
|
59
|
+
|
60
|
+
include Hat::Model::Attributes
|
61
|
+
|
62
|
+
attribute :id
|
63
|
+
attribute :name
|
64
|
+
attribute :description
|
65
|
+
belongs_to :person
|
66
|
+
|
67
|
+
def person_id
|
68
|
+
person.try(:id)
|
69
|
+
end
|
70
|
+
|
71
|
+
#Act like active record for reflectively interogating type info
|
72
|
+
def self.reflections
|
73
|
+
{
|
74
|
+
person: OpenStruct.new(class_name: 'Person')
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
class Address
|
81
|
+
|
82
|
+
attr_accessor :id, :street_address
|
83
|
+
|
84
|
+
def initialize(attrs)
|
85
|
+
@id = attrs[:id]
|
86
|
+
@street_address = attrs[:street_address]
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'hat/nesting/json_serializer'
|
2
|
+
|
3
|
+
module Hat
|
4
|
+
module Nesting
|
5
|
+
class PersonSerializer
|
6
|
+
|
7
|
+
include Hat::Nesting::JsonSerializer
|
8
|
+
|
9
|
+
serializes Person
|
10
|
+
attributes :id, :first_name, :last_name, :full_name, :dob, :email
|
11
|
+
has_one :employer
|
12
|
+
has_many :skills
|
13
|
+
|
14
|
+
def full_name
|
15
|
+
"#{serializable.first_name} #{serializable.last_name}"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class CompanySerializer
|
21
|
+
|
22
|
+
include Hat::Nesting::JsonSerializer
|
23
|
+
|
24
|
+
serializes Company
|
25
|
+
attributes :id, :name
|
26
|
+
has_many :employees
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
class SkillSerializer
|
32
|
+
|
33
|
+
include Hat::Nesting::JsonSerializer
|
34
|
+
|
35
|
+
serializes Skill
|
36
|
+
attributes :id, :name, :description
|
37
|
+
has_one :person
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'hat/sideloading/json_serializer'
|
2
|
+
|
3
|
+
module Hat
|
4
|
+
module Sideloading
|
5
|
+
class PersonSerializer
|
6
|
+
|
7
|
+
include Hat::Sideloading::JsonSerializer
|
8
|
+
|
9
|
+
serializes Person
|
10
|
+
attributes :id, :first_name, :last_name, :full_name, :dob, :email
|
11
|
+
has_one :employer
|
12
|
+
has_many :skills
|
13
|
+
|
14
|
+
def full_name
|
15
|
+
"#{serializable.first_name} #{serializable.last_name}"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class CompanySerializer
|
21
|
+
|
22
|
+
include Hat::Sideloading::JsonSerializer
|
23
|
+
|
24
|
+
serializes Company
|
25
|
+
attributes :id, :name
|
26
|
+
has_many :employees
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
class SkillSerializer
|
32
|
+
|
33
|
+
include Hat::Sideloading::JsonSerializer
|
34
|
+
|
35
|
+
serializes Skill
|
36
|
+
attributes :id, :name, :description
|
37
|
+
has_one :person
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'hat/type_key_resolver'
|
3
|
+
|
4
|
+
module Hat
|
5
|
+
|
6
|
+
describe TypeKeyResolver do
|
7
|
+
|
8
|
+
let(:resolver) { TypeKeyResolver.new }
|
9
|
+
|
10
|
+
describe 'resolving class names' do
|
11
|
+
|
12
|
+
it 'correctly resolves the type key multiple times' do
|
13
|
+
expect(resolver.for_class(String)).to eq 'strings'
|
14
|
+
expect(resolver.for_class(String)).to eq 'strings'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/spec/spec_helper.rb
ADDED