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,78 @@
1
+ require 'spec_helper'
2
+ require 'contextio/api/url_builder'
3
+
4
+ describe ContextIO::API::URLBuilder do
5
+ let(:api) { double('api') }
6
+
7
+ describe "#url_for" do
8
+ subject { ContextIO::API::URLBuilder.url_for(resource) }
9
+
10
+ context "when passed an unregistered class" do
11
+ let(:resource) { "String isn't registered."}
12
+
13
+ it "raises an exception" do
14
+ expect { subject }.to raise_exception(ContextIO::API::URLBuilder::Error)
15
+ end
16
+ end
17
+
18
+ context "when passed a ConnectToken" do
19
+ context "with an account" do
20
+ let(:account) { double('account', id: 'account_id') }
21
+ let(:resource) { ContextIO::ConnectToken.new(api, token: 'token', account: account) }
22
+
23
+ it { should eq('accounts/account_id/connect_tokens/token') }
24
+ end
25
+
26
+ context "without an account" do
27
+ let(:resource) { ContextIO::ConnectToken.new(api, token: 'token', api_attributes: { 'account' => { } }) }
28
+
29
+ it { should eq('connect_tokens/token') }
30
+ end
31
+ end
32
+
33
+ context "when passed a ConnectTokenCollection" do
34
+ context "with an account" do
35
+ let(:account) { double('account', id: 'account_id') }
36
+ let(:resource) { ContextIO::ConnectTokenCollection.new(api, account: account) }
37
+
38
+ it { should eq('accounts/account_id/connect_tokens') }
39
+ end
40
+
41
+ context "wiehout an account" do
42
+ let(:resource) { ContextIO::ConnectTokenCollection.new(api) }
43
+
44
+ it { should eq('connect_tokens') }
45
+ end
46
+ end
47
+
48
+ context "when passed an OAuthProvider" do
49
+ let(:resource) { ContextIO::OAuthProvider.new(api, provider_consumer_key: 'provider_consumer_key') }
50
+
51
+ it { should eq('oauth_providers/provider_consumer_key') }
52
+ end
53
+
54
+ context "when passed an OAuthProviderCollection" do
55
+ let(:resource) { ContextIO::OAuthProviderCollection.new(api) }
56
+
57
+ it { should eq('oauth_providers') }
58
+ end
59
+
60
+ context "when passed an EmailSettings" do
61
+ let(:resource) { ContextIO::EmailSettings.new(api, 'email') }
62
+
63
+ it { should eq('discovery') }
64
+ end
65
+
66
+ context "when passed an Account" do
67
+ let(:resource) { ContextIO::Account.new(api, id: 'account_id') }
68
+
69
+ it { should eq('accounts/account_id') }
70
+ end
71
+
72
+ context "when passed an AccountCollection" do
73
+ let(:resource) { ContextIO::AccountCollection.new(api) }
74
+
75
+ it { should eq('accounts') }
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,123 @@
1
+ require 'spec_helper'
2
+ require 'contextio/api'
3
+
4
+ describe ContextIO::API do
5
+ describe ".version" do
6
+ subject { ContextIO::API }
7
+
8
+ it "uses API version 2.0" do
9
+ expect(subject.version).to eq('2.0')
10
+ end
11
+ end
12
+
13
+ describe ".base_url" do
14
+ subject { ContextIO::API }
15
+
16
+ it "is https://api.context.io" do
17
+ expect(subject.base_url).to eq('https://api.context.io')
18
+ end
19
+ end
20
+
21
+ describe ".new" do
22
+ subject { ContextIO::API.new('test_key', 'test_secret') }
23
+
24
+ it "takes a key" do
25
+ expect(subject.key).to eq('test_key')
26
+ end
27
+
28
+ it "takes a secret" do
29
+ expect(subject.secret).to eq('test_secret')
30
+ end
31
+ end
32
+
33
+ describe "#path" do
34
+ context "without params" do
35
+ subject { ContextIO::API.new(nil, nil).path('test_command') }
36
+
37
+ it "puts the command in the path" do
38
+ expect(subject).to eq('/2.0/test_command')
39
+ end
40
+ end
41
+
42
+ context "with params" do
43
+ subject { ContextIO::API.new(nil, nil).path('test_command', foo: 1, bar: %w(a b c)) }
44
+
45
+ it "URL encodes the params" do
46
+ expect(subject).to eq('/2.0/test_command?foo=1&bar=a%2Cb%2Cc')
47
+ end
48
+ end
49
+
50
+ context "with a full URL" do
51
+ subject { ContextIO::API.new(nil, nil).path('https://api.context.io/2.0/test_command') }
52
+
53
+ it "strips out the command" do
54
+ expect(subject).to eq('/2.0/test_command')
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "#request" do
60
+ subject { ContextIO::API.new(nil, nil).request(:get, 'test') }
61
+
62
+ context "with a good response" do
63
+ before do
64
+ FakeWeb.register_uri(
65
+ :get,
66
+ 'https://api.context.io/2.0/test',
67
+ body: JSON.dump('a' => 'b', 'c' => 'd')
68
+ )
69
+ end
70
+
71
+ it "parses the JSON response" do
72
+ expect(subject).to eq('a' => 'b', 'c' => 'd')
73
+ end
74
+ end
75
+
76
+ context "with a bad response that has a body" do
77
+ before do
78
+ FakeWeb.register_uri(
79
+ :get,
80
+ 'https://api.context.io/2.0/test',
81
+ status: ['400', 'Bad Request'],
82
+ body: JSON.dump('type' => 'error', 'value' => 'nope')
83
+ )
84
+ end
85
+
86
+ it "raises an API error with the body message" do
87
+ expect { subject }.to raise_error(ContextIO::API::Error, 'nope')
88
+ end
89
+ end
90
+
91
+ context "with a bad response that has no body" do
92
+ before do
93
+ FakeWeb.register_uri(
94
+ :get,
95
+ 'https://api.context.io/2.0/test',
96
+ status: ['400', 'Bad Request']
97
+ )
98
+ end
99
+
100
+ it "raises an API error with the header message" do
101
+ expect { subject }.to raise_error(ContextIO::API::Error, 'Bad Request')
102
+ end
103
+ end
104
+ end
105
+
106
+ describe ".url_for" do
107
+ it "delegates to ContextIO::API::URLBuilder" do
108
+ ContextIO::API::URLBuilder.should_receive(:url_for).with('foo')
109
+
110
+ ContextIO::API.url_for('foo')
111
+ end
112
+ end
113
+
114
+ describe "#url_for" do
115
+ subject { ContextIO::API.new('test_key', 'test_secret') }
116
+
117
+ it "delegates to the class" do
118
+ ContextIO::API.should_receive(:url_for).with('foo')
119
+
120
+ subject.url_for('foo')
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+ require 'contextio/connect_token_collection'
3
+
4
+ describe ContextIO::ConnectTokenCollection do
5
+ let(:api) { double('API', url_for: 'url from api') }
6
+
7
+ subject { ContextIO::ConnectTokenCollection.new(api) }
8
+
9
+ describe "#create" do
10
+ before do
11
+ api.stub(:request).with(:post, anything, anything).and_return({ token: '1234' })
12
+ end
13
+
14
+ it "posts to the api" do
15
+ api.should_receive(:request).with(
16
+ :post,
17
+ 'url from api',
18
+ hash_including(callback_url: 'http://callback.com')
19
+ )
20
+
21
+ subject.create('http://callback.com')
22
+ end
23
+
24
+ it "doesn't make any more API calls than it needs to" do
25
+ api.should_not_receive(:request).with(:get, anything, anything)
26
+
27
+ subject.create('http://callback.com')
28
+ end
29
+
30
+ it "returns a ConnectToken" do
31
+ expect(subject.create('http://callback.com')).to be_a(ContextIO::ConnectToken)
32
+ end
33
+
34
+ it "takes an optional service level" do
35
+ api.should_receive(:request).with(
36
+ anything,
37
+ anything,
38
+ hash_including(service_level: 'PRO')
39
+ )
40
+
41
+ subject.create('http://callback.com', service_level: 'PRO')
42
+ end
43
+
44
+ it "takes an optional email" do
45
+ api.should_receive(:request).with(
46
+ anything,
47
+ anything,
48
+ hash_including(email: 'person@email.com')
49
+ )
50
+
51
+ subject.create('http://callback.com', email: 'person@email.com')
52
+ end
53
+
54
+ it "takes an optional first name" do
55
+ api.should_receive(:request).with(
56
+ anything,
57
+ anything,
58
+ hash_including(first_name: 'Bruno')
59
+ )
60
+
61
+ subject.create('http://callback.com', first_name: 'Bruno')
62
+ end
63
+
64
+ it "takes an optional last name" do
65
+ api.should_receive(:request).with(
66
+ anything,
67
+ anything,
68
+ hash_including(last_name: 'Morency')
69
+ )
70
+
71
+ subject.create('http://callback.com', last_name: 'Morency')
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ require 'contextio/connect_token'
3
+
4
+ describe ContextIO::ConnectToken do
5
+ let(:api) { double('API') }
6
+
7
+ describe ".new" do
8
+ subject { ContextIO::ConnectToken.new(api, token: '1234', foo: 'bar') }
9
+
10
+ it "takes an api handle" do
11
+ expect(subject.api).to eq(api)
12
+ end
13
+
14
+ it "assigns instance variables for hash arguments" do
15
+ expect(subject.instance_variable_get('@token')).to eq('1234')
16
+ expect(subject.instance_variable_get('@foo')).to eq('bar')
17
+ end
18
+
19
+ context "with a token passed in" do
20
+ it "doesn't raise an error" do
21
+ expect { ContextIO::ConnectToken.new(api, token: '1234') }.to_not raise_error
22
+ end
23
+ end
24
+
25
+ context "with neither a provider_token nor a resource_url passed in" do
26
+ it "raises an ArgumentError" do
27
+ expect { ContextIO::ConnectToken.new(api, foo: 'bar') }.to raise_error(ArgumentError)
28
+ end
29
+ end
30
+ end
31
+
32
+ describe "#token" do
33
+ context "when input at creation" do
34
+ subject { ContextIO::ConnectToken.new(api, token: '1234') }
35
+
36
+ it "uses the input key" do
37
+ api.should_not_receive(:request)
38
+
39
+ expect(subject.token).to eq('1234')
40
+ end
41
+ end
42
+
43
+ context "when not input at creation" do
44
+ subject { ContextIO::ConnectToken.new(api, resource_url: 'http://example.com/hitme') }
45
+
46
+ it "loads it from the API" do
47
+ api.should_receive(:request).with(
48
+ :get,
49
+ 'http://example.com/hitme'
50
+ ).and_return({
51
+ 'token' => 'baphoo'
52
+ })
53
+
54
+ expect(subject.token).to eq('baphoo')
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+ require 'contextio/email_settings'
3
+
4
+ describe ContextIO::EmailSettings do
5
+ let(:api) { double('API') }
6
+
7
+ subject { ContextIO::EmailSettings.new(api, 'email@email.com') }
8
+
9
+ describe ".new" do
10
+ context "without a source type passed in" do
11
+ it "takes an api handle" do
12
+ expect(subject.api).to eq(api)
13
+ end
14
+
15
+ it "takes an email address" do
16
+ expect(subject.email).to eq('email@email.com')
17
+ end
18
+
19
+ it "defaults the source type to 'IMAP'" do
20
+ expect(subject.source_type).to eq('IMAP')
21
+ end
22
+ end
23
+
24
+ context "with a source type passed in" do
25
+ subject { ContextIO::EmailSettings.new(api, 'email@email.com', 'FOO') }
26
+
27
+ it "takes a source type argument" do
28
+ expect(subject.source_type).to eq('FOO')
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "#resource_url" do
34
+ it "builds the right url" do
35
+ expect(subject.resource_url).to eq('discovery')
36
+ end
37
+ end
38
+
39
+ describe "#documentation" do
40
+ it "fetches it from the api" do
41
+ api.should_receive(:request).with(:get, anything, anything).and_return({ 'documentation' => ['foo', 'bar'] })
42
+ expect(subject.documentation).to eq(['foo', 'bar'])
43
+ end
44
+ end
45
+
46
+ describe "#found?" do
47
+ it "fetches it from the api" do
48
+ api.should_receive(:request).with(:get, anything, anything).and_return({ 'found' => true })
49
+ expect(subject).to be_found
50
+ end
51
+ end
52
+
53
+ describe "#type" do
54
+ it "fetches it from the api" do
55
+ api.should_receive(:request).with(:get, anything, anything).and_return({ 'type' => 'gmail' })
56
+ expect(subject.type).to eq('gmail')
57
+ end
58
+ end
59
+
60
+ describe "#server" do
61
+ it "fetches it from the api" do
62
+ api.should_receive(:request).with(:get, anything, anything).and_return({ 'imap' => { 'server' => 'imap.gmail.com' }})
63
+ expect(subject.server).to eq('imap.gmail.com')
64
+ end
65
+ end
66
+
67
+ describe "#username" do
68
+ it "fetches it from the api" do
69
+ api.should_receive(:request).with(:get, anything, anything).and_return({ 'imap' => { 'username' => 'ben' }})
70
+ expect(subject.username).to eq('ben')
71
+ end
72
+ end
73
+
74
+ describe "#port" do
75
+ it "fetches it from the api" do
76
+ api.should_receive(:request).with(:get, anything, anything).and_return({ 'imap' => { 'port' => 993 }})
77
+ expect(subject.port).to eq(993)
78
+ end
79
+ end
80
+
81
+ describe "#oauth?" do
82
+ it "fetches it from the api" do
83
+ api.should_receive(:request).with(:get, anything, anything).and_return({ 'imap' => { 'oauth' => false }})
84
+ expect(subject).to_not be_oauth
85
+ end
86
+ end
87
+
88
+ describe "#use_ssl?" do
89
+ it "fetches it from the api" do
90
+ api.should_receive(:request).with(:get, anything, anything).and_return({ 'imap' => { 'use_ssl' => false }})
91
+ expect(subject).to_not be_use_ssl
92
+ end
93
+ end
94
+
95
+ describe "#fetch_attributes" do
96
+ before do
97
+ api.stub(:request).with(:get, anything, anything).and_return({ 'foo' => 'bar' })
98
+ end
99
+
100
+ it "defines a getter if one doesn't already exist" do
101
+ subject.send(:fetch_attributes)
102
+
103
+ expect(subject.foo).to eq('bar')
104
+ end
105
+
106
+ it "hits the right URL" do
107
+ api.should_receive(:request).with(:get, 'discovery', 'email' => 'email@email.com', 'source_type' => 'IMAP')
108
+
109
+ subject.send(:fetch_attributes)
110
+ end
111
+ end
112
+ end