grackle 0.1.10 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +7 -0
- data/README.rdoc +56 -42
- data/lib/grackle.rb +1 -17
- data/lib/grackle/client.rb +33 -17
- data/lib/grackle/transport.rb +54 -6
- data/lib/grackle/version.rb +9 -0
- data/test/{test_client.rb → client_test.rb} +64 -6
- data/test/{test_handlers.rb → handlers_test.rb} +1 -1
- data/test/test_helper.rb +4 -2
- metadata +18 -20
- data/grackle.gemspec +0 -40
- data/test/test_grackle.rb +0 -4
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 0.2.0 (2012-6-10)
|
2
|
+
* New auto_append_format attribute (thanks @jcsalterego) for specifying whether or not to automatically add .json, etc to a request URI
|
3
|
+
* New response attribute which captures raw info about the response from the most recent request. This permits access to response headers with rate limit information. Thanks to @mandoescamilla.
|
4
|
+
* Added Twitter's media upload endpoint. Thanks @jbrennon.
|
5
|
+
* Modernized the code a bit with better test running and a new gemspec
|
6
|
+
* Now testing in 1.8.6, 1.8.7, 1.9.2 and 1.9.3
|
7
|
+
|
1
8
|
== 0.1.10 (2010-6-13)
|
2
9
|
* Changed :v1 (api.twitter.com/1) to be the default API instead of REST. :rest is now deprecated
|
3
10
|
* Fixed issue with DELETE requests not being able to have form encoded body parameters. This was causing the list membership delete method to fail. As a side note, it appears that Twitter is actually violating the HTTP 1.1 spec on this one since RFC 2616 states that a DELETE "requests that the origin server delete the resource identified by the Request-URI" (note no mention of any "enclosed entity").
|
data/README.rdoc
CHANGED
@@ -1,30 +1,32 @@
|
|
1
1
|
=grackle
|
2
2
|
by Hayes Davis
|
3
3
|
- http://twitter.com/hayesdavis
|
4
|
-
- hayes [at]
|
5
|
-
- http://
|
6
|
-
- http://www.appozite.com
|
4
|
+
- hayes [at] unionmetrics [dot] com
|
5
|
+
- http://unionmetrics.com
|
7
6
|
- http://hayesdavis.net
|
8
7
|
|
9
8
|
== DESCRIPTION
|
10
|
-
Grackle is a lightweight Ruby wrapper around the Twitter REST and Search APIs.
|
11
|
-
Twitter API to build http://cheaptweet.com
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
9
|
+
Grackle is a lightweight Ruby wrapper around the Twitter REST and Search APIs.
|
10
|
+
It's based on my experience using the Twitter API to build http://cheaptweet.com
|
11
|
+
and http://tweetreach.com. The main goal of Grackle is to never require a
|
12
|
+
release when the Twitter API changes (which it often does) or in the face of a
|
13
|
+
particular Twitter API bug. As such it's somewhat different from other Twitter
|
14
|
+
API libraries. It doesn't try to hide the Twitter "methods" under an access
|
15
|
+
layer nor does it introduce concrete classes for the various objects returned by
|
16
|
+
Twitter. Instead, calls to the Grackle client map directly to Twitter API URLs.
|
17
|
+
The objects returned by API calls are generated as OpenStructs on the fly and
|
18
|
+
make no assumptions about the presence or absence of any particular attributes.
|
19
|
+
Taking this approach means that changes to URLs used by Twitter, parameters
|
20
|
+
required by those URLs or return values will not require a new release. It will
|
21
|
+
potentially require, however, some modifications to your code that uses Grackle.
|
21
22
|
|
22
23
|
=== Support and Announcements
|
23
|
-
The preferred forum for questions and discussions is the Google group at
|
24
|
-
You can email me directly or @reply me
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
The preferred forum for questions and discussions is the Google group at
|
25
|
+
http://groups.google.com/group/gracklerb. You can email me directly or @reply me
|
26
|
+
on Twitter, but the group is better since the questions and responses will be
|
27
|
+
available to everyone. I'll also make announcements there. There are some
|
28
|
+
examples on the wiki at http://wiki.github.com/hayesdavis/grackle. If you prefer
|
29
|
+
your information in 140 characters, follow @gracklerb[http://twitter.com/gracklerb].
|
28
30
|
|
29
31
|
==USING GRACKLE
|
30
32
|
|
@@ -32,9 +34,6 @@ Before you do anything else, you'll need to
|
|
32
34
|
require 'grackle'
|
33
35
|
|
34
36
|
===Creating a Grackle::Client
|
35
|
-
====Using Basic Auth
|
36
|
-
client = Grackle::Client.new(:auth=>{:type=>:basic,:username=>'your_user',:password=>'yourpass'})
|
37
|
-
|
38
37
|
====Using OAuth
|
39
38
|
client = Grackle::Client.new(:auth=>{
|
40
39
|
:type=>:oauth,
|
@@ -42,11 +41,18 @@ Before you do anything else, you'll need to
|
|
42
41
|
:token=>'ACCESSTOKENACQUIREDONUSERSBEHALF', :token_secret=>'SUPERSECRETACCESSTOKENSECRET'
|
43
42
|
})
|
44
43
|
|
44
|
+
OAuth can be a bit complicated. See the wiki[http://wiki.github.com/hayesdavis/grackle/grackle-and-oauth]
|
45
|
+
for more information on acquiring the keys, tokens and secrets needed to
|
46
|
+
successfully authenticate with OAuth.
|
47
|
+
|
45
48
|
====Using No Auth
|
46
49
|
client = Grackle::Client.new
|
47
50
|
|
48
|
-
|
49
|
-
|
51
|
+
====Using Basic Auth (DEPRECATED)
|
52
|
+
As of August 31st, 2010, Twitter has deprecated basic authentication in favor of OAuth. Please refer to the section on OAuth authentication.
|
53
|
+
client = Grackle::Client.new(:auth=>{:type=>:basic,:username=>'your_user',:password=>'yourpass'})
|
54
|
+
|
55
|
+
See Grackle::Client for more information about valid arguments to the constructor. It's quite configurable. Among other things, you can turn on ssl and specify custom headers. The calls below are pretty much as simple as it gets.
|
50
56
|
|
51
57
|
===Grackle Method Syntax
|
52
58
|
Grackle uses a method syntax that corresponds to the Twitter API URLs with a few twists. Where you would have a slash in
|
@@ -64,7 +70,7 @@ format (usually JSON, but see Formats section below):
|
|
64
70
|
client.users.show? :screen_name=>'some_user' #http://twitter.com/users/show.json?screen_name=some_user
|
65
71
|
|
66
72
|
You can force XML format by doing:
|
67
|
-
client.users.show.xml? :screen_name=>'some_user' #http://twitter.com/users/show.xml?
|
73
|
+
client.users.show.xml? :screen_name=>'some_user' #http://twitter.com/users/show.xml?screen_name=some_user
|
68
74
|
|
69
75
|
You can force JSON:
|
70
76
|
client.users.show.json? :screen_name=>'some_user' #http://twitter.com/users/show.json?screen_name=some_user
|
@@ -73,7 +79,7 @@ Or, since Twitter also allows certain ids/screen_names to be part of their URLs,
|
|
73
79
|
client.users.show.some_user? #http://twitter.com/users/show/some_user.json
|
74
80
|
|
75
81
|
If you use an explicit format, you can leave off the "?" like so:
|
76
|
-
client.users.show.xml :screen_name=>'some_user' #http://twitter.com/users/show.xml?
|
82
|
+
client.users.show.xml :screen_name=>'some_user' #http://twitter.com/users/show.xml?screen_name=some_user
|
77
83
|
|
78
84
|
===POSTing data
|
79
85
|
To use Twitter API methods that require an HTTP POST, you need to end your method chain with a bang (!)
|
@@ -127,6 +133,23 @@ Search and REST requests are all built using the same method chaining and termin
|
|
127
133
|
Regardless of the format used, Grackle returns an OpenStruct (actually a Grackle::TwitterStruct) of data. The attributes
|
128
134
|
available on these structs correspond to the data returned by Twitter.
|
129
135
|
|
136
|
+
===Rate Limits and the Response
|
137
|
+
The Grackle client has a response method which is populated with information
|
138
|
+
about the most recent response received as a result of a request. This response
|
139
|
+
contains the requested URI, the HTTP status code, a subset of the response
|
140
|
+
headers and the raw response body. The response headers are the most useful
|
141
|
+
because they can be used to retrieve the rate limit information that Twitter
|
142
|
+
includes in a response.
|
143
|
+
|
144
|
+
user = client.users.show.hayesdavis?
|
145
|
+
client.response.headers["X-Ratelimit-Remaining"]
|
146
|
+
|
147
|
+
Not all headers returned by Twitter are included by default. You can control
|
148
|
+
which headers are accessible with the response_headers attribute on the Client.
|
149
|
+
By default, the important rate limit headers are returned. Please note that all
|
150
|
+
header values will be Strings so you'll need to convert rate limits, etc to ints
|
151
|
+
in your code.
|
152
|
+
|
130
153
|
===Dealing with Errors
|
131
154
|
If the request to Twitter does not return a status code of 200, then a TwitterError is thrown. This contains the HTTP method used,
|
132
155
|
the full request URI, the response status, the response body in text and a response object build by parsing the formatted error
|
@@ -164,26 +187,17 @@ You'll need the following gems to use all features of Grackle:
|
|
164
187
|
- mime-types
|
165
188
|
|
166
189
|
=== Ruby Version Support
|
167
|
-
Grackle
|
168
|
-
the exception of OAuth. The OAuth gem used by Grackle has not been updated fully
|
169
|
-
to support 1.9. Please see this thread[http://groups.google.com/group/oauth-ruby/browse_thread/thread/d0851a907878cd22]
|
170
|
-
for more information.
|
190
|
+
Grackle is tested on 1.8.6, 1.8.7, 1.9.2 and 1.9.3.
|
171
191
|
|
172
|
-
|
173
|
-
|
192
|
+
If you are using 1.8.6, please be aware that certain newer versions of the json
|
193
|
+
and oauth gems are not compatible with that Ruby version. You can use older
|
194
|
+
version and grackle will work fine. On 1.8.6, I recommend using oauth 0.4.4 and
|
195
|
+
json < 1.7.
|
174
196
|
|
175
197
|
== INSTALL
|
176
|
-
|
177
|
-
in your sources, you can do the following:
|
178
|
-
sudo gem install grackle
|
179
|
-
|
180
|
-
If you haven't yet setup gemcutter in your sources, go to http://gemcutter.org and follow the instructions there.
|
181
|
-
They will likely tell you to do the following:
|
182
|
-
sudo gem install gemcutter
|
183
|
-
sudo gem tumble
|
198
|
+
Grackle is available on rubygems.org. Just do the usual:
|
184
199
|
|
185
|
-
|
186
|
-
sudo gem install grackle
|
200
|
+
gem install grackle
|
187
201
|
|
188
202
|
== LICENSE
|
189
203
|
|
data/lib/grackle.rb
CHANGED
@@ -1,20 +1,3 @@
|
|
1
|
-
module Grackle
|
2
|
-
|
3
|
-
# :stopdoc:
|
4
|
-
VERSION = '0.1.10'
|
5
|
-
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
6
|
-
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
7
|
-
# :startdoc:
|
8
|
-
|
9
|
-
# Returns the version string for the library.
|
10
|
-
def self.version
|
11
|
-
VERSION
|
12
|
-
end
|
13
|
-
|
14
|
-
end # module Grackle
|
15
|
-
|
16
|
-
$:.unshift File.dirname(__FILE__)
|
17
|
-
|
18
1
|
require 'ostruct'
|
19
2
|
require 'open-uri'
|
20
3
|
require 'net/http'
|
@@ -25,6 +8,7 @@ require 'oauth'
|
|
25
8
|
require 'oauth/client'
|
26
9
|
require 'mime/types'
|
27
10
|
|
11
|
+
require 'grackle/version'
|
28
12
|
require 'grackle/utils'
|
29
13
|
require 'grackle/transport'
|
30
14
|
require 'grackle/handlers'
|
data/lib/grackle/client.rb
CHANGED
@@ -86,10 +86,18 @@ module Grackle
|
|
86
86
|
# refer to it wherever Grackle::Client uses an API symbol. You may wish
|
87
87
|
# to do this when Twitter introduces API versions greater than 1.
|
88
88
|
TWITTER_API_HOSTS = {
|
89
|
-
:search=>'search.twitter.com', :v1=>'api.twitter.com/1'
|
89
|
+
:search=>'search.twitter.com', :v1=>'api.twitter.com/1',
|
90
|
+
:upload=>'upload.twitter.com/1'
|
90
91
|
}
|
91
92
|
TWITTER_API_HOSTS[:rest] = TWITTER_API_HOSTS[:v1]
|
92
|
-
|
93
|
+
|
94
|
+
# Contains the response headers from twitter
|
95
|
+
DEFAULT_RESPONSE_HEADERS =[
|
96
|
+
'x-ratelimit-limit',
|
97
|
+
'x-ratelimit-remaining',
|
98
|
+
'x-ratelimit-reset'
|
99
|
+
]
|
100
|
+
|
93
101
|
#Basic OAuth information needed to communicate with Twitter
|
94
102
|
TWITTER_OAUTH_SPEC = {
|
95
103
|
:request_token_path=>'/oauth/request_token',
|
@@ -98,24 +106,28 @@ module Grackle
|
|
98
106
|
}
|
99
107
|
|
100
108
|
attr_accessor :auth, :handlers, :default_format, :headers, :ssl, :api,
|
101
|
-
:transport, :request, :api_hosts, :timeout, :auto_append_ids
|
109
|
+
:transport, :request, :api_hosts, :timeout, :auto_append_ids,
|
110
|
+
:auto_append_format, :response_headers, :response
|
102
111
|
|
103
112
|
# Arguments (all are optional):
|
104
|
-
# - :username
|
105
|
-
# - :password
|
106
|
-
# - :handlers
|
107
|
-
# - :default_format
|
108
|
-
# - :headers
|
109
|
-
# - :ssl
|
110
|
-
# - :api
|
111
|
-
# - :auth
|
112
|
-
# - :type=>:basic
|
113
|
-
# - :type=>:oauth
|
113
|
+
# - :username - Twitter username to authenticate with (deprecated in favor of :auth arg)
|
114
|
+
# - :password - Twitter password to authenticate with (deprecated in favor of :auth arg)
|
115
|
+
# - :handlers - Hash of formats to Handler instances (e.g. {:json=>CustomJSONHandler.new})
|
116
|
+
# - :default_format - Symbol of format to use when no format is specified in an API call (e.g. :json, :xml)
|
117
|
+
# - :headers - Hash of string keys and values for headers to pass in the HTTP request to twitter
|
118
|
+
# - :ssl - true or false to turn SSL on or off. Default is off (i.e. http://)
|
119
|
+
# - :api - one of :rest, :search or :v1. :v1 is the default and :rest is now deprecated
|
120
|
+
# - :auth - Hash of authentication type and credentials. Must have :type key with value one of :basic or :oauth
|
121
|
+
# - :type=>:basic - Include :username and :password keys
|
122
|
+
# - :type=>:oauth - Include :consumer_key, :consumer_secret, :token and :token_secret keys
|
123
|
+
# - :auto_append_format - true or false to include format in URI (e.g. /test.json). Default is true
|
124
|
+
# - :response_headers - array of headers to return from the response
|
114
125
|
def initialize(options={})
|
115
126
|
self.transport = Transport.new
|
116
127
|
self.handlers = {:json=>Handlers::JSONHandler.new,:xml=>Handlers::XMLHandler.new,:unknown=>Handlers::StringHandler.new}
|
117
128
|
self.handlers.merge!(options[:handlers]||{})
|
118
129
|
self.default_format = options[:default_format] || :json
|
130
|
+
self.auto_append_format = options[:auto_append_format] == false ? false : true
|
119
131
|
self.headers = {"User-Agent"=>"Grackle/#{Grackle::VERSION}"}.merge!(options[:headers]||{})
|
120
132
|
self.ssl = options[:ssl] == true
|
121
133
|
self.api = options[:api] || :v1
|
@@ -123,6 +135,7 @@ module Grackle
|
|
123
135
|
self.timeout = options[:timeout] || 60
|
124
136
|
self.auto_append_ids = options[:auto_append_ids] == false ? false : true
|
125
137
|
self.auth = {}
|
138
|
+
self.response_headers = options[:response_headers] || DEFAULT_RESPONSE_HEADERS
|
126
139
|
if options.has_key?(:username) || options.has_key?(:password)
|
127
140
|
#Use basic auth if :username and :password args are passed in
|
128
141
|
self.auth.merge!({:type=>:basic,:username=>options[:username],:password=>options[:password]})
|
@@ -218,7 +231,9 @@ module Grackle
|
|
218
231
|
id = request.params.delete(:id)
|
219
232
|
request << "/#{id}" if id
|
220
233
|
end
|
221
|
-
|
234
|
+
if auto_append_format
|
235
|
+
request << ".#{format}"
|
236
|
+
end
|
222
237
|
res = send_request
|
223
238
|
process_response(format,res)
|
224
239
|
ensure
|
@@ -230,10 +245,11 @@ module Grackle
|
|
230
245
|
http_method = (
|
231
246
|
request.params.delete(:__method) or request.method or :get
|
232
247
|
)
|
233
|
-
transport.request(
|
248
|
+
@response = transport.request(
|
234
249
|
http_method, request.url,
|
235
250
|
:auth=>auth,:headers=>headers,
|
236
|
-
:params=>request.params,:timeout
|
251
|
+
:params=>request.params,:timeout=>timeout,
|
252
|
+
:response_headers=>response_headers
|
237
253
|
)
|
238
254
|
rescue => e
|
239
255
|
puts e
|
@@ -288,4 +304,4 @@ module Grackle
|
|
288
304
|
end
|
289
305
|
end
|
290
306
|
end
|
291
|
-
end
|
307
|
+
end
|
data/lib/grackle/transport.rb
CHANGED
@@ -1,12 +1,50 @@
|
|
1
1
|
module Grackle
|
2
|
-
|
2
|
+
|
3
|
+
class Headers #:nodoc:
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@data = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](name)
|
11
|
+
res = @data[name.downcase.to_sym]
|
12
|
+
res ? res.join(",") : nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def []=(name,value)
|
16
|
+
@data[name.downcase.to_sym] = [value]
|
17
|
+
end
|
18
|
+
|
19
|
+
def add(name,value)
|
20
|
+
res = (@data[name.downcase.to_sym] ||= [])
|
21
|
+
res << value
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_all(name,values)
|
25
|
+
res = (@data[name.downcase.to_sym] ||= [])
|
26
|
+
res.push(*values)
|
27
|
+
end
|
28
|
+
|
29
|
+
def each
|
30
|
+
@data.each do |name,value|
|
31
|
+
yield(name.to_s,value.join(","))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def size
|
36
|
+
@data.size
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
3
40
|
class Response #:nodoc:
|
4
|
-
attr_accessor :method, :request_uri, :status, :body
|
41
|
+
attr_accessor :method, :request_uri, :status, :body, :headers
|
5
42
|
|
6
|
-
def initialize(method,request_uri,status,body)
|
43
|
+
def initialize(method,request_uri,status,body,headers)
|
7
44
|
self.method = method
|
8
45
|
self.request_uri = request_uri
|
9
46
|
self.status = status
|
47
|
+
self.headers = headers
|
10
48
|
self.body = body
|
11
49
|
end
|
12
50
|
end
|
@@ -32,6 +70,7 @@ module Grackle
|
|
32
70
|
# - :headers - a hash of headers to send with the request
|
33
71
|
# - :auth - a hash of authentication parameters for either basic or oauth
|
34
72
|
# - :timeout - timeout for the http request in seconds
|
73
|
+
# - :response_headers - a list of headers to return with the response
|
35
74
|
def request(method, string_url, options={})
|
36
75
|
params = stringify_params(options[:params])
|
37
76
|
if method == :get && params
|
@@ -73,8 +112,9 @@ module Grackle
|
|
73
112
|
redirect_limit = options[:redirect_limit] || DEFAULT_REDIRECT_LIMIT
|
74
113
|
if res.code.to_s =~ /^3\d\d$/ && redirect_limit > 0 && res['location']
|
75
114
|
execute_request(method,URI.parse(res['location']),options.merge(:redirect_limit=>redirect_limit-1))
|
76
|
-
else
|
77
|
-
|
115
|
+
else
|
116
|
+
headers = filter_headers(options[:response_headers],res)
|
117
|
+
Response.new(method,url.to_s,res.code.to_i,res.body,headers)
|
78
118
|
end
|
79
119
|
end
|
80
120
|
end
|
@@ -199,6 +239,14 @@ module Grackle
|
|
199
239
|
end
|
200
240
|
end
|
201
241
|
|
242
|
+
def filter_headers(headers, res)
|
243
|
+
filtered = Headers.new
|
244
|
+
headers.each do |h|
|
245
|
+
filtered.add(h, res[h])
|
246
|
+
end
|
247
|
+
filtered
|
248
|
+
end
|
249
|
+
|
202
250
|
def http_class
|
203
251
|
if proxy
|
204
252
|
if proxy.kind_of?(Proc)
|
@@ -245,4 +293,4 @@ EOS
|
|
245
293
|
req.request_body_permitted? || req.kind_of?(Net::HTTP::Delete)
|
246
294
|
end
|
247
295
|
end
|
248
|
-
end
|
296
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/test_helper'
|
2
2
|
|
3
|
-
class
|
3
|
+
class ClientTest < Test::Unit::TestCase
|
4
4
|
|
5
5
|
#Used for mocking HTTP requests
|
6
6
|
class Net::HTTP
|
@@ -197,7 +197,44 @@ class TestClient < Test::Unit::TestCase
|
|
197
197
|
assert_equal('TestAgent/1.0',Net::HTTP.request['User-Agent'],"Custom User-Agent header should have been set")
|
198
198
|
assert_equal('Header Value',Net::HTTP.request['X-Test-Header'],"Custom X-Test-Header header should have been set")
|
199
199
|
end
|
200
|
-
|
200
|
+
|
201
|
+
def test_default_response_headers
|
202
|
+
client = new_client(200, '[{"id":1,"text":"test 1"}]')
|
203
|
+
|
204
|
+
# Load up some other headers in the response
|
205
|
+
Grackle::Client::DEFAULT_RESPONSE_HEADERS.each_with_index do |header,i|
|
206
|
+
Net::HTTP.response[header] = "value#{i}"
|
207
|
+
end
|
208
|
+
|
209
|
+
client.statuses.public_timeline?
|
210
|
+
headers = client.response.headers
|
211
|
+
assert(!headers.nil?)
|
212
|
+
assert_equal(Grackle::Client::DEFAULT_RESPONSE_HEADERS.size, headers.size)
|
213
|
+
|
214
|
+
Grackle::Client::DEFAULT_RESPONSE_HEADERS.each_with_index do |h,i|
|
215
|
+
assert_equal("value#{i}",headers[h])
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_custom_response_headers
|
220
|
+
response_headers = ['X-Your-Face-Header']
|
221
|
+
client = new_client(200, '[{"id":1,"text":"test 1"}]', :response_headers=>response_headers)
|
222
|
+
|
223
|
+
# Load up some other headers in the response
|
224
|
+
Net::HTTP.response["X-Your-Face-Header"] = "asdf"
|
225
|
+
Net::HTTP.response["X-Something-Else"] = "foo"
|
226
|
+
|
227
|
+
assert_equal(response_headers,client.response_headers,"Response headers should override defaults")
|
228
|
+
|
229
|
+
client.statuses.public_timeline?
|
230
|
+
headers = client.response.headers
|
231
|
+
assert(!headers.nil?)
|
232
|
+
assert_equal(response_headers.size, headers.size)
|
233
|
+
|
234
|
+
assert_equal("asdf",headers["X-Your-Face-Header"])
|
235
|
+
assert(headers["X-Something-Else"].nil?)
|
236
|
+
end
|
237
|
+
|
201
238
|
def test_custom_handlers
|
202
239
|
client = new_client(200,'[{"id":1,"text":"test 1"}]',:handlers=>{:json=>TestHandler.new(42)})
|
203
240
|
value = client.statuses.public_timeline.json?
|
@@ -209,7 +246,7 @@ class TestClient < Test::Unit::TestCase
|
|
209
246
|
client.some.url.that.does.not.exist
|
210
247
|
assert_equal('/some/url/that/does/not/exist',client.send(:request).path,"An unexecuted path should be built up")
|
211
248
|
client.clear
|
212
|
-
assert_equal('',client.send(:request).path,"The path
|
249
|
+
assert_equal('',client.send(:request).path,"The path should be cleared")
|
213
250
|
end
|
214
251
|
|
215
252
|
def test_file_param_triggers_multipart_encoding
|
@@ -311,7 +348,22 @@ class TestClient < Test::Unit::TestCase
|
|
311
348
|
assert_equal(12345,client.transport.options[:params][:id], "Id should be treated as a parameter")
|
312
349
|
assert_equal("id=#{12345}",Net::HTTP.request.path.split(/\?/)[1],"id should be part of the query string")
|
313
350
|
end
|
314
|
-
|
351
|
+
|
352
|
+
def test_auto_append_format_is_honored
|
353
|
+
client = new_client(200,'{"id":12345,"screen_name":"test_user"}')
|
354
|
+
client.users.show.hayesdavis?
|
355
|
+
assert_equal('/1/users/show/hayesdavis.json',client.transport.url.path,"Format should be appended by default")
|
356
|
+
client.auto_append_format = false
|
357
|
+
client.users.show.hayesdavis?
|
358
|
+
assert_equal('/1/users/show/hayesdavis',client.transport.url.path,"Format should not be appended to the URI")
|
359
|
+
end
|
360
|
+
|
361
|
+
def test_auto_append_format_can_be_set_in_constructor
|
362
|
+
client = new_client(200,'{"id":12345,"screen_name":"test_user"}',:auto_append_format=>false)
|
363
|
+
client.users.show.hayesdavis?
|
364
|
+
assert_equal('/1/users/show/hayesdavis',client.transport.url.path,"Format should not be appended to the URI")
|
365
|
+
end
|
366
|
+
|
315
367
|
def test_default_api
|
316
368
|
client = Grackle::Client.new
|
317
369
|
assert_equal(:v1,client.api,":v1 should be default api")
|
@@ -351,9 +403,15 @@ class TestClient < Test::Unit::TestCase
|
|
351
403
|
assert_equal('http',client.transport.url.scheme,"Expected scheme to be http")
|
352
404
|
assert_equal('api.twitter.com',client.transport.url.host,"Expected request to be against twitter.com")
|
353
405
|
assert_equal('/1/statuses/update.json',client.transport.url.path)
|
354
|
-
|
406
|
+
|
407
|
+
if RUBY_VERSION >= "1.9.3"
|
408
|
+
# 1.9.3 encodes a space with a + instead of %20
|
409
|
+
assert_match(/status=test\+status/,Net::HTTP.request.body,"Parameters should be form encoded")
|
410
|
+
else
|
411
|
+
assert_match(/status=test%20status/,Net::HTTP.request.body,"Parameters should be form encoded")
|
412
|
+
end
|
355
413
|
assert_equal(12345,value.id)
|
356
414
|
yield(client) if block_given?
|
357
415
|
end
|
358
416
|
|
359
|
-
end
|
417
|
+
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grackle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Hayes Davis
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2012-06-10 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -60,36 +60,34 @@ dependencies:
|
|
60
60
|
version: "0"
|
61
61
|
type: :runtime
|
62
62
|
version_requirements: *id003
|
63
|
-
description: Grackle is a
|
64
|
-
email: hayes@
|
63
|
+
description: " Grackle is a library for the Twitter REST and Search API designed to not\n require a new release in the face Twitter API changes or errors.\n"
|
64
|
+
email: hayes@unionmetrics.com
|
65
65
|
executables: []
|
66
66
|
|
67
67
|
extensions: []
|
68
68
|
|
69
69
|
extra_rdoc_files:
|
70
70
|
- README.rdoc
|
71
|
-
files:
|
72
71
|
- CHANGELOG.rdoc
|
72
|
+
files:
|
73
73
|
- README.rdoc
|
74
|
-
-
|
75
|
-
- lib/grackle.rb
|
74
|
+
- CHANGELOG.rdoc
|
76
75
|
- lib/grackle/client.rb
|
77
76
|
- lib/grackle/handlers.rb
|
78
77
|
- lib/grackle/transport.rb
|
79
78
|
- lib/grackle/utils.rb
|
80
|
-
-
|
79
|
+
- lib/grackle/version.rb
|
80
|
+
- lib/grackle.rb
|
81
|
+
- test/client_test.rb
|
82
|
+
- test/handlers_test.rb
|
81
83
|
- test/test_helper.rb
|
82
|
-
- test/test_client.rb
|
83
|
-
- test/test_handlers.rb
|
84
84
|
has_rdoc: true
|
85
85
|
homepage: http://github.com/hayesdavis/grackle
|
86
86
|
licenses: []
|
87
87
|
|
88
88
|
post_install_message:
|
89
|
-
rdoc_options:
|
90
|
-
|
91
|
-
- --charset=UTF-8
|
92
|
-
- --main=README.rdoc
|
89
|
+
rdoc_options: []
|
90
|
+
|
93
91
|
require_paths:
|
94
92
|
- lib
|
95
93
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -112,10 +110,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
110
|
version: "0"
|
113
111
|
requirements: []
|
114
112
|
|
115
|
-
rubyforge_project:
|
113
|
+
rubyforge_project:
|
116
114
|
rubygems_version: 1.3.7
|
117
115
|
signing_key:
|
118
|
-
specification_version:
|
119
|
-
summary: Grackle is a library for the Twitter REST and Search API
|
116
|
+
specification_version: 3
|
117
|
+
summary: Grackle is a lightweight library for the Twitter REST and Search API.
|
120
118
|
test_files: []
|
121
119
|
|
data/grackle.gemspec
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
Gem::Specification.new do |s|
|
4
|
-
s.name = %q{grackle}
|
5
|
-
s.version = "0.1.10"
|
6
|
-
|
7
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
-
s.authors = ["Hayes Davis"]
|
9
|
-
s.date = %q{2010-6-13}
|
10
|
-
s.description = %q{Grackle is a lightweight library for the Twitter REST and Search API.}
|
11
|
-
s.email = %q{hayes@appozite.com}
|
12
|
-
s.files = ["CHANGELOG.rdoc", "README.rdoc", "grackle.gemspec", "lib/grackle.rb", "lib/grackle/client.rb", "lib/grackle/handlers.rb", "lib/grackle/transport.rb", "lib/grackle/utils.rb", "test/test_grackle.rb", "test/test_helper.rb", "test/test_client.rb", "test/test_handlers.rb"]
|
13
|
-
s.has_rdoc = true
|
14
|
-
s.homepage = %q{http://github.com/hayesdavis/grackle}
|
15
|
-
s.rdoc_options = ["--inline-source", "--charset=UTF-8","--main=README.rdoc"]
|
16
|
-
s.extra_rdoc_files = ['README.rdoc']
|
17
|
-
s.require_paths = ["lib"]
|
18
|
-
s.rubyforge_project = %q{grackle}
|
19
|
-
s.rubygems_version = %q{1.3.1}
|
20
|
-
s.summary = %q{Grackle is a library for the Twitter REST and Search API designed to not require a new release in the face Twitter API changes or errors. It supports both basic and OAuth authentication mechanisms.}
|
21
|
-
|
22
|
-
if s.respond_to? :specification_version then
|
23
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
-
s.specification_version = 2
|
25
|
-
|
26
|
-
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
27
|
-
s.add_runtime_dependency(%q<json>, [">= 0"])
|
28
|
-
s.add_dependency(%q<mime-types>, [">= 0"])
|
29
|
-
s.add_dependency(%q<oauth>, [">= 0"])
|
30
|
-
else
|
31
|
-
s.add_dependency(%q<json>, [">= 0"])
|
32
|
-
s.add_dependency(%q<mime-types>, [">= 0"])
|
33
|
-
s.add_dependency(%q<oauth>, [">= 0"])
|
34
|
-
end
|
35
|
-
else
|
36
|
-
s.add_dependency(%q<json>, [">= 0"])
|
37
|
-
s.add_dependency(%q<mime-types>, [">= 0"])
|
38
|
-
s.add_dependency(%q<oauth>, [">= 0"])
|
39
|
-
end
|
40
|
-
end
|
data/test/test_grackle.rb
DELETED