codetocustomer-twitter 0.6.14
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/History +215 -0
- data/License +20 -0
- data/Notes +33 -0
- data/README.rdoc +19 -0
- data/Rakefile +103 -0
- data/VERSION.yml +4 -0
- data/examples/connect.rb +30 -0
- data/examples/friendship_existance.rb +13 -0
- data/examples/helpers/config_store.rb +38 -0
- data/examples/httpauth.rb +11 -0
- data/examples/ids.rb +13 -0
- data/examples/search.rb +15 -0
- data/examples/timeline.rb +19 -0
- data/examples/unauthorized.rb +16 -0
- data/examples/update.rb +11 -0
- data/examples/user.rb +5 -0
- data/lib/twitter.rb +63 -0
- data/lib/twitter/base.rb +165 -0
- data/lib/twitter/httpauth.rb +27 -0
- data/lib/twitter/oauth.rb +41 -0
- data/lib/twitter/request.rb +102 -0
- data/lib/twitter/search.rb +111 -0
- data/lib/twitter/trends.rb +29 -0
- data/test/fixtures/firehose.json +1 -0
- data/test/fixtures/follower_ids.json +1 -0
- data/test/fixtures/friend_ids.json +1 -0
- data/test/fixtures/friends_timeline.json +1 -0
- data/test/fixtures/rate_limit_exceeded.json +1 -0
- data/test/fixtures/replies.json +1 -0
- data/test/fixtures/search.json +1 -0
- data/test/fixtures/search_from_jnunemaker.json +1 -0
- data/test/fixtures/status.json +1 -0
- data/test/fixtures/status_show.json +1 -0
- data/test/fixtures/trends_current.json +1 -0
- data/test/fixtures/trends_current_exclude.json +1 -0
- data/test/fixtures/trends_daily.json +1 -0
- data/test/fixtures/trends_daily_date.json +1 -0
- data/test/fixtures/trends_daily_exclude.json +1 -0
- data/test/fixtures/trends_weekly.json +1 -0
- data/test/fixtures/trends_weekly_date.json +1 -0
- data/test/fixtures/trends_weekly_exclude.json +1 -0
- data/test/fixtures/user.json +1 -0
- data/test/fixtures/user_timeline.json +1 -0
- data/test/test_helper.rb +36 -0
- data/test/twitter/base_test.rb +95 -0
- data/test/twitter/httpauth_test.rb +76 -0
- data/test/twitter/oauth_test.rb +105 -0
- data/test/twitter/request_test.rb +217 -0
- data/test/twitter/search_test.rb +159 -0
- data/test/twitter/trends_test.rb +95 -0
- data/test/twitter_test.rb +38 -0
- metadata +200 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
class ConfigStore
|
2
|
+
attr_reader :file
|
3
|
+
|
4
|
+
def initialize(file)
|
5
|
+
@file = file
|
6
|
+
end
|
7
|
+
|
8
|
+
def load
|
9
|
+
@config ||= YAML::load(open(file))
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](key)
|
14
|
+
load
|
15
|
+
@config[key]
|
16
|
+
end
|
17
|
+
|
18
|
+
def []=(key, value)
|
19
|
+
@config[key] = value
|
20
|
+
end
|
21
|
+
|
22
|
+
def delete(*keys)
|
23
|
+
keys.each { |key| @config.delete(key) }
|
24
|
+
save
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def update(c={})
|
29
|
+
@config.merge!(c)
|
30
|
+
save
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def save
|
35
|
+
File.open(file, 'w') { |f| f.write(YAML.dump(@config)) }
|
36
|
+
self
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
2
|
+
require File.join(File.dirname(__FILE__), 'helpers', 'config_store')
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
config = ConfigStore.new("#{ENV['HOME']}/.twitter")
|
6
|
+
|
7
|
+
httpauth = Twitter::HTTPAuth.new(config['email'], config['password'])
|
8
|
+
base = Twitter::Base.new(httpauth)
|
9
|
+
|
10
|
+
pp base.user_timeline
|
11
|
+
pp base.verify_credentials
|
data/examples/ids.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
2
|
+
require File.join(File.dirname(__FILE__), 'helpers', 'config_store')
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
config = ConfigStore.new("#{ENV['HOME']}/.twitter")
|
6
|
+
|
7
|
+
oauth = Twitter::OAuth.new(config['token'], config['secret'])
|
8
|
+
oauth.authorize_from_access(config['atoken'], config['asecret'])
|
9
|
+
|
10
|
+
client = Twitter::Base.new(oauth)
|
11
|
+
|
12
|
+
puts client.friend_ids
|
13
|
+
puts client.follower_ids
|
data/examples/search.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
search = Twitter::Search.new.from('jnunemaker')
|
5
|
+
|
6
|
+
puts '*'*50, 'First Run', '*'*50
|
7
|
+
search.each { |result| pp result }
|
8
|
+
|
9
|
+
puts '*'*50, 'Second Run', '*'*50
|
10
|
+
search.each { |result| pp result }
|
11
|
+
|
12
|
+
puts '*'*50, 'Parameter Check', '*'*50
|
13
|
+
pp Twitter::Search.new('#austineats').fetch().results.first
|
14
|
+
pp Twitter::Search.new('#austineats').page(2).fetch().results.first
|
15
|
+
pp Twitter::Search.new('#austineats').since(1412737343).fetch().results.first
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
2
|
+
require File.join(File.dirname(__FILE__), 'helpers', 'config_store')
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
config = ConfigStore.new("#{ENV['HOME']}/.twitter")
|
6
|
+
|
7
|
+
oauth = Twitter::OAuth.new(config['token'], config['secret'])
|
8
|
+
oauth.authorize_from_access(config['atoken'], config['asecret'])
|
9
|
+
|
10
|
+
client = Twitter::Base.new(oauth)
|
11
|
+
|
12
|
+
pp client.friends_timeline
|
13
|
+
puts '*'*50
|
14
|
+
|
15
|
+
pp client.user_timeline
|
16
|
+
puts '*'*50
|
17
|
+
|
18
|
+
pp client.replies
|
19
|
+
puts '*'*50
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
puts 'User', '*'*50
|
5
|
+
pp Twitter.user('jnunemaker')
|
6
|
+
pp Twitter.user('snitch_test')
|
7
|
+
|
8
|
+
puts 'Status', '*'*50
|
9
|
+
pp Twitter.status(1533815199)
|
10
|
+
|
11
|
+
puts 'Friend Ids', '*'*50
|
12
|
+
pp Twitter.friend_ids('jnunemaker')
|
13
|
+
|
14
|
+
puts 'Follower Ids', '*'*50
|
15
|
+
pp Twitter.follower_ids('jnunemaker')
|
16
|
+
|
data/examples/update.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
2
|
+
require File.join(File.dirname(__FILE__), 'helpers', 'config_store')
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
config = ConfigStore.new("#{ENV['HOME']}/.twitter")
|
6
|
+
|
7
|
+
oauth = Twitter::OAuth.new(config['token'], config['secret'])
|
8
|
+
oauth.authorize_from_access(config['atoken'], config['asecret'])
|
9
|
+
|
10
|
+
client = Twitter::Base.new(oauth)
|
11
|
+
pp client.update('This is an update from the twitter gem')
|
data/examples/user.rb
ADDED
data/lib/twitter.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
gem 'oauth', '>= 0.3.5'
|
5
|
+
require 'oauth'
|
6
|
+
|
7
|
+
gem 'mash', '0.0.3'
|
8
|
+
require 'mash'
|
9
|
+
|
10
|
+
gem 'httparty', '0.4.3'
|
11
|
+
require 'httparty'
|
12
|
+
|
13
|
+
module Twitter
|
14
|
+
class TwitterError < StandardError
|
15
|
+
attr_reader :data
|
16
|
+
|
17
|
+
def initialize(data)
|
18
|
+
@data = data
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class RateLimitExceeded < TwitterError; end
|
24
|
+
class Unauthorized < TwitterError; end
|
25
|
+
class General < TwitterError; end
|
26
|
+
|
27
|
+
class Unavailable < StandardError; end
|
28
|
+
class InformTwitter < StandardError; end
|
29
|
+
class NotFound < StandardError; end
|
30
|
+
|
31
|
+
|
32
|
+
def self.firehose
|
33
|
+
response = HTTParty.get('http://twitter.com/statuses/public_timeline.json', :format => :json)
|
34
|
+
response.map { |tweet| Mash.new(tweet) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.user(id)
|
38
|
+
response = HTTParty.get("http://twitter.com/users/show/#{id}.json", :format => :json)
|
39
|
+
Mash.new(response)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.status(id)
|
43
|
+
response = HTTParty.get("http://twitter.com/statuses/show/#{id}.json", :format => :json)
|
44
|
+
Mash.new(response)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.friend_ids(id)
|
48
|
+
HTTParty.get("http://twitter.com/friends/ids/#{id}.json", :format => :json)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.follower_ids(id)
|
52
|
+
HTTParty.get("http://twitter.com/followers/ids/#{id}.json", :format => :json)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
directory = File.expand_path(File.dirname(__FILE__))
|
57
|
+
|
58
|
+
require File.join(directory, 'twitter', 'oauth')
|
59
|
+
require File.join(directory, 'twitter', 'httpauth')
|
60
|
+
require File.join(directory, 'twitter', 'request')
|
61
|
+
require File.join(directory, 'twitter', 'base')
|
62
|
+
require File.join(directory, 'twitter', 'search')
|
63
|
+
require File.join(directory, 'twitter', 'trends')
|
data/lib/twitter/base.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
module Twitter
|
2
|
+
class Base
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegators :client, :get, :post
|
6
|
+
|
7
|
+
attr_reader :client
|
8
|
+
|
9
|
+
def initialize(client)
|
10
|
+
@client = client
|
11
|
+
end
|
12
|
+
|
13
|
+
# Options: since_id, max_id, count, page, since
|
14
|
+
def friends_timeline(query={})
|
15
|
+
perform_get('/statuses/friends_timeline.json', :query => query)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Options: id, user_id, screen_name, since_id, max_id, page, since
|
19
|
+
def user_timeline(query={})
|
20
|
+
perform_get('/statuses/user_timeline.json', :query => query)
|
21
|
+
end
|
22
|
+
|
23
|
+
def status(id)
|
24
|
+
perform_get("/statuses/show/#{id}.json")
|
25
|
+
end
|
26
|
+
|
27
|
+
# Options: in_reply_to_status_id
|
28
|
+
def update(status, query={})
|
29
|
+
perform_post("/statuses/update.json", :body => {:status => status}.merge(query))
|
30
|
+
end
|
31
|
+
|
32
|
+
# Options: since_id, max_id, since, page
|
33
|
+
def replies(query={})
|
34
|
+
perform_get('/statuses/replies.json', :query => query)
|
35
|
+
end
|
36
|
+
|
37
|
+
def status_destroy(id)
|
38
|
+
perform_post("/statuses/destroy/#{id}.json")
|
39
|
+
end
|
40
|
+
|
41
|
+
# Options: id, user_id, screen_name, page
|
42
|
+
def friends(query={})
|
43
|
+
perform_get('/statuses/friends.json', :query => query)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Options: id, user_id, screen_name, page
|
47
|
+
def followers(query={})
|
48
|
+
perform_get('/statuses/followers.json', :query => query)
|
49
|
+
end
|
50
|
+
|
51
|
+
def user(id, query={})
|
52
|
+
perform_get("/users/show/#{id}.json", :query => query)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Options: since, since_id, page
|
56
|
+
def direct_messages(query={})
|
57
|
+
perform_get("/direct_messages.json", :query => query)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Options: since, since_id, page
|
61
|
+
def direct_messages_sent(query={})
|
62
|
+
perform_get("/direct_messages/sent.json", :query => query)
|
63
|
+
end
|
64
|
+
|
65
|
+
def direct_message_create(user, text)
|
66
|
+
perform_post("/direct_messages/new.json", :body => {:user => user, :text => text})
|
67
|
+
end
|
68
|
+
|
69
|
+
def direct_message_destroy(id)
|
70
|
+
perform_post("/direct_messages/destroy/#{id}.json")
|
71
|
+
end
|
72
|
+
|
73
|
+
def friendship_create(id, follow=false)
|
74
|
+
body = {}
|
75
|
+
body.merge!(:follow => follow) if follow
|
76
|
+
perform_post("/friendships/create/#{id}.json", :body => body)
|
77
|
+
end
|
78
|
+
|
79
|
+
def friendship_destroy(id)
|
80
|
+
perform_post("/friendships/destroy/#{id}.json")
|
81
|
+
end
|
82
|
+
|
83
|
+
def friendship_exists?(a, b)
|
84
|
+
perform_get("/friendships/exists.json", :query => {:user_a => a, :user_b => b})
|
85
|
+
end
|
86
|
+
|
87
|
+
# Options: id, user_id, screen_name
|
88
|
+
def friend_ids(query={})
|
89
|
+
perform_get("/friends/ids.json", :query => query, :mash => false)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Options: id, user_id, screen_name
|
93
|
+
def follower_ids(query={})
|
94
|
+
perform_get("/followers/ids.json", :query => query, :mash => false)
|
95
|
+
end
|
96
|
+
|
97
|
+
def verify_credentials
|
98
|
+
perform_get("/account/verify_credentials.json")
|
99
|
+
end
|
100
|
+
|
101
|
+
# Device must be sms, im or none
|
102
|
+
def update_delivery_device(device)
|
103
|
+
perform_post('/account/update_delivery_device.json', :body => {:device => device})
|
104
|
+
end
|
105
|
+
|
106
|
+
# One or more of the following must be present:
|
107
|
+
# profile_background_color, profile_text_color, profile_link_color,
|
108
|
+
# profile_sidebar_fill_color, profile_sidebar_border_color
|
109
|
+
def update_profile_colors(colors={})
|
110
|
+
perform_post('/account/update_profile_colors.json', :body => colors)
|
111
|
+
end
|
112
|
+
|
113
|
+
def rate_limit_status
|
114
|
+
perform_get('/account/rate_limit_status.json')
|
115
|
+
end
|
116
|
+
|
117
|
+
# One or more of the following must be present:
|
118
|
+
# name, email, url, location, description
|
119
|
+
def update_profile(body={})
|
120
|
+
perform_post('/account/update_profile.json', :body => body)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Options: id, page
|
124
|
+
def favorites(query={})
|
125
|
+
perform_get('/favorites.json', :query => query)
|
126
|
+
end
|
127
|
+
|
128
|
+
def favorite_create(id)
|
129
|
+
perform_post("/favorites/create/#{id}.json")
|
130
|
+
end
|
131
|
+
|
132
|
+
def favorite_destroy(id)
|
133
|
+
perform_post("/favorites/destroy/#{id}.json")
|
134
|
+
end
|
135
|
+
|
136
|
+
def enable_notifications(id)
|
137
|
+
perform_post("/notifications/follow/#{id}.json")
|
138
|
+
end
|
139
|
+
|
140
|
+
def disable_notifications(id)
|
141
|
+
perform_post("/notifications/leave/#{id}.json")
|
142
|
+
end
|
143
|
+
|
144
|
+
def block(id)
|
145
|
+
perform_post("/blocks/create/#{id}.json")
|
146
|
+
end
|
147
|
+
|
148
|
+
def unblock(id)
|
149
|
+
perform_post("/blocks/destroy/#{id}.json")
|
150
|
+
end
|
151
|
+
|
152
|
+
def help
|
153
|
+
perform_get('/help/test.json')
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
def perform_get(path, options={})
|
158
|
+
Twitter::Request.get(self, path, options)
|
159
|
+
end
|
160
|
+
|
161
|
+
def perform_post(path, options={})
|
162
|
+
Twitter::Request.post(self, path, options)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Twitter
|
2
|
+
class HTTPAuth
|
3
|
+
include HTTParty
|
4
|
+
format :plain
|
5
|
+
|
6
|
+
attr_reader :username, :password, :options
|
7
|
+
|
8
|
+
def initialize(username, password, options={})
|
9
|
+
@username, @password = username, password
|
10
|
+
@options = {:ssl => false}.merge(options)
|
11
|
+
self.class.base_uri "http#{'s' if options[:ssl]}://twitter.com"
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(uri, headers={})
|
15
|
+
self.class.get(uri, :headers => headers, :basic_auth => basic_auth)
|
16
|
+
end
|
17
|
+
|
18
|
+
def post(uri, body={}, headers={})
|
19
|
+
self.class.post(uri, :body => body, :headers => headers, :basic_auth => basic_auth)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def basic_auth
|
24
|
+
@basic_auth ||= {:username => @username, :password => @password}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Twitter
|
2
|
+
class OAuth
|
3
|
+
extend Forwardable
|
4
|
+
def_delegators :access_token, :get, :post
|
5
|
+
|
6
|
+
attr_reader :ctoken, :csecret, :consumer_options
|
7
|
+
|
8
|
+
# Options
|
9
|
+
# :sign_in => true to just sign in with twitter instead of doing oauth authorization
|
10
|
+
# (http://apiwiki.twitter.com/Sign-in-with-Twitter)
|
11
|
+
def initialize(ctoken, csecret, options={})
|
12
|
+
@ctoken, @csecret, @consumer_options = ctoken, csecret, {}
|
13
|
+
|
14
|
+
if options[:sign_in]
|
15
|
+
@consumer_options[:authorize_path] = '/oauth/authenticate'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def consumer
|
20
|
+
@consumer ||= ::OAuth::Consumer.new(@ctoken, @csecret, {:site => 'http://twitter.com'}.merge(consumer_options))
|
21
|
+
end
|
22
|
+
|
23
|
+
def request_token(params = {})
|
24
|
+
@request_token ||= consumer.get_request_token(params)
|
25
|
+
end
|
26
|
+
|
27
|
+
def authorize_from_request(rtoken, rsecret, params = {})
|
28
|
+
request_token = ::OAuth::RequestToken.new(consumer, rtoken, rsecret)
|
29
|
+
access_token = request_token.get_access_token(params)
|
30
|
+
@atoken, @asecret = access_token.token, access_token.secret
|
31
|
+
end
|
32
|
+
|
33
|
+
def access_token
|
34
|
+
@access_token ||= ::OAuth::AccessToken.new(consumer, @atoken, @asecret)
|
35
|
+
end
|
36
|
+
|
37
|
+
def authorize_from_access(atoken, asecret)
|
38
|
+
@atoken, @asecret = atoken, asecret
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Twitter
|
2
|
+
class Request
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def self.get(client, path, options={})
|
6
|
+
new(client, :get, path, options).perform
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.post(client, path, options={})
|
10
|
+
new(client, :post, path, options).perform
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :client, :method, :path, :options
|
14
|
+
|
15
|
+
def_delegators :client, :get, :post
|
16
|
+
|
17
|
+
def initialize(client, method, path, options={})
|
18
|
+
@client, @method, @path, @options = client, method, path, {:mash => true}.merge(options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def uri
|
22
|
+
@uri ||= begin
|
23
|
+
uri = URI.parse(path)
|
24
|
+
|
25
|
+
if options[:query] && options[:query] != {}
|
26
|
+
uri.query = to_query(options[:query])
|
27
|
+
end
|
28
|
+
|
29
|
+
uri.to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def perform
|
34
|
+
make_friendly(send("perform_#{method}"))
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def perform_get
|
39
|
+
send(:get, uri, options[:headers])
|
40
|
+
end
|
41
|
+
|
42
|
+
def perform_post
|
43
|
+
send(:post, uri, options[:body], options[:headers])
|
44
|
+
end
|
45
|
+
|
46
|
+
def make_friendly(response)
|
47
|
+
raise_errors(response)
|
48
|
+
data = parse(response)
|
49
|
+
options[:mash] ? mash(data) : data
|
50
|
+
end
|
51
|
+
|
52
|
+
def raise_errors(response)
|
53
|
+
case response.code.to_i
|
54
|
+
when 400
|
55
|
+
data = parse(response)
|
56
|
+
raise RateLimitExceeded.new(data), "(#{response.code}): #{response.message} - #{data['error'] if data}"
|
57
|
+
when 401
|
58
|
+
data = parse(response)
|
59
|
+
raise Unauthorized.new(data), "(#{response.code}): #{response.message} - #{data['error'] if data}"
|
60
|
+
when 403
|
61
|
+
data = parse(response)
|
62
|
+
raise General.new(data), "(#{response.code}): #{response.message} - #{data['error'] if data}"
|
63
|
+
when 404
|
64
|
+
raise NotFound, "(#{response.code}): #{response.message}"
|
65
|
+
when 500
|
66
|
+
raise InformTwitter, "Twitter had an internal error. Please let them know in the group. (#{response.code}): #{response.message}"
|
67
|
+
when 502..503
|
68
|
+
raise Unavailable, "(#{response.code}): #{response.message}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def parse(response)
|
73
|
+
Crack::JSON.parse(response.body)
|
74
|
+
end
|
75
|
+
|
76
|
+
def mash(obj)
|
77
|
+
if obj.is_a?(Array)
|
78
|
+
obj.map { |item| make_mash_with_consistent_hash(item) }
|
79
|
+
elsif obj.is_a?(Hash)
|
80
|
+
make_mash_with_consistent_hash(obj)
|
81
|
+
else
|
82
|
+
obj
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Lame workaround for the fact that mash doesn't hash correctly
|
87
|
+
def make_mash_with_consistent_hash(obj)
|
88
|
+
m = Mash.new(obj)
|
89
|
+
def m.hash
|
90
|
+
inspect.hash
|
91
|
+
end
|
92
|
+
return m
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_query(options)
|
96
|
+
options.inject([]) do |collection, opt|
|
97
|
+
collection << "#{opt[0]}=#{opt[1]}"
|
98
|
+
collection
|
99
|
+
end * '&'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|