contextio 0.5.0 → 1.0.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.
Files changed (65) hide show
  1. data/.document +4 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -0
  5. data/ChangeLog.md +5 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE.md +20 -0
  8. data/README.md +62 -22
  9. data/Rakefile +46 -36
  10. data/contextio.gemspec +30 -0
  11. data/lib/contextio.rb +69 -583
  12. data/lib/contextio/account.rb +132 -0
  13. data/lib/contextio/account_collection.rb +57 -0
  14. data/lib/contextio/account_sync_data.rb +22 -0
  15. data/lib/contextio/api.rb +162 -0
  16. data/lib/contextio/api/association_helpers.rb +17 -0
  17. data/lib/contextio/api/resource.rb +230 -0
  18. data/lib/contextio/api/resource_collection.rb +174 -0
  19. data/lib/contextio/api/url_builder.rb +153 -0
  20. data/lib/contextio/body_part.rb +45 -0
  21. data/lib/contextio/body_part_collection.rb +13 -0
  22. data/lib/contextio/connect_token.rb +57 -0
  23. data/lib/contextio/connect_token_collection.rb +44 -0
  24. data/lib/contextio/contact.rb +43 -0
  25. data/lib/contextio/contact_collection.rb +21 -0
  26. data/lib/contextio/email_address.rb +53 -0
  27. data/lib/contextio/email_address_collection.rb +21 -0
  28. data/lib/contextio/email_settings.rb +146 -0
  29. data/lib/contextio/file.rb +92 -0
  30. data/lib/contextio/file_collection.rb +13 -0
  31. data/lib/contextio/folder.rb +56 -0
  32. data/lib/contextio/folder_collection.rb +18 -0
  33. data/lib/contextio/folder_sync_data.rb +32 -0
  34. data/lib/contextio/message.rb +96 -0
  35. data/lib/contextio/message_collection.rb +35 -0
  36. data/lib/contextio/oauth_provider.rb +29 -0
  37. data/lib/contextio/oauth_provider_collection.rb +46 -0
  38. data/lib/contextio/source.rb +55 -0
  39. data/lib/contextio/source_collection.rb +41 -0
  40. data/lib/contextio/source_sync_data.rb +23 -0
  41. data/lib/contextio/thread.rb +15 -0
  42. data/lib/contextio/thread_collection.rb +25 -0
  43. data/lib/contextio/version.rb +11 -0
  44. data/lib/contextio/webhook.rb +39 -0
  45. data/lib/contextio/webhook_collection.rb +26 -0
  46. data/spec/config.yml.example +3 -0
  47. data/spec/contextio/account_collection_spec.rb +78 -0
  48. data/spec/contextio/account_spec.rb +52 -0
  49. data/spec/contextio/api/association_helpers_spec.rb +28 -0
  50. data/spec/contextio/api/resource_collection_spec.rb +286 -0
  51. data/spec/contextio/api/resource_spec.rb +467 -0
  52. data/spec/contextio/api/url_builder_spec.rb +78 -0
  53. data/spec/contextio/api_spec.rb +123 -0
  54. data/spec/contextio/connect_token_collection_spec.rb +74 -0
  55. data/spec/contextio/connect_token_spec.rb +58 -0
  56. data/spec/contextio/email_settings_spec.rb +112 -0
  57. data/spec/contextio/oauth_provider_collection_spec.rb +36 -0
  58. data/spec/contextio/oauth_provider_spec.rb +120 -0
  59. data/spec/contextio/source_collection_spec.rb +57 -0
  60. data/spec/contextio/source_spec.rb +52 -0
  61. data/spec/contextio/version_spec.rb +10 -0
  62. data/spec/contextio_spec.rb +64 -0
  63. data/spec/spec_helper.rb +17 -0
  64. metadata +234 -12
  65. data/README.textile +0 -29
@@ -0,0 +1,467 @@
1
+ require 'spec_helper'
2
+ require 'contextio/api/resource'
3
+
4
+ class ResourceCollection
5
+ def initialize(*args); end
6
+
7
+ ContextIO::API::AssociationHelpers.register_resource(self, :resources)
8
+ end
9
+
10
+ class Resource
11
+ def initialize(*args); end
12
+
13
+ ContextIO::API::AssociationHelpers.register_resource(self, :resource)
14
+ end
15
+
16
+ describe ContextIO::API::Resource do
17
+ let(:api) { double('api') }
18
+
19
+ describe ".new" do
20
+ let(:helper_class) do
21
+ Class.new do
22
+ include ContextIO::API::Resource
23
+
24
+ self.primary_key = :foo
25
+
26
+ def foo
27
+ 'defined in class'
28
+ end
29
+ end
30
+ end
31
+
32
+ subject { helper_class.new(api, foo: 'defined in method call', bar: 'baz') }
33
+
34
+ it "defines accessors for options passed in" do
35
+ expect(subject.bar).to eq('baz')
36
+ end
37
+
38
+ it "doesn't over-write accessors that already exist" do
39
+ expect(subject.foo).to eq('defined in class')
40
+ end
41
+ end
42
+
43
+ describe "#validate_options" do
44
+ context "with a string primary key" do
45
+ subject do
46
+ Class.new do
47
+ include ContextIO::API::Resource
48
+
49
+ self.primary_key = 'string'
50
+ end
51
+ end
52
+
53
+ it "matches a symbol" do
54
+ expect { subject.new(api, string: 'foo') }.to_not raise_error
55
+ end
56
+
57
+ it "matches a string" do
58
+ expect { subject.new(api, 'string' => 'foo') }.to_not raise_error
59
+ end
60
+
61
+ it "raises with missing keys" do
62
+ expect { subject.new(api, foo: 'bar') }.to raise_error
63
+ end
64
+
65
+ it "doesn't raise if resource_url is set" do
66
+ expect { subject.new(api, resource_url: 'some url') }.to_not raise_error
67
+ end
68
+ end
69
+
70
+ context "with a symbol primary key"
71
+ subject do
72
+ Class.new do
73
+ include ContextIO::API::Resource
74
+
75
+ self.primary_key = :symbol
76
+ end
77
+ end
78
+
79
+ it "matches a string" do
80
+ expect { subject.new(api, 'symbol' => 'foo') }.to_not raise_error
81
+ end
82
+
83
+ it "matches a symbol" do
84
+ expect { subject.new(api, symbol: 'bar') }.to_not raise_error
85
+ end
86
+
87
+ it "raises with missing keys" do
88
+ expect { subject.new(api, foo: 'bar') }.to raise_error
89
+ end
90
+
91
+ it "doesn't raise if resource_url is set" do
92
+ expect { subject.new(api, resource_url: 'some url') }.to_not raise_error
93
+ end
94
+ end
95
+
96
+ describe ".lazy_attributes" do
97
+ let(:helper_class) do
98
+ Class.new do
99
+ include ContextIO::API::Resource
100
+
101
+ lazy_attributes :foo, :longer_name
102
+ end
103
+ end
104
+
105
+ let(:api) do
106
+ double('api', request: {'foo' => 'set from API', 'longer-name' => 'bar'})
107
+ end
108
+
109
+ subject { helper_class.new(api, resource_url: 'resource_url') }
110
+
111
+ it "defines a method for the attribute" do
112
+ expect(subject).to respond_to(:foo)
113
+ end
114
+
115
+ context "when the attribute is set at creation" do
116
+ subject do
117
+ helper_class.new(api, resource_url: 'resource_url', foo: 'foo', 'longer-name' => 'bar')
118
+ end
119
+
120
+ it "returns the value set" do
121
+ expect(subject.foo).to eq('foo')
122
+ end
123
+
124
+ it "doesn't try to fetch from the API" do
125
+ subject.should_not_receive(:fetch_attributes)
126
+
127
+ subject.foo
128
+ end
129
+
130
+ it "subs '-' for '_' in attribute names" do
131
+ expect(subject.longer_name).to eq('bar')
132
+ end
133
+ end
134
+
135
+ context "when the attributes is not set at creation" do
136
+ it "tries to fetch from the API" do
137
+ api.should_receive(:request).with(:get, 'resource_url').
138
+ and_return({'foo' => 'set from API', 'longer-name' => 'bar'})
139
+
140
+ subject.foo
141
+ end
142
+
143
+ it "returns the value from the API" do
144
+ expect(subject.foo).to eq('set from API')
145
+ end
146
+
147
+ it "subs '-' for '_' in attribute names" do
148
+ expect(subject.longer_name).to eq('bar')
149
+ end
150
+ end
151
+ end
152
+
153
+ describe ".belongs_to" do
154
+ let(:helper_class) do
155
+ Class.new do
156
+ include ContextIO::API::Resource
157
+
158
+ belongs_to :resource
159
+ end
160
+ end
161
+
162
+ context "when one isn't passed in at creation" do
163
+ context "and one is returned from the API" do
164
+ subject { helper_class.new(api, resource_url: 'resource_url') }
165
+
166
+ before do
167
+ api.stub(:request).and_return(
168
+ {
169
+ 'resource' => {
170
+ 'resource_url' => 'relation_url'
171
+ }
172
+ }
173
+ )
174
+ end
175
+
176
+ it "makes a related object available" do
177
+ expect(subject.resource).to be_a(Resource)
178
+ end
179
+
180
+ it "passes keys from the api response to the new object" do
181
+ Resource.should_receive(:new).with(api, 'resource_url' => 'relation_url')
182
+
183
+ subject.resource
184
+ end
185
+
186
+ it "returns the same object each time" do
187
+ expect(subject.resource).to be(subject.resource)
188
+ end
189
+ end
190
+
191
+ context "and one isn't returned from the API" do
192
+ subject { helper_class.new(api, resource_url: 'resource_url') }
193
+
194
+ before do
195
+ api.stub(:request).and_return({ })
196
+ end
197
+
198
+ it "makes the resource nil" do
199
+ expect(subject.resource).to be_nil
200
+ end
201
+ end
202
+
203
+ context "and the API returns an empty hash" do
204
+ subject { helper_class.new(api, resource_url: 'resource_url') }
205
+
206
+ before do
207
+ api.stub(:request).and_return(
208
+ {
209
+ 'resource' => { }
210
+ }
211
+ )
212
+ end
213
+
214
+ it "makes the resource nil" do
215
+ expect(subject.resource).to be_nil
216
+ end
217
+ end
218
+
219
+ context "and the API returns an empty array" do
220
+ subject { helper_class.new(api, resource_url: 'resource_url') }
221
+
222
+ before do
223
+ api.stub(:request).and_return(
224
+ {
225
+ 'resource' => [ ]
226
+ }
227
+ )
228
+ end
229
+
230
+ it "makes the resource nil" do
231
+ expect(subject.resource).to be_nil
232
+ end
233
+ end
234
+ end
235
+
236
+ context "when one is passed in at creation" do
237
+ let(:relation_object) { Resource.new(api, resource_url: 'relation_url') }
238
+
239
+ subject { helper_class.new(api, resource_url: 'resource_url', resource: relation_object)}
240
+
241
+ it "makes the passed-in related object available" do
242
+ expect(subject.resource).to be(relation_object)
243
+ end
244
+
245
+ it "doesn't make any API calls" do
246
+ api.should_not_receive(:request)
247
+
248
+ subject.resource
249
+ end
250
+ end
251
+ end
252
+
253
+ describe ".has_many" do
254
+ let(:helper_class) do
255
+ Class.new do
256
+ include ContextIO::API::Resource
257
+
258
+ has_many :resources
259
+ self.association_name = :helper_class
260
+ end
261
+ end
262
+
263
+ context "when a collection isn't passed in at creation" do
264
+ context "and a collection is returned from the API" do
265
+ subject { helper_class.new(api, resource_url: 'resource_url') }
266
+
267
+ before do
268
+ api.stub(:request).and_return(
269
+ {
270
+ 'resources' => [{
271
+ 'resource_url' => 'relation_url'
272
+ }]
273
+ }
274
+ )
275
+ end
276
+
277
+ it "makes a related collection object available" do
278
+ expect(subject.resources).to be_a(ResourceCollection)
279
+ end
280
+
281
+ it "passes keys from the api response to the new object" do
282
+ ResourceCollection.should_receive(:new).with(api, hash_including(attribute_hashes: [{'resource_url' => 'relation_url'}]))
283
+
284
+ subject.resources
285
+ end
286
+
287
+ it "returns the same object each time" do
288
+ expect(subject.resources).to be(subject.resources)
289
+ end
290
+
291
+ it "passes its self to the new collection" do
292
+ ResourceCollection.should_receive(:new).with(anything, hash_including(:helper_class => subject))
293
+
294
+ subject.resources
295
+ end
296
+ end
297
+
298
+ context "and a collection isn't returned from the API" do
299
+ subject { helper_class.new(api, resource_url: 'resource_url') }
300
+
301
+ before do
302
+ api.stub(:request).and_return({ 'foo' => 'bar' })
303
+ end
304
+
305
+ it "tries the API only once" do
306
+ api.should_receive(:request).exactly(:once).and_return({ 'foo' => 'bar' })
307
+
308
+ subject.resources
309
+ subject.resources
310
+ end
311
+
312
+ it "still builds a relation object" do
313
+ expect(subject.resources).to be_a(ResourceCollection)
314
+ end
315
+
316
+ it "passes its self to the new collection" do
317
+ ResourceCollection.should_receive(:new).with(anything, hash_including(:helper_class => subject))
318
+
319
+ subject.resources
320
+ end
321
+ end
322
+ end
323
+
324
+ context "when an Array of Hashes is passed in at creation" do
325
+ subject do
326
+ helper_class.new(api, resource_url: 'resource_url', resources: [{'resource_url' => 'xxx'}])
327
+ end
328
+
329
+ it "makes a collection object available" do
330
+ expect(subject.resources).to be_a(ResourceCollection)
331
+ end
332
+
333
+ it "doesn't make any API calls" do
334
+ api.should_not_receive(:request)
335
+
336
+ subject.resources
337
+ end
338
+ end
339
+ end
340
+
341
+ describe "#fetch_attributes" do
342
+ let(:helper_class) do
343
+ Class.new do
344
+ include ContextIO::API::Resource
345
+ end
346
+ end
347
+
348
+ subject do
349
+ helper_class.new(api, resource_url: 'resource_url')
350
+ end
351
+
352
+ it "makes a request to the API" do
353
+ subject.api.should_receive(:request).with(:get, 'resource_url').and_return({})
354
+
355
+ subject.send(:fetch_attributes)
356
+ end
357
+
358
+ it "defines getter methods for new attributes returned" do
359
+ subject.api.stub(:request).and_return(foo: 'bar')
360
+
361
+ subject.send(:fetch_attributes)
362
+
363
+ expect(subject.foo).to eq('bar')
364
+ end
365
+
366
+ it "doesn't override existing getter methods" do
367
+ def subject.foo
368
+ 'hard coded value'
369
+ end
370
+
371
+ subject.api.stub(:request).and_return(foo: 'bar')
372
+
373
+ subject.send(:fetch_attributes)
374
+
375
+ expect(subject.foo).to eq('hard coded value')
376
+ end
377
+
378
+ it "stores the response hash" do
379
+ subject.api.stub(:request).and_return('foo' => 'bar')
380
+
381
+ subject.send(:fetch_attributes)
382
+
383
+ expect(subject.api_attributes).to eq('foo' => 'bar')
384
+ end
385
+ end
386
+
387
+ describe "#api_attributes" do
388
+ let(:helper_class) do
389
+ Class.new do
390
+ include ContextIO::API::Resource
391
+ end
392
+ end
393
+
394
+ let(:api) do
395
+ double('api', request: { 'foo' => 'bar', 'boolean' => false })
396
+ end
397
+
398
+ subject do
399
+ helper_class.new(api, resource_url: 'resource_url')
400
+ end
401
+
402
+ it "hits the API only on first call" do
403
+ api.should_receive(:request).exactly(:once)
404
+
405
+ subject.api_attributes
406
+ subject.api_attributes
407
+ end
408
+
409
+ it "caches the api response hash" do
410
+ expect(subject.api_attributes).to eq('foo' => 'bar', 'boolean' => false)
411
+ end
412
+ end
413
+
414
+ describe "#resource_url" do
415
+ let(:helper_class) do
416
+ Class.new do
417
+ include ContextIO::API::Resource
418
+
419
+ self.primary_key = :id
420
+ end
421
+ end
422
+
423
+ context "when one is set at creation" do
424
+ subject do
425
+ helper_class.new(api, resource_url: 'resource_url')
426
+ end
427
+
428
+ it "returns the one passed in" do
429
+ expect(subject.resource_url).to eq('resource_url')
430
+ end
431
+ end
432
+
433
+ context "when one is not set at creation" do
434
+ subject do
435
+ helper_class.new(api, id: '33f1')
436
+ end
437
+
438
+ it "delegates URL construction to the api" do
439
+ api.should_receive(:url_for).with(subject).and_return('helpers/33f1')
440
+
441
+ expect(subject.resource_url).to eq('helpers/33f1')
442
+ end
443
+ end
444
+ end
445
+
446
+ describe "#delete" do
447
+ let(:helper_class) do
448
+ Class.new do
449
+ include ContextIO::API::Resource
450
+ end
451
+ end
452
+
453
+ subject do
454
+ helper_class.new(double('api', :request => {'success' => true}), resource_url: 'resource_url')
455
+ end
456
+
457
+ it "makes a request to the API" do
458
+ subject.api.should_receive(:request).with(:delete, 'resource_url')
459
+
460
+ subject.delete
461
+ end
462
+
463
+ it "returns the contents of the 'success' key" do
464
+ expect(subject.delete).to eq(true)
465
+ end
466
+ end
467
+ end