representors 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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,108 @@
1
+ require 'spec_helper'
2
+ require 'representors/serialization/serializer_base'
3
+
4
+ module Representors
5
+
6
+ describe SerializerFactory do
7
+ let(:factory) { Class.new(SerializerFactory) } # prevent singleton pollution from spec
8
+
9
+ describe '.register_serializers' do
10
+ it 'adds classes to the registered serializers' do
11
+ serializer_classes = [create_serializer('serializer1'), create_serializer('serializer2')]
12
+ factory.register_serializers(*serializer_classes)
13
+
14
+ expect(factory.registered_serializers).to include(*serializer_classes)
15
+ end
16
+ end
17
+
18
+ describe '.registered_serializers' do
19
+ before do
20
+ @serializer_class = create_serializer('serializer3')
21
+ factory.register_serializers(@serializer_class)
22
+ end
23
+
24
+ it 'memoizes' do
25
+ registered_serializers = factory.registered_serializers.object_id
26
+
27
+ expect(registered_serializers).to eq(factory.registered_serializers.object_id)
28
+ end
29
+
30
+ it 'returns a frozen list of registered_serializers' do
31
+ expect(factory.registered_serializers).to be_frozen
32
+ end
33
+
34
+ it 'returns registered serializers' do
35
+ expect(factory.registered_serializers).to include(@serializer_class)
36
+ end
37
+ end
38
+ end
39
+
40
+ describe '#build' do
41
+ let(:representor) { Representor.new }
42
+ subject(:serializer) { SerializerFactory.build(media_type, representor) }
43
+
44
+ shared_examples_for 'a built serializer' do
45
+ it 'sets the correct target in the serializer' do
46
+ expect(serializer.target).to eq(representor)
47
+ end
48
+ end
49
+
50
+ shared_examples_for 'a hal serializer' do
51
+ it 'returns a Halserializer' do
52
+ expect(serializer).to be_instance_of(Serialization::HalSerializer)
53
+ end
54
+
55
+ it_behaves_like 'a built serializer'
56
+ end
57
+
58
+ context 'with hal+json media type as a string' do
59
+ let(:media_type) { 'application/hal+json' }
60
+
61
+ it_behaves_like 'a hal serializer'
62
+ end
63
+
64
+ context 'with hal+json media type as a symbol' do
65
+ let(:media_type) { :hal_json }
66
+
67
+ it_behaves_like 'a hal serializer'
68
+ end
69
+
70
+ shared_examples_for 'a hale serializer' do
71
+ it 'returns a Haleserializer' do
72
+ expect(serializer).to be_instance_of(Serialization::HaleSerializer)
73
+ end
74
+
75
+ it_behaves_like 'a built serializer'
76
+ end
77
+
78
+ context 'with hale+json media type as a string' do
79
+ let(:media_type) { 'application/vnd.hale+json' }
80
+
81
+ it_behaves_like 'a hale serializer'
82
+ end
83
+
84
+ context 'with hale+json media type as a symbol' do
85
+ let(:media_type) { :hale_json }
86
+
87
+ it_behaves_like 'a hale serializer'
88
+ end
89
+
90
+ shared_examples_for 'an unknown media type' do
91
+ it 'raises an unknown media type error' do
92
+ expect { serializer }.to raise_error(UnknownMediaTypeError, "Unknown media-type: #{media_type}.")
93
+ end
94
+ end
95
+
96
+ context 'unknown media type string' do
97
+ let(:media_type) { 'unknown' }
98
+
99
+ it_behaves_like 'an unknown media type'
100
+ end
101
+
102
+ context 'unknown media type symbol' do
103
+ let(:media_type) { :unknown }
104
+
105
+ it_behaves_like 'an unknown media type'
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,349 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+ require 'uri'
4
+
5
+ module Representors
6
+ describe Transition do
7
+ before do
8
+ @self_transition = {
9
+ doc: 'Returns a list of DRDs.',
10
+ rt: 'drds',
11
+ type: 'safe',
12
+ href: 'some.example.com/list',
13
+ rel: 'self'
14
+ }
15
+ @search_transition = {
16
+ doc: 'Returns a list of DRDs that satisfy the search term.',
17
+ rt: 'drds',
18
+ type: 'safe',
19
+ method: 'post',
20
+ href: '/{?name}',
21
+ rel: 'search',
22
+ links: {
23
+ self: 'DRDs#drds/create',
24
+ help: 'Forms/create'
25
+ },
26
+ descriptors: {
27
+ name: {
28
+ doc: 'Name to search',
29
+ profile: 'http://alps.io/schema.org/Text',
30
+ sample: 'drdname',
31
+ scope: 'href',
32
+ options: { list: ['one', 'two'] }
33
+ },
34
+ status: {
35
+ doc: 'How is the DRD.',
36
+ profile: 'http://alps.io/schema.org/Text',
37
+ sample: 'renegade',
38
+ options: { list: ['renegade', 'compliant'], id: 'status_list' }
39
+ }
40
+ }
41
+ }
42
+ end
43
+
44
+ let(:representor_hash) { @representor_hash || @self_transition }
45
+ let(:subject) { Transition.new(representor_hash) }
46
+
47
+ describe '#to_s' do
48
+ it 'retuns a string representation' do
49
+ expect(subject.to_s).to eq(representor_hash.to_s)
50
+ end
51
+ end
52
+
53
+ describe '#to_hash' do
54
+ let(:hash_with_symbol_keys) do
55
+ {
56
+ href: 'some.niceplace.com/list',
57
+ rel: 'self'
58
+ }
59
+ end
60
+ let(:hash_with_string_keys) do
61
+ {
62
+ 'href' => 'some.niceplace.com/list',
63
+ 'rel' => 'self'
64
+ }
65
+ end
66
+ context 'the keys are strings' do
67
+ let(:representor_hash) {hash_with_string_keys}
68
+ it 'returns a hash with the keys as strings' do
69
+ expect(subject.to_hash).to eq(hash_with_string_keys)
70
+ end
71
+ end
72
+ context 'the keys are symbols' do
73
+ let(:representor_hash) {hash_with_symbol_keys}
74
+ it 'returns a hash with the keys as strings' do
75
+ expect(subject.to_hash).to eq(hash_with_string_keys)
76
+ end
77
+ end
78
+ end
79
+
80
+ describe '#[]' do
81
+ let(:representor_hash) { {key => value}}
82
+ let(:value) { 'http://www.dontknow.com'}
83
+ let(:key) {'href'}
84
+
85
+ it 'retuns the value for the keys' do
86
+ expect(subject[key]).to eq(value)
87
+ end
88
+
89
+ it 'returns nil if the key is not in this transition' do
90
+ expect(subject['Ido not exists']).to be_nil
91
+ end
92
+
93
+ it 'has indiferent access to the hash' do
94
+ expect(subject[key.to_sym]).to eq(value)
95
+ expect(subject[key.to_s]).to eq(value)
96
+ end
97
+
98
+ end
99
+
100
+ describe '#has_key?' do
101
+ let(:representor_hash) { {key => value}}
102
+ let(:value) { 'http://www.dontknow.com'}
103
+ let(:key) {'href'}
104
+
105
+ it 'retuns the value for the keys' do
106
+ expect(subject.has_key?(key)).to eq(true)
107
+ end
108
+
109
+ it 'returns nil if the key is not in this transition' do
110
+ expect(subject.has_key?('Ido not exists')).to eq(false)
111
+ end
112
+ end
113
+
114
+ describe '.new' do
115
+ it 'returns a Representors::Transition instance' do
116
+ expect(subject).to be_an_instance_of(Transition)
117
+ end
118
+
119
+ describe '#rel' do
120
+ it 'returns the transition key' do
121
+ expect(subject.rel).to eq('self')
122
+ end
123
+ end
124
+
125
+ describe '#interface_method' do
126
+ it 'returns the uniform interface method' do
127
+ expect(subject.interface_method).to eq('GET')
128
+ end
129
+ it 'retuns the interface_method provided by the hash' do
130
+ @representor_hash = @search_transition
131
+ expect(subject.interface_method).to eq('post')
132
+ end
133
+ end
134
+
135
+ describe '#parameters' do
136
+ it 'returns a list of fields representing the link parameters' do
137
+ @representor_hash = @search_transition
138
+ expect(subject.parameters.size).to eq(1)
139
+ field = subject.parameters.first
140
+ expect(field).to be_an_instance_of(Field)
141
+ expect(field.scope).to eq('href')
142
+ expect(field.name).to eq(:name)
143
+ end
144
+ context 'there are no params' do
145
+ let(:transition) do
146
+ {
147
+ href: 'some.example.com',
148
+ rel: 'filter'
149
+ }
150
+ end
151
+ it 'returns an empty array' do
152
+ expect(Transition.new(transition).parameters).to eq([])
153
+ end
154
+ end
155
+ context 'the uri template has information we do not have in data' do
156
+ let(:transition) do
157
+ {
158
+ href: 'some.place.com{?name,localization}',
159
+ rel: 'filter',
160
+ descriptors: {
161
+ name: {
162
+ doc: name_doc,
163
+ type: 'Integer',
164
+ profile: name_profile,
165
+ scope: 'href'
166
+ },
167
+ localization: {
168
+ doc: 'wrong scope',
169
+ type: 'Something crazy',
170
+ profile: 'Because this key has no scope should not be used'
171
+ }
172
+ }
173
+ }
174
+ end
175
+ let(:name_doc) {'di place of Trusmis'}
176
+ let(:name_profile) {'http://alps.io/schema.org/Text'}
177
+
178
+ it 'returns all the variables in the uri template' do
179
+ expect(Transition.new(transition).parameters.size).to eq(2)
180
+ end
181
+ it 'returns the information about the variable described by the document' do
182
+ param = Transition.new(transition).parameters.find{|param| param.name == :name}
183
+ expect(param.scope).to eq('href')
184
+ expect(param.type).to eq('Integer')
185
+ end
186
+ it 'returns default information for the variable not described by the document' do
187
+ param = Transition.new(transition).parameters.find{|param| param.name == :localization}
188
+ expect(param.scope).to eq('href')
189
+ expect(param.type).to eq('string')
190
+ end
191
+ end
192
+ end
193
+
194
+ describe '#attributes' do
195
+ it 'returns a list of fields representing the link attributes' do
196
+ @representor_hash = @search_transition
197
+ expect(subject.attributes.size).to eq(1)
198
+ field = subject.attributes.first
199
+ expect(field).to be_an_instance_of(Field)
200
+ expect(field.scope).to eq('attribute')
201
+ expect(field.name).to eq(:status)
202
+ end
203
+ end
204
+
205
+ describe 'descriptors' do
206
+ it 'returns a list of fields representing the link attributes' do
207
+ @representor_hash = @search_transition
208
+ expect(subject.descriptors.size).to eq(2)
209
+ fields = subject.descriptors.all? { |item| item.instance_of?(Field) }
210
+ expect(fields).to eq(true)
211
+ end
212
+
213
+ it 'returns params as part of the descriptors' do
214
+ @representor_hash = @search_transition
215
+ field = subject.descriptors.first
216
+ expect(field).to be_an_instance_of(Field)
217
+ expect(field.scope).to eq('attribute')
218
+ end
219
+
220
+ it 'returns attributes as part of the descriptors' do
221
+ @representor_hash = @search_transition
222
+ field = subject.descriptors[1]
223
+ expect(field).to be_an_instance_of(Field)
224
+ expect(field.scope).to eq('href')
225
+ end
226
+ end
227
+
228
+ describe '#meta_links' do
229
+ context 'no metalinks' do
230
+ it 'returns an empty array' do
231
+ expect(subject.meta_links).to eq([])
232
+ end
233
+ end
234
+
235
+ it 'returns a list of Transitions' do
236
+ @representor_hash = @search_transition
237
+ links = subject.meta_links.all? { |item| item.instance_of?(Transition) }
238
+ expect(links).to eq(true)
239
+ end
240
+ it 'returns self as the first meta link' do
241
+ @representor_hash = @search_transition
242
+ link = subject.meta_links[0]
243
+ expect(link.rel).to eq(:self)
244
+ expect(link.uri).to eq('DRDs#drds/create')
245
+ end
246
+ it 'returns self as the first meta link' do
247
+ @representor_hash = @search_transition
248
+ link = subject.meta_links[1]
249
+ expect(link.rel).to eq(:help)
250
+ expect(link.uri).to eq("Forms/create")
251
+ end
252
+ end
253
+
254
+ describe '#uri' do
255
+ context 'the url does not have a template variable in the url' do
256
+ let(:transition) do
257
+ {
258
+ href: 'some.example.com',
259
+ rel: 'filter'
260
+ }
261
+ end
262
+ context 'params provided' do
263
+ it 'returns the url as it is' do
264
+ expect(Transition.new(transition).uri(uuid: 'uuid')).to eq(transition[:href])
265
+ end
266
+ end
267
+ context 'params not provided' do
268
+ it 'returns the url as it is' do
269
+ expect(Transition.new(transition).uri).to eq(transition[:href])
270
+ end
271
+ end
272
+ end
273
+
274
+ context 'the url has template variables in the base url and the query parameters' do
275
+ let(:transition) do
276
+ {
277
+ href: 'some.example.com/{uuid}?first_param=goodstuff{&filter}',
278
+ rel: 'filter'
279
+ }
280
+ end
281
+ let(:uuid) { SecureRandom.uuid}
282
+ let(:filter) {'cows'}
283
+ let(:full_url) {"some.example.com/#{uuid}?first_param=goodstuff&filter=cows"}
284
+ let(:not_templated_url) {'some.example.com/?first_param=goodstuff'}
285
+
286
+ it 'allows to create the url with the correct parameters' do
287
+ expect(Transition.new(transition).uri(uuid: uuid, filter: filter)).to eq(full_url)
288
+ end
289
+ it 'returns the url without template variables when there are no params' do
290
+ expect(Transition.new(transition).uri).to eq(not_templated_url)
291
+ end
292
+ it 'returns the url without template variables when the params does not match the template variable' do
293
+ expect(Transition.new(transition).uri(stuff: filter)).to eq(not_templated_url)
294
+ end
295
+ end
296
+ end
297
+
298
+ describe '#templated_uri' do
299
+ context 'the transition has a templated url' do
300
+ let(:transition) do
301
+ {
302
+ href: 'some.example.com/{uuid}?first_param=goodstuff{&filter}',
303
+ rel: 'filter'
304
+ }
305
+ end
306
+ it 'returns the templated url' do
307
+ expect(Transition.new(transition).templated_uri).to eq(transition[:href])
308
+ end
309
+ end
310
+ context 'the transition has a non-templated url' do
311
+ let(:transition) do
312
+ {
313
+ href: 'some.example.com',
314
+ rel: 'filter'
315
+ }
316
+ end
317
+ it 'returns the url' do
318
+ expect(Transition.new(transition).templated_uri).to eq(transition[:href])
319
+ end
320
+ end
321
+ end
322
+
323
+ describe '#templated?' do
324
+ context 'the transition has a templated url' do
325
+ let(:transition) do
326
+ {
327
+ href: 'some.example.com/{uuid}?first_param=goodstuff{&filter}',
328
+ rel: 'filter'
329
+ }
330
+ end
331
+ it 'returns true' do
332
+ expect(Transition.new(transition)).to be_templated
333
+ end
334
+ end
335
+ context 'the transition has a non-templated url' do
336
+ let(:transition) do
337
+ {
338
+ href: 'some.example.com',
339
+ rel: 'filter'
340
+ }
341
+ end
342
+ it 'returns false' do
343
+ expect(Transition.new(transition)).not_to be_templated
344
+ end
345
+ end
346
+ end
347
+ end
348
+ end
349
+ end