representors 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +18 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +126 -0
- data/LICENSE.md +19 -0
- data/README.md +28 -0
- data/Rakefile +10 -0
- data/lib/representor_support/utilities.rb +39 -0
- data/lib/representors.rb +5 -0
- data/lib/representors/errors.rb +7 -0
- data/lib/representors/field.rb +108 -0
- data/lib/representors/options.rb +67 -0
- data/lib/representors/representor.rb +161 -0
- data/lib/representors/representor_builder.rb +64 -0
- data/lib/representors/representor_hash.rb +59 -0
- data/lib/representors/serialization.rb +4 -0
- data/lib/representors/serialization/deserializer_base.rb +29 -0
- data/lib/representors/serialization/deserializer_factory.rb +13 -0
- data/lib/representors/serialization/hal_deserializer.rb +44 -0
- data/lib/representors/serialization/hal_serializer.rb +91 -0
- data/lib/representors/serialization/hale_deserializer.rb +162 -0
- data/lib/representors/serialization/hale_serializer.rb +110 -0
- data/lib/representors/serialization/serialization_base.rb +27 -0
- data/lib/representors/serialization/serialization_factory_base.rb +54 -0
- data/lib/representors/serialization/serializer_base.rb +20 -0
- data/lib/representors/serialization/serializer_factory.rb +17 -0
- data/lib/representors/transition.rb +130 -0
- data/lib/representors/version.rb +4 -0
- data/spec/fixtures/complex_hal.json +92 -0
- data/spec/fixtures/complex_hale_document.json +81 -0
- data/spec/fixtures/drds_hash.rb +120 -0
- data/spec/fixtures/hale_spec_examples/basic.json +77 -0
- data/spec/fixtures/hale_spec_examples/complex_reference_objects.json +157 -0
- data/spec/fixtures/hale_spec_examples/data.json +17 -0
- data/spec/fixtures/hale_spec_examples/data_objects.json +96 -0
- data/spec/fixtures/hale_spec_examples/link_objects.json +18 -0
- data/spec/fixtures/hale_spec_examples/nested_ref.json +43 -0
- data/spec/fixtures/hale_spec_examples/reference_objects.json +89 -0
- data/spec/fixtures/hale_tutorial_examples/basic_links.json +85 -0
- data/spec/fixtures/hale_tutorial_examples/basic_links_with_orders.json +96 -0
- data/spec/fixtures/hale_tutorial_examples/basic_links_with_references.json +108 -0
- data/spec/fixtures/hale_tutorial_examples/embedded.json +182 -0
- data/spec/fixtures/hale_tutorial_examples/empty.json +1 -0
- data/spec/fixtures/hale_tutorial_examples/enctype.json +14 -0
- data/spec/fixtures/hale_tutorial_examples/final.json +141 -0
- data/spec/fixtures/hale_tutorial_examples/get_link.json +17 -0
- data/spec/fixtures/hale_tutorial_examples/get_link_with_data.json +29 -0
- data/spec/fixtures/hale_tutorial_examples/links.json +11 -0
- data/spec/fixtures/hale_tutorial_examples/links_only.json +3 -0
- data/spec/fixtures/hale_tutorial_examples/meta.json +208 -0
- data/spec/fixtures/hale_tutorial_examples/self_link.json +7 -0
- data/spec/fixtures/single_drd.rb +266 -0
- data/spec/lib/representors/complex_representor_spec.rb +288 -0
- data/spec/lib/representors/field_spec.rb +141 -0
- data/spec/lib/representors/representor_builder_spec.rb +223 -0
- data/spec/lib/representors/representor_spec.rb +285 -0
- data/spec/lib/representors/serialization/deserializer_factory_spec.rb +118 -0
- data/spec/lib/representors/serialization/hal_deserializer_spec.rb +34 -0
- data/spec/lib/representors/serialization/hal_serializer_spec.rb +171 -0
- data/spec/lib/representors/serialization/hale_deserializer_spec.rb +59 -0
- data/spec/lib/representors/serialization/hale_roundtrip_spec.rb +34 -0
- data/spec/lib/representors/serialization/hale_serializer_spec.rb +659 -0
- data/spec/lib/representors/serialization/serializer_factory_spec.rb +108 -0
- data/spec/lib/representors/transition_spec.rb +349 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/basic-hale.json +12 -0
- data/spec/support/hal_representor_shared.rb +206 -0
- data/spec/support/helpers.rb +8 -0
- data/tasks/benchmark.rake +75 -0
- data/tasks/complex_hal_document.json +98 -0
- data/tasks/test_specs.rake +37 -0
- data/tasks/yard.rake +22 -0
- metadata +232 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Representors
|
4
|
+
describe HaleDeserializer do
|
5
|
+
it 'inherits from HalDeserializer' do
|
6
|
+
expect(HaleDeserializer.class.ancestors.include? HalDeserializer)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'provides the media type application/vnd.hale+json' do
|
10
|
+
expect(HaleDeserializer.media_types).to include('application/vnd.hale+json')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'provides the media symbol :hale' do
|
14
|
+
expect(HaleDeserializer.media_symbols).to include(:hale)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#to_representor" do
|
18
|
+
it_behaves_like 'can create a representor from a hal document' do
|
19
|
+
subject(:deserializer) {Representors::HaleDeserializer.new(document)}
|
20
|
+
end
|
21
|
+
|
22
|
+
context '_meta with properties and links' do
|
23
|
+
subject(:deserializer) {Representors::HaleDeserializer.new(document)}
|
24
|
+
let(:semantics) { { 'title' => 'The Neverending Story'}}
|
25
|
+
let(:transition_rel) { 'author'}
|
26
|
+
let(:transition_href) { '/mike'}
|
27
|
+
let(:document) do
|
28
|
+
{
|
29
|
+
'title' => 'The Neverending Story',
|
30
|
+
'_links' => {
|
31
|
+
'author' => {'href' => '/mike'}
|
32
|
+
},
|
33
|
+
'_meta' => {
|
34
|
+
'any' => { 'json' => 'thing'}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
end
|
38
|
+
let(:semantics_field) {deserializer.to_representor.properties}
|
39
|
+
let(:transitions_field) {deserializer.to_representor.transitions}
|
40
|
+
let(:embedded_field) {deserializer.to_representor.embedded }
|
41
|
+
|
42
|
+
it 'return a hash with all the attributes of the document' do
|
43
|
+
expect(semantics_field).to eq(semantics)
|
44
|
+
end
|
45
|
+
it 'Create a transition with the link' do
|
46
|
+
expect(transitions_field.size).to eq(1)
|
47
|
+
expect(transitions_field.first.rel).to eq(transition_rel)
|
48
|
+
expect(transitions_field.first.uri).to eq(transition_href)
|
49
|
+
end
|
50
|
+
it 'does not return any embedded resource' do
|
51
|
+
expect(embedded_field).to be_empty
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Representors
|
4
|
+
|
5
|
+
describe 'Hale round trips' do
|
6
|
+
after do
|
7
|
+
deserialized_representor = HaleDeserializer.new(@file).to_representor
|
8
|
+
serialized_hale = Serialization::HaleSerializer.new(deserialized_representor).to_media_type
|
9
|
+
redeserialized_representor = HaleDeserializer.new(serialized_hale).to_representor
|
10
|
+
reserialized_hale = Serialization::HaleSerializer.new(redeserialized_representor).to_media_type
|
11
|
+
expect(JSON.parse(serialized_hale)).to eq(JSON.parse(reserialized_hale))
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'round trips a simple document' do
|
15
|
+
@file = File.read("#{SPEC_DIR}/support/basic-hale.json")
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'round trips a complex document' do
|
19
|
+
@file = File.read("#{SPEC_DIR}/fixtures/complex_hale_document.json")
|
20
|
+
end
|
21
|
+
|
22
|
+
Dir["#{SPEC_DIR}/fixtures/hale_spec_examples/*.json"].each do |path|
|
23
|
+
it "round trips the hale spec #{path[/hale_spec_examples\/(.*?)\.json/, 1]} document" do
|
24
|
+
@file = File.read(path)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Dir["#{SPEC_DIR}/fixtures/hale_tutorial_examples/*.json"].each do |path|
|
29
|
+
it "round trips the hale tutorial #{path[/hale_tutorial_examples\/(.*?)\.json/, 1]} document" do
|
30
|
+
@file = File.read(path)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,659 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'yaml'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
#TODO: This should only test functionality of this class and not repeat the file hal_spec
|
6
|
+
module Representors
|
7
|
+
describe Serialization::HaleSerializer do
|
8
|
+
before do
|
9
|
+
@base_representor = {
|
10
|
+
protocol: 'http',
|
11
|
+
href: 'www.example.com/drds',
|
12
|
+
id: 'drds',
|
13
|
+
doc: 'doc'
|
14
|
+
}
|
15
|
+
@options = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
subject(:serializer) { SerializerFactory.build(:hale_json, Representor.new(document)) }
|
19
|
+
let(:result) {JSON.parse(serializer.to_media_type(@options))}
|
20
|
+
|
21
|
+
shared_examples "a hale documents attributes" do |representor_hash, media|
|
22
|
+
let(:document) { RepresentorHash.new(representor_hash).merge(@base_representor) }
|
23
|
+
|
24
|
+
representor_hash[:attributes].each do |k, v|
|
25
|
+
it "includes the document attribute #{k} and associated value" do
|
26
|
+
expect(result[k]).to eq(v[:value])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
shared_examples "a hale documents links" do |representor_hash, media|
|
32
|
+
let(:document) { representor_hash.merge(@base_representor) }
|
33
|
+
representor = Representor.new(representor_hash)
|
34
|
+
|
35
|
+
representor.transitions.each do |item|
|
36
|
+
it "includes the document transition #{item}" do
|
37
|
+
expect(result["_links"][item[:rel]]['href']).to eq(item.templated_uri)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
representor.meta_links.each do |transition|
|
42
|
+
it "includes meta link #{transition}" do
|
43
|
+
expect(result["_links"][transition.rel.to_s]['href']).to eq(transition.templated_uri)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
shared_examples "a hale documents embedded hale documents" do |representor_hash, media|
|
49
|
+
let(:document) { representor_hash.merge(@base_representor) }
|
50
|
+
|
51
|
+
representor_hash[:embedded].each do |embed_name, embed|
|
52
|
+
embed[:attributes].each do |k, v|
|
53
|
+
it "includes the document attribute #{k} and associated value" do
|
54
|
+
expect(result["_embedded"][embed_name][k]).to eq(v[:value])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
embed[:transitions].each do |item|
|
58
|
+
it "includes the document attribute #{item} and associated value" do
|
59
|
+
expect(result["_embedded"][embed_name]["_links"][item[:rel]]['href']).to eq(item[:href])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
shared_examples "a hale documents embedded collection" do |representor_hash, media|
|
66
|
+
let(:document) { representor_hash.merge(@base_representor) }
|
67
|
+
|
68
|
+
representor_hash[:embedded].each do |embed_name, embeds|
|
69
|
+
embeds.each_with_index do |embed, index|
|
70
|
+
embed[:attributes].each do |k, v|
|
71
|
+
it "includes the document attribute #{k} and associated value" do
|
72
|
+
expect(result["_embedded"][embed_name][index][k]).to eq(v[:value])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
embed[:transitions].each do |item|
|
76
|
+
it "includes the document attribute #{item} and associated value" do
|
77
|
+
expect(result["_embedded"][embed_name][index]["_links"][item[:rel]]['href']).to eq(item[:href])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#to_media_type' do
|
85
|
+
context 'Document that is empty' do
|
86
|
+
let(:document) { {} }
|
87
|
+
|
88
|
+
it 'returns a hash with no attributes, links or embedded resources' do
|
89
|
+
expect(result).to eq({})
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'Document with only self link' do
|
94
|
+
representor_hash = begin
|
95
|
+
{
|
96
|
+
transitions: [{rel: 'self', href: "www.example.com/coffeebucks/"}]
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
it_behaves_like 'a hale documents links', representor_hash, @options
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'Document with only self and profile link' do
|
104
|
+
representor_hash = begin
|
105
|
+
{
|
106
|
+
links: {
|
107
|
+
profile: 'http://www.example.com/drds/show/DRDs',
|
108
|
+
},
|
109
|
+
transitions: [{rel: 'self', href: "www.example.com/coffeebucks/"}]
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
it_behaves_like 'a hale documents links', representor_hash, @options
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'Document with GET link' do
|
117
|
+
representor_hash = begin
|
118
|
+
{
|
119
|
+
links: {
|
120
|
+
profile: 'http://www.example.com/drds/show/DRDs',
|
121
|
+
},
|
122
|
+
transitions: [
|
123
|
+
{rel: 'self', href: "www.example.com/coffeebucks/"},
|
124
|
+
{rel: "next", href: "www.example.com/coffeebucks?page=2"},
|
125
|
+
{
|
126
|
+
rel: 'orders',
|
127
|
+
href: "www.example.com/coffeebucks{?order_status,page}",
|
128
|
+
descriptors: {
|
129
|
+
"order_status" => {
|
130
|
+
scope: "href",
|
131
|
+
options: {
|
132
|
+
'list' => [
|
133
|
+
"pending_payment",
|
134
|
+
"preparing",
|
135
|
+
"fulfilled"
|
136
|
+
],},
|
137
|
+
:validators => [
|
138
|
+
"in"
|
139
|
+
],
|
140
|
+
cardinality: "multiple",
|
141
|
+
},
|
142
|
+
"page" => {
|
143
|
+
scope: "href",
|
144
|
+
type: "integer",
|
145
|
+
:validators => [
|
146
|
+
{"min" => 1},
|
147
|
+
{"max" => 2},
|
148
|
+
],
|
149
|
+
value: 1
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
]
|
154
|
+
}
|
155
|
+
end
|
156
|
+
|
157
|
+
it_behaves_like 'a hale documents links', representor_hash, @options
|
158
|
+
let(:document) { representor_hash.merge(@base_representor) }
|
159
|
+
it 'has the expected Hale output' do
|
160
|
+
link_data = result["_links"]["orders"]["data"]
|
161
|
+
expect(link_data["order_status"]["scope"]).to eq("href")
|
162
|
+
expect(link_data["order_status"]["in"]).to eq(true)
|
163
|
+
expect(link_data["order_status"]["multi"]).to eq(true)
|
164
|
+
expect(link_data["order_status"]["options"]).to eq([
|
165
|
+
"pending_payment",
|
166
|
+
"preparing",
|
167
|
+
"fulfilled"
|
168
|
+
])
|
169
|
+
|
170
|
+
expect(link_data["page"]["scope"]).to eq("href")
|
171
|
+
expect(link_data["page"]["type"]).to eq("integer")
|
172
|
+
expect(link_data["page"]["min"]).to eq(1)
|
173
|
+
expect(link_data["page"]["max"]).to eq(2)
|
174
|
+
expect(link_data["page"]["value"]).to eq(1)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'Document with POST link' do
|
179
|
+
representor_hash = begin
|
180
|
+
{
|
181
|
+
links: {
|
182
|
+
profile: 'http://www.example.com/drds/show/DRDs',
|
183
|
+
},
|
184
|
+
transitions: [
|
185
|
+
{rel: 'self', href: "www.example.com/coffeebucks/"},
|
186
|
+
{
|
187
|
+
rel: 'place_order',
|
188
|
+
method: 'POST',
|
189
|
+
href: "www.example.com/coffeebucks/orders",
|
190
|
+
descriptors: {
|
191
|
+
"drink_type" => {
|
192
|
+
options: {
|
193
|
+
'list' => [
|
194
|
+
"coffee",
|
195
|
+
"americano",
|
196
|
+
"latte",
|
197
|
+
"mocha",
|
198
|
+
"cappuccino",
|
199
|
+
"macchiato",
|
200
|
+
"espresso"
|
201
|
+
],},
|
202
|
+
:validators => [
|
203
|
+
"in",
|
204
|
+
"required"
|
205
|
+
],
|
206
|
+
cardinality: "multiple",
|
207
|
+
},
|
208
|
+
"iced" => {
|
209
|
+
type: "boolean",
|
210
|
+
value: false
|
211
|
+
},
|
212
|
+
"size" => {
|
213
|
+
type: "integer",
|
214
|
+
field_type: "number",
|
215
|
+
options: {
|
216
|
+
'hash' => {
|
217
|
+
"small" => 8,
|
218
|
+
"medium" => 12,
|
219
|
+
"large" => 16,
|
220
|
+
"extra-large" => 20
|
221
|
+
},},
|
222
|
+
:validators => [
|
223
|
+
"in",
|
224
|
+
"required"
|
225
|
+
],
|
226
|
+
},
|
227
|
+
"shots" => {
|
228
|
+
type: "integer",
|
229
|
+
field_type: "range",
|
230
|
+
:validators => [
|
231
|
+
{"min" => 0},
|
232
|
+
{"max" => 16},
|
233
|
+
],
|
234
|
+
},
|
235
|
+
"decaf" => {
|
236
|
+
type: "integer",
|
237
|
+
field_type: "range",
|
238
|
+
:validators => [
|
239
|
+
{"min" => 0},
|
240
|
+
{"max" => 16},
|
241
|
+
],
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
]
|
246
|
+
}
|
247
|
+
end
|
248
|
+
|
249
|
+
it_behaves_like 'a hale documents links', representor_hash, @options
|
250
|
+
let(:document) { representor_hash.merge(@base_representor) }
|
251
|
+
it 'has the expected Hale output' do
|
252
|
+
link_data = result["_links"]["place_order"]["data"]
|
253
|
+
expect(link_data["drink_type"]["in"]).to eq(true)
|
254
|
+
expect(link_data["drink_type"]["required"]).to eq(true)
|
255
|
+
expect(link_data["drink_type"]["options"]).to eq([
|
256
|
+
"coffee",
|
257
|
+
"americano",
|
258
|
+
"latte",
|
259
|
+
"mocha",
|
260
|
+
"cappuccino",
|
261
|
+
"macchiato",
|
262
|
+
"espresso"
|
263
|
+
])
|
264
|
+
|
265
|
+
expect(link_data["iced"]["type"]).to eq("boolean")
|
266
|
+
expect(link_data["iced"]["value"]).to eq(false)
|
267
|
+
|
268
|
+
expect(link_data["size"]["type"]).to eq("integer:number")
|
269
|
+
expect(link_data["size"]["in"]).to eq(true)
|
270
|
+
expect(link_data["size"]["required"]).to eq(true)
|
271
|
+
expect(link_data["size"]["options"]).to eq([
|
272
|
+
{"small" => 8},
|
273
|
+
{"medium" => 12},
|
274
|
+
{"large" => 16},
|
275
|
+
{"extra-large" => 20}
|
276
|
+
])
|
277
|
+
|
278
|
+
expect(link_data["shots"]["type"]).to eq("integer:range")
|
279
|
+
expect(link_data["shots"]["min"]).to eq(0)
|
280
|
+
expect(link_data["shots"]["max"]).to eq(16)
|
281
|
+
|
282
|
+
expect(link_data["decaf"]["type"]).to eq("integer:range")
|
283
|
+
expect(link_data["decaf"]["min"]).to eq(0)
|
284
|
+
expect(link_data["decaf"]["max"]).to eq(16)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
context 'Document with properties and links' do
|
289
|
+
representor_hash = begin
|
290
|
+
{
|
291
|
+
attributes: {
|
292
|
+
"count" => {value: 3},
|
293
|
+
"total_count" => {value: 6},
|
294
|
+
},
|
295
|
+
transitions: [
|
296
|
+
{rel: 'self', href: "www.example.com/coffeebucks/"},
|
297
|
+
{rel: "next", href: "www.example.com/coffeebucks?page=2"},
|
298
|
+
{
|
299
|
+
rel: 'orders',
|
300
|
+
href: "www.example.com/coffeebucks",
|
301
|
+
descriptors: {
|
302
|
+
"order_status" => {
|
303
|
+
scope: "href",
|
304
|
+
options: {
|
305
|
+
'list' => [
|
306
|
+
"pending_payment",
|
307
|
+
"preparing",
|
308
|
+
"fulfilled"
|
309
|
+
],},
|
310
|
+
:validators => [
|
311
|
+
"in"
|
312
|
+
],
|
313
|
+
cardinality: "multiple",
|
314
|
+
},
|
315
|
+
"page" => {
|
316
|
+
scope: "href",
|
317
|
+
type: "integer",
|
318
|
+
:validators => [
|
319
|
+
{"min" => 1},
|
320
|
+
{"max" => 2},
|
321
|
+
],
|
322
|
+
value: 1
|
323
|
+
}
|
324
|
+
}
|
325
|
+
}
|
326
|
+
]
|
327
|
+
}
|
328
|
+
end
|
329
|
+
|
330
|
+
it_behaves_like 'a hale documents attributes', representor_hash, @options
|
331
|
+
it_behaves_like 'a hale documents links', representor_hash, @options
|
332
|
+
end
|
333
|
+
|
334
|
+
context 'Document with properties' do
|
335
|
+
representor_hash = begin
|
336
|
+
{
|
337
|
+
attributes: {
|
338
|
+
"count" => {value: 3},
|
339
|
+
"total_count" => {value: 6},
|
340
|
+
},
|
341
|
+
}
|
342
|
+
end
|
343
|
+
|
344
|
+
it_behaves_like 'a hale documents attributes', representor_hash, @options
|
345
|
+
end
|
346
|
+
|
347
|
+
|
348
|
+
context 'Document with properties, links, and embedded' do
|
349
|
+
representor_hash = begin
|
350
|
+
{
|
351
|
+
attributes: {
|
352
|
+
'title' => {value: 'The Neverending Story'},
|
353
|
+
},
|
354
|
+
transitions: [
|
355
|
+
{
|
356
|
+
href: '/mike',
|
357
|
+
rel: 'author',
|
358
|
+
}
|
359
|
+
],
|
360
|
+
embedded: {
|
361
|
+
'embedded_book' => {attributes: {'content' => { value: 'A...' } }, transitions: [{rel: 'self', href: '/foo'}]}
|
362
|
+
}
|
363
|
+
}
|
364
|
+
end
|
365
|
+
|
366
|
+
it_behaves_like 'a hale documents attributes', representor_hash, @options
|
367
|
+
it_behaves_like 'a hale documents links', representor_hash, @options
|
368
|
+
it_behaves_like 'a hale documents embedded hale documents', representor_hash, @options
|
369
|
+
end
|
370
|
+
|
371
|
+
context 'Document with an embedded collection' do
|
372
|
+
embedded = [{
|
373
|
+
transitions: [
|
374
|
+
{rel: "self", href: "www.example.com/coffeebucks/1"},
|
375
|
+
{
|
376
|
+
rel: 'fulfill',
|
377
|
+
href: "www.example.com/coffeebucks/1",
|
378
|
+
method: "PUT",
|
379
|
+
descriptors: {
|
380
|
+
"status" => {
|
381
|
+
value: "fulfilled",
|
382
|
+
validators: [
|
383
|
+
"required"
|
384
|
+
],
|
385
|
+
}
|
386
|
+
}
|
387
|
+
}
|
388
|
+
],
|
389
|
+
attributes: {
|
390
|
+
"status" => {value: "preparing"},
|
391
|
+
"created" => {value: 12569537329},
|
392
|
+
"drink_type" => {value: "latte"},
|
393
|
+
"iced" => {value: "true"},
|
394
|
+
"size" => {value: 8},
|
395
|
+
"shots" => {value: 2},
|
396
|
+
"decaf" => {value: 1}
|
397
|
+
}
|
398
|
+
},{
|
399
|
+
transitions: [
|
400
|
+
{rel: "self", href: "www.example.com/coffeebucks/2"},
|
401
|
+
],
|
402
|
+
attributes: {
|
403
|
+
"status" => {value: "fulfilled"},
|
404
|
+
"created" => {value: 12569537312},
|
405
|
+
"drink_type" => {value: "latte"},
|
406
|
+
"iced" => {value: "true"},
|
407
|
+
"size" => {value: 8},
|
408
|
+
"shots" => {value: 2},
|
409
|
+
"decaf" => {value: 1}
|
410
|
+
}
|
411
|
+
},{
|
412
|
+
transitions: [
|
413
|
+
{rel: "self", href: "www.example.com/coffeebucks/3"},
|
414
|
+
{
|
415
|
+
rel: "cancel",
|
416
|
+
href: "www.example.com/coffeebucks/3",
|
417
|
+
method: "DELETE"
|
418
|
+
},
|
419
|
+
{
|
420
|
+
rel: 'prepare',
|
421
|
+
href: "www.example.com/coffeebucks/3",
|
422
|
+
method: "PUT",
|
423
|
+
descriptors: {
|
424
|
+
"status" => {
|
425
|
+
value: "preparing",
|
426
|
+
validators: [
|
427
|
+
"required"
|
428
|
+
],
|
429
|
+
},
|
430
|
+
"paid" => {
|
431
|
+
value: 495,
|
432
|
+
validators: [
|
433
|
+
"required"
|
434
|
+
],
|
435
|
+
}
|
436
|
+
}
|
437
|
+
}
|
438
|
+
],
|
439
|
+
attributes: {
|
440
|
+
"status" => {value: "pending_payment"},
|
441
|
+
"created" => {value: 12569534536},
|
442
|
+
"drink_type" => {value: "latte"},
|
443
|
+
"iced" => {value: "true"},
|
444
|
+
"size" => {value: 8},
|
445
|
+
"shots" => {value: 2},
|
446
|
+
"decaf" => {value: 1},
|
447
|
+
"cost" => {value: 495}
|
448
|
+
}
|
449
|
+
},]
|
450
|
+
|
451
|
+
|
452
|
+
representor_hash = begin
|
453
|
+
{
|
454
|
+
embedded: {
|
455
|
+
"order_list" => embedded
|
456
|
+
}
|
457
|
+
}
|
458
|
+
end
|
459
|
+
|
460
|
+
let(:embedded_transitions) { {transitions: [
|
461
|
+
{:href=>"www.example.com/coffeebucks/1", :rel=>"order_list"},
|
462
|
+
{:href=>"www.example.com/coffeebucks/2", :rel=>"order_list"},
|
463
|
+
{:href=>"www.example.com/coffeebucks/3", :rel=>"order_list"}
|
464
|
+
]
|
465
|
+
}
|
466
|
+
}
|
467
|
+
|
468
|
+
it 'does not add embedded links if they already exist' do
|
469
|
+
representor = Representor.new(representor_hash.merge(@base_representor).merge(embedded_transitions))
|
470
|
+
serialized_hale = JSON.parse(Serialization::HaleSerializer.new(representor).to_media_type)
|
471
|
+
expect(serialized_hale["_links"]["order_list"].count).to eq(3)
|
472
|
+
end
|
473
|
+
|
474
|
+
it_behaves_like 'a hale documents embedded collection', representor_hash, @options
|
475
|
+
end
|
476
|
+
|
477
|
+
context 'Document with an complex object' do
|
478
|
+
representor_hash = begin
|
479
|
+
{
|
480
|
+
attributes: {
|
481
|
+
"count" => {value: 3},
|
482
|
+
"total_count" => {value: 6},
|
483
|
+
},
|
484
|
+
transitions: [{
|
485
|
+
rel: 'multi_order',
|
486
|
+
href: "www.example.com/coffeebucks/orders",
|
487
|
+
request_encoding: "application/json",
|
488
|
+
method: "POST",
|
489
|
+
descriptors: {
|
490
|
+
"multi_order" => {
|
491
|
+
value: true
|
492
|
+
},
|
493
|
+
"orders" => {
|
494
|
+
type: "object",
|
495
|
+
cardinality: "multiple",
|
496
|
+
descriptors: {
|
497
|
+
"drink_type" => {
|
498
|
+
options: {
|
499
|
+
'list' => [
|
500
|
+
"coffee",
|
501
|
+
"americano",
|
502
|
+
"latte",
|
503
|
+
"mocha",
|
504
|
+
"cappuccino",
|
505
|
+
"macchiato",
|
506
|
+
"espresso"
|
507
|
+
],},
|
508
|
+
:validators => [
|
509
|
+
"in",
|
510
|
+
"required"
|
511
|
+
],
|
512
|
+
cardinality: "multiple",
|
513
|
+
},
|
514
|
+
"iced" => {
|
515
|
+
type: "boolean",
|
516
|
+
value: false
|
517
|
+
},
|
518
|
+
"size" => {
|
519
|
+
type: "integer",
|
520
|
+
field_type: "number",
|
521
|
+
options: {
|
522
|
+
'hash' => {
|
523
|
+
"small" => 8,
|
524
|
+
"medium" => 12,
|
525
|
+
"large" => 16,
|
526
|
+
"extra-large" => 20
|
527
|
+
},},
|
528
|
+
:validators => [
|
529
|
+
"in",
|
530
|
+
"required"
|
531
|
+
],
|
532
|
+
},
|
533
|
+
"shots" => {
|
534
|
+
type: "integer",
|
535
|
+
field_type: "range",
|
536
|
+
:validators => [
|
537
|
+
{"min" => 0},
|
538
|
+
{"max" => 16},
|
539
|
+
],
|
540
|
+
},
|
541
|
+
"decaf" => {
|
542
|
+
type: "integer",
|
543
|
+
field_type: "range",
|
544
|
+
:validators => [
|
545
|
+
{"min" => 0},
|
546
|
+
{"max" => 16},
|
547
|
+
],
|
548
|
+
}
|
549
|
+
}
|
550
|
+
}
|
551
|
+
}
|
552
|
+
}]
|
553
|
+
}
|
554
|
+
end
|
555
|
+
|
556
|
+
it_behaves_like 'a hale documents attributes', representor_hash, @options
|
557
|
+
it_behaves_like 'a hale documents links', representor_hash, @options
|
558
|
+
|
559
|
+
let(:document) { representor_hash.merge(@base_representor) }
|
560
|
+
it 'has the expected Hale output' do
|
561
|
+
link_data = result["_links"]["multi_order"]["data"]["orders"]["data"]
|
562
|
+
expect(link_data["drink_type"]["in"]).to eq(true)
|
563
|
+
expect(link_data["drink_type"]["required"]).to eq(true)
|
564
|
+
expect(link_data["drink_type"]["options"]).to eq([
|
565
|
+
"coffee",
|
566
|
+
"americano",
|
567
|
+
"latte",
|
568
|
+
"mocha",
|
569
|
+
"cappuccino",
|
570
|
+
"macchiato",
|
571
|
+
"espresso"
|
572
|
+
])
|
573
|
+
|
574
|
+
expect(link_data["iced"]["type"]).to eq("boolean")
|
575
|
+
expect(link_data["iced"]["value"]).to eq(false)
|
576
|
+
|
577
|
+
expect(link_data["size"]["type"]).to eq("integer:number")
|
578
|
+
expect(link_data["size"]["in"]).to eq(true)
|
579
|
+
expect(link_data["size"]["required"]).to eq(true)
|
580
|
+
expect(link_data["size"]["options"]).to eq([
|
581
|
+
{"small" => 8},
|
582
|
+
{"medium" => 12},
|
583
|
+
{"large" => 16},
|
584
|
+
{"extra-large" => 20}
|
585
|
+
])
|
586
|
+
|
587
|
+
expect(link_data["shots"]["type"]).to eq("integer:range")
|
588
|
+
expect(link_data["shots"]["min"]).to eq(0)
|
589
|
+
expect(link_data["shots"]["max"]).to eq(16)
|
590
|
+
|
591
|
+
expect(link_data["decaf"]["type"]).to eq("integer:range")
|
592
|
+
expect(link_data["decaf"]["min"]).to eq(0)
|
593
|
+
expect(link_data["decaf"]["max"]).to eq(16)
|
594
|
+
end
|
595
|
+
|
596
|
+
end
|
597
|
+
|
598
|
+
context 'Document has a link data objects' do
|
599
|
+
representor_hash = begin
|
600
|
+
{
|
601
|
+
transitions: [
|
602
|
+
{
|
603
|
+
href: '/mike{?name}',
|
604
|
+
rel: 'author',
|
605
|
+
method: 'post',
|
606
|
+
descriptors: {
|
607
|
+
'name' => {
|
608
|
+
type: 'text',
|
609
|
+
scope: 'href',
|
610
|
+
value: 'Bob',
|
611
|
+
options: {'list' => ['Bob', 'Jane', 'Mike'], 'id' => 'names'},
|
612
|
+
validators: [ "required" ]
|
613
|
+
}
|
614
|
+
}
|
615
|
+
}
|
616
|
+
]
|
617
|
+
}
|
618
|
+
end
|
619
|
+
|
620
|
+
let(:document) { representor_hash.merge(@base_representor) }
|
621
|
+
let(:serialized_result) { JSON.parse(serializer.to_media_type) }
|
622
|
+
|
623
|
+
after do
|
624
|
+
expect(@result_element).to eq(@document_element)
|
625
|
+
end
|
626
|
+
|
627
|
+
it 'returns the correct link method' do
|
628
|
+
@result_element = serialized_result["_links"]['author']['method']
|
629
|
+
@document_element = document[:transitions].first[:method]
|
630
|
+
end
|
631
|
+
|
632
|
+
it 'returns the correct type keyword in link data' do
|
633
|
+
@result_element = serialized_result["_links"]['author']['data']['name']['type']
|
634
|
+
@document_element = document[:transitions].first[:descriptors]['name'][:type]
|
635
|
+
end
|
636
|
+
|
637
|
+
it 'returns the correct scope keyword in link data' do
|
638
|
+
@result_element = serialized_result["_links"]['author']['data']['name']['scope']
|
639
|
+
@document_element = document[:transitions].first[:descriptors]['name'][:scope]
|
640
|
+
end
|
641
|
+
|
642
|
+
it 'returns the correct value keyword in link data' do
|
643
|
+
@result_element = serialized_result["_links"]['author']['data']['name']['value']
|
644
|
+
@document_element = document[:transitions].first[:descriptors]['name'][:value]
|
645
|
+
end
|
646
|
+
|
647
|
+
it 'returns the correct datalists' do
|
648
|
+
@result_element = serialized_result["_meta"]['names']
|
649
|
+
@document_element = document[:transitions].first[:descriptors]['name'][:options]['list']
|
650
|
+
end
|
651
|
+
|
652
|
+
it 'properly references the datalists' do
|
653
|
+
@result_element = serialized_result["_links"]['author']['data']['name']['options']['_ref']
|
654
|
+
@document_element = ['names']
|
655
|
+
end
|
656
|
+
end
|
657
|
+
end
|
658
|
+
end
|
659
|
+
end
|