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.
- data/.document +4 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +5 -0
- data/Gemfile +3 -0
- data/LICENSE.md +20 -0
- data/README.md +62 -22
- data/Rakefile +46 -36
- data/contextio.gemspec +30 -0
- data/lib/contextio.rb +69 -583
- data/lib/contextio/account.rb +132 -0
- data/lib/contextio/account_collection.rb +57 -0
- data/lib/contextio/account_sync_data.rb +22 -0
- data/lib/contextio/api.rb +162 -0
- data/lib/contextio/api/association_helpers.rb +17 -0
- data/lib/contextio/api/resource.rb +230 -0
- data/lib/contextio/api/resource_collection.rb +174 -0
- data/lib/contextio/api/url_builder.rb +153 -0
- data/lib/contextio/body_part.rb +45 -0
- data/lib/contextio/body_part_collection.rb +13 -0
- data/lib/contextio/connect_token.rb +57 -0
- data/lib/contextio/connect_token_collection.rb +44 -0
- data/lib/contextio/contact.rb +43 -0
- data/lib/contextio/contact_collection.rb +21 -0
- data/lib/contextio/email_address.rb +53 -0
- data/lib/contextio/email_address_collection.rb +21 -0
- data/lib/contextio/email_settings.rb +146 -0
- data/lib/contextio/file.rb +92 -0
- data/lib/contextio/file_collection.rb +13 -0
- data/lib/contextio/folder.rb +56 -0
- data/lib/contextio/folder_collection.rb +18 -0
- data/lib/contextio/folder_sync_data.rb +32 -0
- data/lib/contextio/message.rb +96 -0
- data/lib/contextio/message_collection.rb +35 -0
- data/lib/contextio/oauth_provider.rb +29 -0
- data/lib/contextio/oauth_provider_collection.rb +46 -0
- data/lib/contextio/source.rb +55 -0
- data/lib/contextio/source_collection.rb +41 -0
- data/lib/contextio/source_sync_data.rb +23 -0
- data/lib/contextio/thread.rb +15 -0
- data/lib/contextio/thread_collection.rb +25 -0
- data/lib/contextio/version.rb +11 -0
- data/lib/contextio/webhook.rb +39 -0
- data/lib/contextio/webhook_collection.rb +26 -0
- data/spec/config.yml.example +3 -0
- data/spec/contextio/account_collection_spec.rb +78 -0
- data/spec/contextio/account_spec.rb +52 -0
- data/spec/contextio/api/association_helpers_spec.rb +28 -0
- data/spec/contextio/api/resource_collection_spec.rb +286 -0
- data/spec/contextio/api/resource_spec.rb +467 -0
- data/spec/contextio/api/url_builder_spec.rb +78 -0
- data/spec/contextio/api_spec.rb +123 -0
- data/spec/contextio/connect_token_collection_spec.rb +74 -0
- data/spec/contextio/connect_token_spec.rb +58 -0
- data/spec/contextio/email_settings_spec.rb +112 -0
- data/spec/contextio/oauth_provider_collection_spec.rb +36 -0
- data/spec/contextio/oauth_provider_spec.rb +120 -0
- data/spec/contextio/source_collection_spec.rb +57 -0
- data/spec/contextio/source_spec.rb +52 -0
- data/spec/contextio/version_spec.rb +10 -0
- data/spec/contextio_spec.rb +64 -0
- data/spec/spec_helper.rb +17 -0
- metadata +234 -12
- 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
|