representors 0.0.5

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.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +18 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +126 -0
  5. data/LICENSE.md +19 -0
  6. data/README.md +28 -0
  7. data/Rakefile +10 -0
  8. data/lib/representor_support/utilities.rb +39 -0
  9. data/lib/representors.rb +5 -0
  10. data/lib/representors/errors.rb +7 -0
  11. data/lib/representors/field.rb +108 -0
  12. data/lib/representors/options.rb +67 -0
  13. data/lib/representors/representor.rb +161 -0
  14. data/lib/representors/representor_builder.rb +64 -0
  15. data/lib/representors/representor_hash.rb +59 -0
  16. data/lib/representors/serialization.rb +4 -0
  17. data/lib/representors/serialization/deserializer_base.rb +29 -0
  18. data/lib/representors/serialization/deserializer_factory.rb +13 -0
  19. data/lib/representors/serialization/hal_deserializer.rb +44 -0
  20. data/lib/representors/serialization/hal_serializer.rb +91 -0
  21. data/lib/representors/serialization/hale_deserializer.rb +162 -0
  22. data/lib/representors/serialization/hale_serializer.rb +110 -0
  23. data/lib/representors/serialization/serialization_base.rb +27 -0
  24. data/lib/representors/serialization/serialization_factory_base.rb +54 -0
  25. data/lib/representors/serialization/serializer_base.rb +20 -0
  26. data/lib/representors/serialization/serializer_factory.rb +17 -0
  27. data/lib/representors/transition.rb +130 -0
  28. data/lib/representors/version.rb +4 -0
  29. data/spec/fixtures/complex_hal.json +92 -0
  30. data/spec/fixtures/complex_hale_document.json +81 -0
  31. data/spec/fixtures/drds_hash.rb +120 -0
  32. data/spec/fixtures/hale_spec_examples/basic.json +77 -0
  33. data/spec/fixtures/hale_spec_examples/complex_reference_objects.json +157 -0
  34. data/spec/fixtures/hale_spec_examples/data.json +17 -0
  35. data/spec/fixtures/hale_spec_examples/data_objects.json +96 -0
  36. data/spec/fixtures/hale_spec_examples/link_objects.json +18 -0
  37. data/spec/fixtures/hale_spec_examples/nested_ref.json +43 -0
  38. data/spec/fixtures/hale_spec_examples/reference_objects.json +89 -0
  39. data/spec/fixtures/hale_tutorial_examples/basic_links.json +85 -0
  40. data/spec/fixtures/hale_tutorial_examples/basic_links_with_orders.json +96 -0
  41. data/spec/fixtures/hale_tutorial_examples/basic_links_with_references.json +108 -0
  42. data/spec/fixtures/hale_tutorial_examples/embedded.json +182 -0
  43. data/spec/fixtures/hale_tutorial_examples/empty.json +1 -0
  44. data/spec/fixtures/hale_tutorial_examples/enctype.json +14 -0
  45. data/spec/fixtures/hale_tutorial_examples/final.json +141 -0
  46. data/spec/fixtures/hale_tutorial_examples/get_link.json +17 -0
  47. data/spec/fixtures/hale_tutorial_examples/get_link_with_data.json +29 -0
  48. data/spec/fixtures/hale_tutorial_examples/links.json +11 -0
  49. data/spec/fixtures/hale_tutorial_examples/links_only.json +3 -0
  50. data/spec/fixtures/hale_tutorial_examples/meta.json +208 -0
  51. data/spec/fixtures/hale_tutorial_examples/self_link.json +7 -0
  52. data/spec/fixtures/single_drd.rb +266 -0
  53. data/spec/lib/representors/complex_representor_spec.rb +288 -0
  54. data/spec/lib/representors/field_spec.rb +141 -0
  55. data/spec/lib/representors/representor_builder_spec.rb +223 -0
  56. data/spec/lib/representors/representor_spec.rb +285 -0
  57. data/spec/lib/representors/serialization/deserializer_factory_spec.rb +118 -0
  58. data/spec/lib/representors/serialization/hal_deserializer_spec.rb +34 -0
  59. data/spec/lib/representors/serialization/hal_serializer_spec.rb +171 -0
  60. data/spec/lib/representors/serialization/hale_deserializer_spec.rb +59 -0
  61. data/spec/lib/representors/serialization/hale_roundtrip_spec.rb +34 -0
  62. data/spec/lib/representors/serialization/hale_serializer_spec.rb +659 -0
  63. data/spec/lib/representors/serialization/serializer_factory_spec.rb +108 -0
  64. data/spec/lib/representors/transition_spec.rb +349 -0
  65. data/spec/spec_helper.rb +32 -0
  66. data/spec/support/basic-hale.json +12 -0
  67. data/spec/support/hal_representor_shared.rb +206 -0
  68. data/spec/support/helpers.rb +8 -0
  69. data/tasks/benchmark.rake +75 -0
  70. data/tasks/complex_hal_document.json +98 -0
  71. data/tasks/test_specs.rake +37 -0
  72. data/tasks/yard.rake +22 -0
  73. metadata +232 -0
@@ -0,0 +1,285 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+ require 'uri'
4
+
5
+ module Representors
6
+ describe Representor do
7
+ let(:base_doc) {'A list of DRDs.'}
8
+ let(:rel_first_transition) {'self'}
9
+ let(:rel_second_transition) {'search'}
10
+ before do
11
+ @base_representor = {
12
+ protocol: 'http',
13
+ href: 'www.example.com/drds',
14
+ id: 'drds',
15
+ doc: base_doc,
16
+ attributes: {},
17
+ embedded: {},
18
+ links: {},
19
+ transitions: []
20
+ }
21
+
22
+ @semantic_elements = {
23
+ attributes: {
24
+ total_count: {
25
+ doc: 'The total count of DRDs.',
26
+ type: 'semantic',
27
+ profile: 'http://alps.io/schema.org/Integer',
28
+ sample: 1,
29
+ value: 2
30
+ },
31
+ uptime: {
32
+ value: '76ms'
33
+ },
34
+ brackreference: {
35
+ value: 886396728
36
+ }
37
+ }
38
+ }
39
+
40
+ @transition_elements = {
41
+ transitions: [
42
+ {
43
+ doc: 'Returns a list of DRDs.',
44
+ rt: 'drds',
45
+ type: 'safe',
46
+ href: 'some.example.com/list',
47
+ rel: rel_first_transition
48
+ },
49
+ {
50
+ doc: 'Returns a list of DRDs that satisfy the search term.',
51
+ rt: 'drds',
52
+ type: 'safe',
53
+ href: '/',
54
+ rel: rel_second_transition,
55
+ descriptors: {
56
+ name: {
57
+ doc: "Name to search",
58
+ profile: "http://alps.io/schema.org/Text",
59
+ sample: "drdname",
60
+ options: {'list' => ['one', 'two']}
61
+ },
62
+ status: {
63
+ doc: "How is the DRD.",
64
+ profile: "http://alps.io/schema.org/Text",
65
+ sample: "renegade",
66
+ options: {'list' => ['renegade', 'compliant'], 'id' => 'status_list'}
67
+ }
68
+ }
69
+ }
70
+ ]
71
+ }
72
+ end
73
+ let(:representor_hash) { @representor_hash || @base_representor }
74
+ let(:subject) { Representor.new(representor_hash) }
75
+
76
+ describe '.new' do
77
+ it 'returns a Representors::Representor instance' do
78
+ expect(subject).to be_an_instance_of(Representor)
79
+ end
80
+
81
+ it 'yields a builder' do
82
+ Representor.new do |builder|
83
+ expect(builder).to be_an_instance_of(RepresentorBuilder)
84
+ builder
85
+ end
86
+ end
87
+
88
+ it 'returns a Representors::Representor instance with a nil argument' do
89
+ expect(Representor.new).to be_an_instance_of(Representor)
90
+ end
91
+
92
+ describe '#to_s' do
93
+ it 'retuns a string representation' do
94
+ expect(eval(subject.to_s)).to eq(representor_hash)
95
+ end
96
+ end
97
+
98
+ describe '#doc' do
99
+ context 'the hash has a doc' do
100
+ let(:doc) {base_doc}
101
+ it 'returns the same value specified under the doc element of the hash' do
102
+ @representor_hash = RepresentorHash.new
103
+ @representor_hash.doc = doc
104
+ expect(subject.doc).to eq(doc)
105
+ end
106
+ end
107
+ context 'the hash has non doc' do
108
+ it 'returns an empty string' do
109
+ @representor_hash = RepresentorHash.new
110
+ expect(subject.doc).to eq('')
111
+ end
112
+ end
113
+ end
114
+
115
+ describe '#identifier' do
116
+ context 'href and protocol are specified' do
117
+ let(:href) { 'www.example.com/drds'}
118
+ let(:protocol) {'http'}
119
+ it 'returns an url' do
120
+ @representor_hash = RepresentorHash.new(protocol: protocol, href: href)
121
+ expect(subject.identifier).to match(URI::regexp)
122
+ end
123
+ end
124
+
125
+ context 'href is not specified and protocol is specified' do
126
+ let(:protocol) {'http'}
127
+ it 'returns an url with object id' do
128
+ @representor_hash = RepresentorHash.new(protocol: protocol)
129
+ expect(subject.identifier).to eq('http://%s' % subject.object_id)
130
+ end
131
+ end
132
+
133
+ context 'href is specified and protocol is not specified' do
134
+ let(:href) { 'www.example.com/drds'}
135
+ it 'returns an url with default protocol' do
136
+ @representor_hash = RepresentorHash.new(href: href)
137
+ expect(subject.identifier).to eq('http://%s' % href)
138
+ end
139
+ end
140
+
141
+ context 'href is not specified and protocol is not specified' do
142
+ let(:href) { 'www.example.com/drds'}
143
+ it 'returns an unknown protocol object url' do
144
+ @representor_hash = RepresentorHash.new
145
+ expect(subject.identifier).to eq("ruby_id://%s" % subject.object_id)
146
+ end
147
+ end
148
+
149
+ end
150
+
151
+ describe '#to_hash' do
152
+ it 'returns a hash that it can be reconstructed with' do
153
+ expect(Representor.new(subject.to_hash).to_hash).to eq(@base_representor)
154
+ end
155
+ end
156
+
157
+ describe '#to_yaml' do
158
+ it 'returns a yaml file that represents its internal hash' do
159
+ expect(YAML.load(subject.to_yaml)).to eq(@base_representor)
160
+ end
161
+ end
162
+
163
+ describe '#properties' do
164
+ it 'returns a hash of attributes associated with the represented resource' do
165
+ @representor_hash = @base_representor.merge(@semantic_elements)
166
+ semantic_elements_present = %w(total_count uptime brackreference).all? do |key|
167
+ subject.properties[key.to_sym] == @semantic_elements[:attributes][key.to_sym][:value]
168
+ end
169
+ expect(semantic_elements_present).to eq(true)
170
+ end
171
+ end
172
+
173
+ describe '#embedded' do
174
+ let(:embedded_resource) {'embedded_resource'}
175
+ let(:profile_link) { {profile: "http://alps.io/schema.org/Thing"} }
176
+
177
+ before do
178
+ @count = 3
179
+ @representor_hash = RepresentorHash.new(@base_representor).merge(@semantic_elements)
180
+ embedded_resources = []
181
+
182
+ @transitions_hash = {
183
+ transitions: [
184
+ { doc: 'Returns a list of DRDs',
185
+ type: 'safe',
186
+ rel: 'self'
187
+ }
188
+ ]
189
+ }
190
+
191
+ @count.times do |i|
192
+ transitions_hash = deep_dup(@transitions_hash)
193
+ transitions_hash[:transitions][0][:href] = "some.example.com/list/#{i}"
194
+ embedded_item = deep_dup(@representor_hash).merge(transitions_hash)
195
+ embedded_item[:links] = profile_link if i == 0
196
+ embedded_resources << embedded_item
197
+ end
198
+
199
+
200
+ @representor_hash[:embedded] = { embedded_resource => embedded_resources }
201
+ end
202
+
203
+ it 'returns a set of Representor objects' do
204
+ expect(subject.embedded[embedded_resource].first).to be_an_instance_of(Representors::Representor)
205
+ end
206
+
207
+ it 'returns a Representor objects that has its data' do
208
+ embedded_objects_valid = subject.embedded[embedded_resource].all? { |embed| embed.doc == base_doc }
209
+ expect(embedded_objects_valid).to eq(true)
210
+ end
211
+
212
+ it 'returns the all the Representors' do
213
+ expect(subject.embedded[embedded_resource].count).to eq(@count)
214
+ end
215
+
216
+ it 'doesn\'t blow up even if nothing is embedded' do
217
+ @representor_hash = @base_representor
218
+ expect(subject.embedded.count).to eq(0)
219
+ end
220
+
221
+ it 'includes appropriate profile links if it exists' do
222
+ expect(subject.transitions.first[:profile]).to eq(profile_link["profile"])
223
+ expect(subject.transitions[1][:profile]).to be_nil
224
+ expect(subject.transitions.last[:profile]).to be_nil
225
+ end
226
+ end
227
+
228
+ describe '#transitions' do
229
+ it 'returns all transitions' do
230
+ @representor_hash = @base_representor.merge(@transition_elements)
231
+ expect(subject.transitions.size).to eq(2)
232
+ has_transitions = subject.transitions.all? { |trans| trans.instance_of?(Transition) }
233
+ expect(has_transitions).to eq(true)
234
+ expect(subject.transitions[0].rel).to eq(rel_first_transition)
235
+ expect(subject.transitions[1].rel).to eq(rel_second_transition)
236
+ end
237
+ context 'with transitions which have the same rel and href' do
238
+ it 'returns only one transition' do
239
+ transitions = { transitions: [
240
+ {
241
+ doc: 'Returns a list of DRDs.',
242
+ rt: 'drds',
243
+ type: 'safe',
244
+ href: 'some.example.com/list',
245
+ rel: rel_first_transition
246
+ },
247
+ {
248
+ doc: 'Returns a list of trusmis.',
249
+ rt: 'trusmis',
250
+ type: 'unsafe',
251
+ href: 'some.example.com/list',
252
+ rel: rel_first_transition
253
+ }
254
+ ]
255
+ }
256
+ @representor_hash = @base_representor.merge(transitions)
257
+ expect(subject.transitions.size).to eq(1)
258
+ has_transitions = subject.transitions.all? { |trans| trans.instance_of?(Transition) }
259
+ expect(has_transitions).to eq(true)
260
+ expect(subject.transitions[0].rel).to eq(rel_first_transition)
261
+ end
262
+ end
263
+ end
264
+
265
+ describe '#meta_links' do
266
+ it 'should return a list of transitions representing those links' do
267
+ @base_representor[:links] = {
268
+ self: 'DRDs#drds/create',
269
+ help: 'Forms/create'
270
+ }
271
+ expect(subject.meta_links.size).to eq(2)
272
+ has_meta_link = subject.meta_links.all? { |trans| trans.instance_of?(Transition) }
273
+ expect(has_meta_link).to eq(true)
274
+ end
275
+ end
276
+
277
+ describe '#datalists' do
278
+ it 'returns all paramters and attributes that are members of a datalist' do
279
+ @representor_hash = @base_representor.merge(@transition_elements)
280
+ has_data_list = expect(subject.datalists.first.to_hash).to eq({"renegade" => "renegade", "compliant" => "compliant"})
281
+ end
282
+ end
283
+ end
284
+ end
285
+ end
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+ require 'representors/serialization/deserializer_factory'
3
+
4
+ module Representors
5
+ describe DeserializerFactory do
6
+ let(:factory) { Class.new(DeserializerFactory) } # prevent singleton pollution from spec
7
+
8
+ describe '.register_deserializers' do
9
+ it 'adds classes to the registered deserializers' do
10
+ serializer_classes = [double('deserializer1'), double('deserializer2')]
11
+ factory.register_deserializers(*serializer_classes)
12
+
13
+ expect(factory.registered_deserializers).to include(*serializer_classes)
14
+ end
15
+ end
16
+
17
+ describe '.registered_deserializers' do
18
+ before do
19
+ @deserializer_class = double('deserializer3')
20
+ factory.register_deserializers(@deserializer_class)
21
+ end
22
+
23
+ it 'memoizes' do
24
+ registered_deserializers = factory.registered_deserializers.object_id
25
+
26
+ expect(registered_deserializers).to eq(factory.registered_deserializers.object_id)
27
+ end
28
+
29
+ it 'returns a frozen list of registered_deserializers' do
30
+ expect(factory.registered_deserializers).to be_frozen
31
+ end
32
+
33
+ it 'returns registered serializers' do
34
+ expect(factory.registered_deserializers).to include(@deserializer_class)
35
+ end
36
+ end
37
+
38
+ describe '#build' do
39
+ let(:document) { {}.to_json }
40
+ subject(:deserializer) { DeserializerFactory.build(media_type, document) }
41
+
42
+ shared_examples_for 'a built deserializer' do
43
+ it 'sets the correct target in the deserializer' do
44
+ expect(deserializer.to_representor_hash).to eq(RepresentorHash.new)
45
+ end
46
+ end
47
+
48
+ shared_examples_for 'a hal deserializer' do
49
+ it 'returns a HalDeserializer' do
50
+ expect(deserializer).to be_instance_of HalDeserializer
51
+ end
52
+
53
+ it_behaves_like 'a built deserializer'
54
+ end
55
+
56
+ context 'with an empty response body' do
57
+ [nil, '', '{}', ' '].each do |response_body|
58
+ context "when given a #{response_body.inspect}" do
59
+ let(:media_type) { 'application/hal+json' }
60
+ let(:document) { '' }
61
+
62
+ it_behaves_like 'a hal deserializer'
63
+ end
64
+ end
65
+ end
66
+
67
+ context 'with hal+json media type as a string' do
68
+ let(:media_type) { 'application/hal+json' }
69
+
70
+ it_behaves_like 'a hal deserializer'
71
+ end
72
+
73
+ context 'with hal+json media type as a symbol' do
74
+ let(:media_type) { :hal }
75
+
76
+ it_behaves_like 'a hal deserializer'
77
+ end
78
+
79
+ shared_examples_for 'a hale deserializer' do
80
+ it 'returns a HaleDeserializer' do
81
+ expect(deserializer).to be_instance_of HaleDeserializer
82
+ end
83
+
84
+ it_behaves_like 'a built deserializer'
85
+ end
86
+
87
+ context 'with hale+json media type as a string' do
88
+ let(:media_type) { 'application/vnd.hale+json' }
89
+
90
+ it_behaves_like 'a hale deserializer'
91
+ end
92
+
93
+ context 'with hale+json media type as a symbol' do
94
+ let(:media_type) { :hale }
95
+
96
+ it_behaves_like 'a hale deserializer'
97
+ end
98
+
99
+ shared_examples_for 'an unknown media type' do
100
+ it 'raises an unknown media type error' do
101
+ expect { deserializer }.to raise_error(UnknownMediaTypeError, "Unknown media-type: #{media_type}.")
102
+ end
103
+ end
104
+
105
+ context 'unknown media type string' do
106
+ let(:media_type) { 'unknown' }
107
+
108
+ it_behaves_like 'an unknown media type'
109
+ end
110
+
111
+ context 'unknown media type symbol' do
112
+ let(:media_type) { :unknown }
113
+
114
+ it_behaves_like 'an unknown media type'
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe Representors::HalDeserializer do
4
+
5
+ it "initializes with a JSON document" do
6
+ expect(Representors::HalDeserializer.new({}.to_json)).to be_instance_of(Representors::HalDeserializer)
7
+ end
8
+
9
+ it 'provides the media-type application/vnd.hal+json' do
10
+ formats = Representors::HalDeserializer.media_types
11
+ expect(formats).to include('application/hal+json', 'application/json')
12
+ end
13
+
14
+ it 'provides the media symbol :hal' do
15
+ expect(Representors::HalDeserializer.media_symbols).to include(:hal)
16
+ end
17
+
18
+ describe "#to_representor" do
19
+ it_behaves_like 'can create a representor from a hal document' do
20
+ subject(:deserializer) {Representors::HalDeserializer.new(document)}
21
+ end
22
+
23
+ context "when the Hal deserializer recieves a Hale document" do
24
+ it "deserializes as a Hal document and not a Hale document" do
25
+ file = File.read("#{SPEC_DIR}/fixtures/hale_tutorial_examples/meta.json")
26
+ hal_rep = Representors::HalDeserializer.new(file).to_representor
27
+ place_order_link_data = hal_rep.transitions.find { |t| t[:rel] == "place_order" }
28
+ expect(hal_rep.properties.keys).to include('_meta')
29
+ expect(place_order_link_data.interface_method).to eq('GET')
30
+ end
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,171 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+ require 'uri'
4
+
5
+ module Representors
6
+ describe Serialization::HalSerializer do
7
+
8
+ subject(:serializer) { SerializerFactory.build(:hal_json, Representor.new(document)) }
9
+ let(:result) {JSON.parse(serializer.to_media_type)}
10
+ let(:base_representor) do
11
+ {
12
+ protocol: 'http',
13
+ href: 'www.example.com/drds',
14
+ id: 'drds',
15
+ doc: 'doc'
16
+ }
17
+ end
18
+
19
+ shared_examples 'a hal documents attributes' do |representor_hash|
20
+ let(:document) { representor_hash.merge(base_representor) }
21
+
22
+ representor_hash[:attributes].each do |k, v|
23
+ it "includes the document attribute #{k} and associated value" do
24
+ expect(result[k]).to eq(v[:value])
25
+ end
26
+ end
27
+ end
28
+
29
+ shared_examples 'a hal documents links' do |representor_hash|
30
+ let(:document) { representor_hash.merge(base_representor) }
31
+
32
+ representor_hash[:transitions].each do |item|
33
+ it "includes the document transition #{item}" do
34
+ links = result['_links']
35
+ link = links[item[:rel]]
36
+ expect(link['href']).to eq(item[:href])
37
+ end
38
+ end
39
+ end
40
+
41
+ shared_examples 'a hal documents embedded hal documents' do |representor_hash|
42
+ let(:document) { representor_hash.merge(base_representor) }
43
+
44
+ representor_hash[:embedded].each do |embed_name, embed|
45
+ embed[:attributes].each do |k, v|
46
+ it "includes the document attribute #{k} and associated value" do
47
+ expect(result['_embedded'][embed_name][k]).to eq(v[:value])
48
+ end
49
+ end
50
+ embed[:transitions].each do |item|
51
+ it "includes the document attribute #{item} and associated value" do
52
+ expect(result['_embedded'][embed_name]['_links'][item[:rel]]['href']).to eq(item[:href])
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ shared_examples 'a hal documents embedded collection' do |representor_hash|
59
+ let(:document) { representor_hash.merge(base_representor) }
60
+
61
+ representor_hash[:embedded].each do |embed_name, embeds|
62
+ embeds.each_with_index do |embed, index|
63
+ embed[:attributes].each do |k, v|
64
+ it "includes the document attribute #{k} and associated value" do
65
+ expect(result['_embedded'][embed_name][index][k]).to eq(v[:value])
66
+ end
67
+ end
68
+ embed[:transitions].each do |item|
69
+ it "includes the document attribute #{item} and associated value" do
70
+ expect(result['_embedded'][embed_name][index]['_links'][item[:rel]]['href']).to eq(item[:href])
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ describe '#as_media_type' do
78
+ context 'empty document' do
79
+ let(:document) { {} }
80
+
81
+ it 'returns a hash with no attributes, links or embedded resources' do
82
+ empty_json_document = '{}'
83
+ expect(serializer.to_media_type).to eq(empty_json_document)
84
+ end
85
+ end
86
+
87
+ context 'Document with only properties' do
88
+ representor_hash = begin
89
+ {
90
+ attributes: {
91
+ 'title' => {value: 'The Neverending Story'},
92
+ 'author' => {value: 'Michael Ende'},
93
+ 'pages' => {value: '396'}
94
+ }
95
+ }
96
+ end
97
+
98
+ it_behaves_like 'a hal documents attributes', representor_hash
99
+ end
100
+
101
+ context 'Document with properties and links' do
102
+ representor_hash = begin
103
+ {
104
+ attributes: {
105
+ 'title' => {value: 'The Neverending Story'},
106
+ },
107
+ transitions: [
108
+ {
109
+ href: '/mike',
110
+ rel: 'author',
111
+ }
112
+ ]
113
+ }
114
+ end
115
+
116
+ it_behaves_like 'a hal documents attributes', representor_hash
117
+ it_behaves_like 'a hal documents links', representor_hash
118
+ end
119
+
120
+ context 'Document with properties, links, and embedded' do
121
+ representor_hash = begin
122
+ {
123
+ attributes: {
124
+ 'title' => {value: 'The Neverending Story'},
125
+ },
126
+ transitions: [
127
+ {
128
+ href: '/mike',
129
+ rel: 'author',
130
+ }
131
+ ],
132
+ embedded: {
133
+ 'embedded_book' => {attributes: {'content' => { value: 'A...' } }, transitions: [{rel: 'self', href: '/foo'}]}
134
+ }
135
+ }
136
+ end
137
+
138
+ it_behaves_like 'a hal documents attributes', representor_hash
139
+ it_behaves_like 'a hal documents links', representor_hash
140
+ it_behaves_like 'a hal documents embedded hal documents', representor_hash
141
+ end
142
+
143
+ context 'Document with an embedded collection' do
144
+ representor_hash = begin
145
+ {
146
+ attributes: {
147
+ 'title' => {value: 'The Neverending Story'},
148
+ },
149
+ transitions: [
150
+ {
151
+ href: '/mike',
152
+ rel: 'author',
153
+ }
154
+ ],
155
+ embedded: {
156
+ 'embedded_book' => [
157
+ {attributes: {'content' => { value: 'A...' } }, transitions: [{rel: 'self', href: '/foo1'}]},
158
+ {attributes: {'content' => { value: 'B...' } }, transitions: [{rel: 'self', href: '/foo2'}]},
159
+ {attributes: {'content' => { value: 'C...' } }, transitions: [{rel: 'self', href: '/foo3'}]}
160
+ ]
161
+ }
162
+ }
163
+ end
164
+
165
+ it_behaves_like 'a hal documents attributes', representor_hash
166
+ it_behaves_like 'a hal documents links', representor_hash
167
+ it_behaves_like 'a hal documents embedded collection', representor_hash
168
+ end
169
+ end
170
+ end
171
+ end