drink-socially 0.0.4
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/LICENSE +674 -0
- data/README.md +54 -0
- data/config/endpoints.yml +231 -0
- data/lib/drink-socially.rb +43 -0
- data/lib/drink-socially/api.rb +124 -0
- data/lib/drink-socially/api/credential.rb +69 -0
- data/lib/drink-socially/api/notification.rb +13 -0
- data/lib/drink-socially/api/object.rb +83 -0
- data/lib/drink-socially/api/pagination.rb +73 -0
- data/lib/drink-socially/api/rate_limit.rb +17 -0
- data/lib/drink-socially/api/url_tokenizer.rb +47 -0
- data/lib/drink-socially/config.rb +48 -0
- data/lib/drink-socially/extensions/hash.rb +17 -0
- data/lib/drink-socially/http_service.rb +61 -0
- data/lib/drink-socially/http_service/response.rb +27 -0
- data/lib/drink-socially/version.rb +8 -0
- data/spec/cases/drink-socially/api/credential_spec.rb +107 -0
- data/spec/cases/drink-socially/api/object_spec.rb +112 -0
- data/spec/cases/drink-socially/api/pagination_spec.rb +43 -0
- data/spec/cases/drink-socially/api/rate_limit_spec.rb +15 -0
- data/spec/cases/drink-socially/api/url_tokenizer_spec.rb +41 -0
- data/spec/cases/drink-socially/api_spec.rb +79 -0
- data/spec/cases/drink-socially/config_spec.rb +95 -0
- data/spec/cases/drink-socially/extensions/hash_spec.rb +17 -0
- data/spec/cases/drink-socially/http_service/response_spec.rb +38 -0
- data/spec/cases/drink-socially/http_service_spec.rb +70 -0
- data/spec/cases/drink-socially/version_spec.rb +14 -0
- data/spec/cases/drink-socially_spec.rb +41 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/config.yml +3 -0
- metadata +202 -0
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe NRB::Untappd::API::Credential do
|
4
|
+
|
5
|
+
let(:app_credential_attrs) { { client_id: 'NewRepublicBrewing', client_secret: 'good_beer' } }
|
6
|
+
let(:app_credentials) { NRB::Untappd::API::Credential.new app_credential_attrs }
|
7
|
+
|
8
|
+
let(:user_credential_attrs) { { access_token: 'brundage' } }
|
9
|
+
let(:user_credentials) { NRB::Untappd::API::Credential.new user_credential_attrs }
|
10
|
+
|
11
|
+
|
12
|
+
context 'initialzation error checking' do
|
13
|
+
|
14
|
+
it 'blows up when creating a credential with no attributes' do
|
15
|
+
expect { NRB::Untappd::API::Credential.new }.to raise_error(NRB::Untappd::API::Credential::IncompleteCredentialError)
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
it 'blows up when creating a credential with just a client_id' do
|
20
|
+
expect { NRB::Untappd::API::Credential.new client_id: 'bmc' }.to raise_error(NRB::Untappd::API::Credential::IncompleteCredentialError)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
it 'blows up when creating a credential with just a client_secret' do
|
25
|
+
expect { NRB::Untappd::API::Credential.new client_secret: 'corn' }.to raise_error(NRB::Untappd::API::Credential::IncompleteCredentialError)
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
it 'does not raise error for a valid app credential' do
|
30
|
+
expect { app_credentials }.not_to raise_error
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
it 'does not raise error for a valid user credential' do
|
35
|
+
expect { user_credentials }.not_to raise_error
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
it 'returns the credentials as a hash' do
|
42
|
+
user_credentials.to_h.should eq user_credential_attrs
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
shared_examples_for 'has an accessor method' do
|
47
|
+
it "makes an accessor method for the accessor" do
|
48
|
+
credentials.should respond_to(accessor)
|
49
|
+
end
|
50
|
+
it "provides the accessor" do
|
51
|
+
credentials.send(accessor).should eq attrs[accessor]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
context 'app credentials' do
|
57
|
+
|
58
|
+
let(:attrs) { app_credential_attrs }
|
59
|
+
let(:credentials) { app_credentials }
|
60
|
+
|
61
|
+
it_behaves_like 'has an accessor method' do
|
62
|
+
let(:accessor) { :client_id }
|
63
|
+
end
|
64
|
+
|
65
|
+
it_behaves_like 'has an accessor method' do
|
66
|
+
let(:accessor) { :client_secret }
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'correctly answers is_app?' do
|
70
|
+
credentials.should be_is_app
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'correctly answers is_client?' do
|
74
|
+
credentials.should be_is_client
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'correctly answers is_user?' do
|
78
|
+
credentials.should_not be_is_user
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
context 'user credentials' do
|
85
|
+
|
86
|
+
let(:attrs) { user_credential_attrs }
|
87
|
+
let(:credentials) { user_credentials }
|
88
|
+
|
89
|
+
it_behaves_like 'has an accessor method' do
|
90
|
+
let(:accessor) { :access_token }
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'correctly answers is_app?' do
|
94
|
+
credentials.should_not be_is_app
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'correctly answers is_client?' do
|
98
|
+
credentials.should_not be_is_client
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'correctly answers is_user?' do
|
102
|
+
credentials.should be_is_user
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe NRB::Untappd::API::Object do
|
3
|
+
|
4
|
+
let(:body) { { llama: { llama: { llama: { llamas: :all_the_way_down,
|
5
|
+
dude: :sweet
|
6
|
+
} } } } }
|
7
|
+
let(:headers) { { stupid: :llama } }
|
8
|
+
let(:response) { NRB::Untappd::API::Object.new body: body, headers: headers, status: status }
|
9
|
+
let(:status) { 200 }
|
10
|
+
|
11
|
+
it 'has a pagination object' do
|
12
|
+
response.should respond_to(:pagination)
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
context 'extracting an object from the body' do
|
17
|
+
|
18
|
+
let(:path) { [ :llama, :llama, :llama ] }
|
19
|
+
let(:response) { NRB::Untappd::API::Object.new body: body, headers: headers, status: status, results_path: path }
|
20
|
+
let(:target) { response.body[:llama][:llama][:llama] }
|
21
|
+
|
22
|
+
it 'assingns the extraction to @results' do
|
23
|
+
response.results.should eq target
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'updates @attributes with the hash keys' do
|
27
|
+
response.attributes.collect(&:to_sym).sort.should eq target.keys.collect(&:to_sym).sort
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
it 'defines a methods on response for each hash key' do
|
32
|
+
target.keys.each { |m| response.should respond_to(m) }
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
context 'errored responses' do
|
39
|
+
|
40
|
+
let(:error_detail) { "This Venue ID is invalid" }
|
41
|
+
let(:error_type) { "invalid_param" }
|
42
|
+
let(:status) { 500 }
|
43
|
+
|
44
|
+
context 'v4' do
|
45
|
+
|
46
|
+
let(:body) { { meta: { code: 500,
|
47
|
+
error_detail: error_detail,
|
48
|
+
error_type: error_type,
|
49
|
+
response_time: { time: 0.089,
|
50
|
+
measure: "seconds" }
|
51
|
+
},
|
52
|
+
response: [] } }
|
53
|
+
|
54
|
+
it 'creates an errored response' do
|
55
|
+
response.should be_errored
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'has an error message' do
|
59
|
+
response.error_message.should_not be_nil
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'tells you the error detail' do
|
63
|
+
response.error_message.should match /#{error_detail}/
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'tells you the error type' do
|
67
|
+
response.error_message.should match /#{error_type}/
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
context 'legacy' do
|
74
|
+
|
75
|
+
let(:body) { { error: error_detail } }
|
76
|
+
|
77
|
+
it 'has an error message' do
|
78
|
+
response.error_message.should_not be_nil
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'tells you the error detail' do
|
82
|
+
response.error_message.should match /#{error_detail}/
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
context 'unrecognized' do
|
89
|
+
let(:body) { { } }
|
90
|
+
|
91
|
+
it 'has an error message' do
|
92
|
+
response.error_message.should_not be_nil
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
context 'successful requests' do
|
99
|
+
|
100
|
+
let(:status) { 200 }
|
101
|
+
|
102
|
+
it 'should not have an error_message' do
|
103
|
+
response.error_message.should be_nil
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe NRB::Untappd::API::Pagination do
|
3
|
+
|
4
|
+
let(:body) { { response: { pagination: pagination_hash } } }
|
5
|
+
let(:headers) { {} }
|
6
|
+
let(:max_id) { 16546450 }
|
7
|
+
let(:next_url) { "http://api.untappd.com/v4/brewery/checkins/8767?min_id=16546450" }
|
8
|
+
let(:pagination) { NRB::Untappd::API::Pagination.from_response(response) }
|
9
|
+
let(:pagination_hash) { {
|
10
|
+
since_url: since_url,
|
11
|
+
next_url: next_url,
|
12
|
+
max_id: max_id
|
13
|
+
} }
|
14
|
+
let(:response) { NRB::Untappd::API::Object.new body: body, headers: headers, status: status }
|
15
|
+
let(:since_url) { "http://api.untappd.com/v4/brewery/checkins/8767?min_id=16546450" }
|
16
|
+
let(:status) { 200 }
|
17
|
+
|
18
|
+
|
19
|
+
context 'from a response without pagination' do
|
20
|
+
|
21
|
+
let(:body) { { response: { } } }
|
22
|
+
|
23
|
+
it 'gives you nil' do
|
24
|
+
pagination.should be_nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
it 'gives you a pagination object' do
|
30
|
+
pagination.should be_a(NRB::Untappd::API::Pagination)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
it 'has the correct next_id' do
|
35
|
+
pagination.next_id.should eq (max_id + 1)
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
it 'has the correct prev_id' do
|
40
|
+
pagination.prev_id.should eq (max_id - 1)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe NRB::Untappd::API::RateLimit do
|
3
|
+
|
4
|
+
let(:headers) { { 'x-ratelimit-limit' => 5, 'x-ratelimit-remaining' => 4 } }
|
5
|
+
let(:rate_limit) { NRB::Untappd::API::RateLimit.new headers }
|
6
|
+
|
7
|
+
it 'correctly assigns limit' do
|
8
|
+
rate_limit.limit.should eq headers['x-ratelimit-limit']
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'correctly assigns remaining' do
|
12
|
+
rate_limit.remaining.should eq headers['x-ratelimit-remaining']
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe NRB::Untappd::API::URLTokenizer do
|
4
|
+
|
5
|
+
let(:map) { { token => :llama } }
|
6
|
+
let(:result) { tokenizer.tr }
|
7
|
+
let(:token) { :blark }
|
8
|
+
let(:tokenizer) { NRB::Untappd::API::URLTokenizer.new map: map, string: string }
|
9
|
+
|
10
|
+
|
11
|
+
it 'raises ArgumentError with no map' do
|
12
|
+
expect { NRB::Untappd::API::URLTokenizer.new string: "" }.to raise_error(ArgumentError)
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
it 'raises ArgumentError with no string' do
|
17
|
+
expect { NRB::Untappd::API::URLTokenizer.new map: map }.to raise_error(ArgumentError)
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
context 'a non-tokenized string' do
|
22
|
+
let(:string) { "some/url#{token}#its_cool" }
|
23
|
+
it 'leaves the string alone' do
|
24
|
+
result.should eq string
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
context 'a tokenized string' do
|
30
|
+
let(:string) { "some/:#{token}:/url" }
|
31
|
+
it 'changes a string with a single token' do
|
32
|
+
result.should eq "some/#{map[token]}/url"
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'changes multiple tokens' do
|
36
|
+
t = NRB::Untappd::API::URLTokenizer.new map: { token1: :llama, token2: :beer }, string: "/some/:token2:/path/:token1:"
|
37
|
+
t.tr.should eq "/some/beer/path/llama"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe NRB::Untappd::API do
|
4
|
+
|
5
|
+
context 'class methods' do
|
6
|
+
|
7
|
+
it 'has a version' do
|
8
|
+
NRB::Untappd::API.should respond_to :api_version
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'has a server' do
|
12
|
+
NRB::Untappd::API.should respond_to :server
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'default helper classes' do
|
16
|
+
|
17
|
+
it 'uses RateLimit' do
|
18
|
+
NRB::Untappd::API.default_rate_limit_class.should eq NRB::Untappd::API::RateLimit
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'uses Object' do
|
22
|
+
NRB::Untappd::API.default_response_class.should eq NRB::Untappd::API::Object
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
let(:api) { NRB::Untappd::API.new options }
|
31
|
+
let(:options) { { access_token: 'NewRepublicBrewing' } }
|
32
|
+
|
33
|
+
it 'has a credential accessor' do
|
34
|
+
api.should respond_to(:credential)
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
it 'has a credential object' do
|
39
|
+
api.credential.should be_a(NRB::Untappd::API::Credential)
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
context 'using an endpoint config' do
|
44
|
+
|
45
|
+
let(:api) { NRB::Untappd::API.new options }
|
46
|
+
let(:endpoints) { { endpoint1: { }, endpoint2: { } } }
|
47
|
+
let(:options) { { access_token: 'NewRepublicBrewing', endpoints: endpoints } }
|
48
|
+
|
49
|
+
|
50
|
+
it 'defines methods based on the top level of the config hash' do
|
51
|
+
endpoints.keys.each do |meth|
|
52
|
+
api.should respond_to(meth)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
context 'with method aliases' do
|
58
|
+
let(:endpoints) { { endpoint1: { method_aliases: method_aliases } } }
|
59
|
+
let(:method_aliases) { [ :an_alias ] }
|
60
|
+
it 'defines methods for the aliases' do
|
61
|
+
method_aliases.each do |meth|
|
62
|
+
api.should respond_to(meth)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
context 'with required arguments' do
|
69
|
+
let(:endpoints) { { method_name => { required_args: [:llama] } } }
|
70
|
+
let(:invalid_args) { { } }
|
71
|
+
let(:method_name) { :endpoint1 }
|
72
|
+
let(:valid_args) { { llama: :blark } }
|
73
|
+
it 'explodes without the required args' do
|
74
|
+
expect { api.send method_name, invalid_args }.to raise_error(ArgumentError)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
describe NRB::Untappd::Config do
|
5
|
+
|
6
|
+
shared_examples_for 'a config object' do
|
7
|
+
|
8
|
+
it 'defines accessors from a hash' do
|
9
|
+
config_hash.keys.each do |key|
|
10
|
+
config.should respond_to(key)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
it 'uses values from its data hash' do
|
16
|
+
config_hash.each do |k,v|
|
17
|
+
config.send(k).should eq v
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
it 'responds to :[]' do
|
23
|
+
config.should respond_to(:[])
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
it 'responds to #each' do
|
28
|
+
config.should respond_to(:each)
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
it 'responds to :keys' do
|
33
|
+
config.should respond_to(:keys)
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
it 'uses keys from its data hash' do
|
38
|
+
config.keys.should eq config.data.keys
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
it 'delegates [] to its data hash' do
|
43
|
+
config_hash.each do |k,v|
|
44
|
+
config[k].should eq v
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
context 'loading from a YAML file' do
|
52
|
+
let(:config_hash) { YAML.load_file filename }
|
53
|
+
let(:config) { NRB::Untappd::Config.new filename: filename }
|
54
|
+
let(:filename) { NRB::Untappd.config_file_path '../spec/support/config.yml' }
|
55
|
+
it_behaves_like 'a config object'
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
context 'loading from a stream' do
|
60
|
+
let(:config_hash) { { this: :is, a: :stream } }
|
61
|
+
let(:string) { config_hash.to_yaml }
|
62
|
+
let(:string_io) { StringIO.new(string) }
|
63
|
+
let(:config) { NRB::Untappd::Config.new stream: string_io }
|
64
|
+
it_behaves_like 'a config object'
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
context 'with no stream or filename argument' do
|
69
|
+
let(:config) { NRB::Untappd::Config.new Hash.new }
|
70
|
+
it 'explodes' do
|
71
|
+
expect { config }.to raise_error(NRB::Untappd::Config::NoConfig)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
context 'loaders' do
|
77
|
+
|
78
|
+
before :all do
|
79
|
+
Loader = Struct.new(:data) { def load_stream(*args); data; end }
|
80
|
+
end
|
81
|
+
|
82
|
+
let(:config_array) { [ config_hash ] }
|
83
|
+
let(:config_hash) { { change: :the, stream: :loader } }
|
84
|
+
let(:loader) { Loader.new config_array }
|
85
|
+
let(:config) { NRB::Untappd::Config.new stream_loader: loader, stream: {} }
|
86
|
+
|
87
|
+
it 'allows you to change the config loader' do
|
88
|
+
config.should be_a(NRB::Untappd::Config)
|
89
|
+
end
|
90
|
+
|
91
|
+
it_behaves_like 'a config object'
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|