grackle 0.1.9 → 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +4 -0
- data/README.rdoc +8 -13
- data/grackle.gemspec +2 -2
- data/lib/grackle.rb +1 -1
- data/lib/grackle/client.rb +4 -5
- data/lib/grackle/transport.rb +9 -1
- data/test/test_client.rb +33 -15
- metadata +41 -17
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
== 0.1.10 (2010-6-13)
|
2
|
+
* Changed :v1 (api.twitter.com/1) to be the default API instead of REST. :rest is now deprecated
|
3
|
+
* 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").
|
4
|
+
|
1
5
|
== 0.1.9 (2010-2-28)
|
2
6
|
* Added support for a boolean option called auto_append_ids that controls whether parameters named "id" are automatically appended to the URL or used as request parameters. It's true by default so there's no change to existing behavior unless you explicitly set it to false.
|
3
7
|
* Updated the README with changes describing how to use custom handlers (thanks akahn!)
|
data/README.rdoc
CHANGED
@@ -102,27 +102,22 @@ parameter to your method chain called :__method (note the double underscores) to
|
|
102
102
|
client.direct_messages.destroy! :id=>1, :__method=>:delete #HTTP DELETE
|
103
103
|
|
104
104
|
===Toggling APIs
|
105
|
-
|
106
|
-
|
105
|
+
DEPRECATION NOTICE: The :rest API key (pointing to twitter.com) has been
|
106
|
+
deprecated in favor of the versioned API :v1 (pointing to api.twitter.com/1).
|
107
|
+
:v1 is now the default if you do not specify an API. Please do not use :rest
|
108
|
+
in your code.
|
109
|
+
|
110
|
+
By default, the Grackle::Client sends all requests to the versioned Twitter REST API. If you want to send requests to
|
111
|
+
the Twitter Search API, just set Grackle::Client.api to :search. To toggle back, set it to be :v1. All requests made
|
107
112
|
after setting this attribute will go to that API.
|
108
113
|
|
109
114
|
If you want to make a specific request to one API and not change the Client's overall api setting beyond that request, you can use the
|
110
115
|
bracket syntax like so:
|
111
116
|
client[:search].trends.daily? :exclude=>'hashtags'
|
112
|
-
client[:
|
117
|
+
client[:v1].users.show? :id=>'hayesdavis'
|
113
118
|
|
114
119
|
Search and REST requests are all built using the same method chaining and termination conventions.
|
115
120
|
|
116
|
-
Twitter is introducing API versioning. Grackle now supports the version 1 API using the :v1 API name. When using the :v1
|
117
|
-
API, resources that were previously separated between the search and REST APIs are available under one unified API. To
|
118
|
-
use the :v1 API, do the following:
|
119
|
-
client[:v1].search? :q=>'grackle'
|
120
|
-
client[:v1].users.show? :id=>'hayesdavis'
|
121
|
-
|
122
|
-
If you want to use the :v1 API for all requests, you may set Grackle::Client.api to :v1 or specify the :api option in the
|
123
|
-
Grackle::Client constructor like:
|
124
|
-
client = Grackle::Client.new(:api=>:v1)
|
125
|
-
|
126
121
|
===Parameter handling
|
127
122
|
- All parameters are URL encoded as necessary.
|
128
123
|
- If you use a File object as a parameter it will be POSTed to Twitter in a multipart request.
|
data/grackle.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{grackle}
|
5
|
-
s.version = "0.1.
|
5
|
+
s.version = "0.1.10"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Hayes Davis"]
|
9
|
-
s.date = %q{2010-
|
9
|
+
s.date = %q{2010-6-13}
|
10
10
|
s.description = %q{Grackle is a lightweight library for the Twitter REST and Search API.}
|
11
11
|
s.email = %q{hayes@appozite.com}
|
12
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"]
|
data/lib/grackle.rb
CHANGED
data/lib/grackle/client.rb
CHANGED
@@ -86,10 +86,9 @@ 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
|
-
:
|
90
|
-
:search=>'search.twitter.com',
|
91
|
-
:v1=>'api.twitter.com/1'
|
89
|
+
:search=>'search.twitter.com', :v1=>'api.twitter.com/1'
|
92
90
|
}
|
91
|
+
TWITTER_API_HOSTS[:rest] = TWITTER_API_HOSTS[:v1]
|
93
92
|
|
94
93
|
#Basic OAuth information needed to communicate with Twitter
|
95
94
|
TWITTER_OAUTH_SPEC = {
|
@@ -108,7 +107,7 @@ module Grackle
|
|
108
107
|
# - :default_format - Symbol of format to use when no format is specified in an API call (e.g. :json, :xml)
|
109
108
|
# - :headers - Hash of string keys and values for headers to pass in the HTTP request to twitter
|
110
109
|
# - :ssl - true or false to turn SSL on or off. Default is off (i.e. http://)
|
111
|
-
# - :api - one of :rest, :search or :v1. :
|
110
|
+
# - :api - one of :rest, :search or :v1. :v1 is the default and :rest is now deprecated
|
112
111
|
# - :auth - Hash of authentication type and credentials. Must have :type key with value one of :basic or :oauth
|
113
112
|
# - :type=>:basic - Include :username and :password keys
|
114
113
|
# - :type=>:oauth - Include :consumer_key, :consumer_secret, :token and :token_secret keys
|
@@ -119,7 +118,7 @@ module Grackle
|
|
119
118
|
self.default_format = options[:default_format] || :json
|
120
119
|
self.headers = {"User-Agent"=>"Grackle/#{Grackle::VERSION}"}.merge!(options[:headers]||{})
|
121
120
|
self.ssl = options[:ssl] == true
|
122
|
-
self.api = options[:api] || :
|
121
|
+
self.api = options[:api] || :v1
|
123
122
|
self.api_hosts = TWITTER_API_HOSTS.clone
|
124
123
|
self.timeout = options[:timeout] || 60
|
125
124
|
self.auto_append_ids = options[:auto_append_ids] == false ? false : true
|
data/lib/grackle/transport.rb
CHANGED
@@ -126,7 +126,7 @@ module Grackle
|
|
126
126
|
end
|
127
127
|
|
128
128
|
def add_form_data(req,params)
|
129
|
-
if
|
129
|
+
if request_body_permitted?(req) && params
|
130
130
|
req.set_form_data(params)
|
131
131
|
end
|
132
132
|
end
|
@@ -236,5 +236,13 @@ EOS
|
|
236
236
|
end
|
237
237
|
end
|
238
238
|
end
|
239
|
+
|
240
|
+
# Methods like Twitter's DELETE list membership expect that the user id
|
241
|
+
# will be form encoded like a POST request in the body. Net::HTTP seems
|
242
|
+
# to think that DELETEs can't have body parameters so we have to work
|
243
|
+
# around that.
|
244
|
+
def request_body_permitted?(req)
|
245
|
+
req.request_body_permitted? || req.kind_of?(Net::HTTP::Delete)
|
246
|
+
end
|
239
247
|
end
|
240
248
|
end
|
data/test/test_client.rb
CHANGED
@@ -118,8 +118,8 @@ class TestClient < Test::Unit::TestCase
|
|
118
118
|
assert_equal(:get,client.transport.method)
|
119
119
|
assert_equal('http',client.transport.url.scheme)
|
120
120
|
assert(!Net::HTTP.last_instance.use_ssl?,'Net::HTTP instance should not be set to use SSL')
|
121
|
-
assert_equal('twitter.com',client.transport.url.host)
|
122
|
-
assert_equal('/users/show.json',client.transport.url.path)
|
121
|
+
assert_equal('api.twitter.com',client.transport.url.host)
|
122
|
+
assert_equal('/1/users/show.json',client.transport.url.path)
|
123
123
|
assert_equal('test_user',client.transport.options[:params][:screen_name])
|
124
124
|
assert_equal('screen_name=test_user',Net::HTTP.request.path.split(/\?/)[1])
|
125
125
|
assert_equal(12345,value.id)
|
@@ -174,7 +174,7 @@ class TestClient < Test::Unit::TestCase
|
|
174
174
|
assert_equal('search.twitter.com',client.transport.url.host)
|
175
175
|
|
176
176
|
client[:rest].users.show.some_user?
|
177
|
-
assert_equal('twitter.com',client.transport.url.host)
|
177
|
+
assert_equal('api.twitter.com',client.transport.url.host)
|
178
178
|
|
179
179
|
client.api = :search
|
180
180
|
client.trends?
|
@@ -207,7 +207,7 @@ class TestClient < Test::Unit::TestCase
|
|
207
207
|
def test_clear
|
208
208
|
client = new_client(200,'[{"id":1,"text":"test 1"}]')
|
209
209
|
client.some.url.that.does.not.exist
|
210
|
-
assert_equal('/some/url/that/does/not/exist',client.send(:request).path,"An unexecuted path should be
|
210
|
+
assert_equal('/some/url/that/does/not/exist',client.send(:request).path,"An unexecuted path should be built up")
|
211
211
|
client.clear
|
212
212
|
assert_equal('',client.send(:request).path,"The path shoudl be cleared")
|
213
213
|
end
|
@@ -222,14 +222,14 @@ class TestClient < Test::Unit::TestCase
|
|
222
222
|
client = new_client(200,'[{"id":1,"text":"test 1"}]')
|
223
223
|
time = Time.now-60*60
|
224
224
|
client.statuses.public_timeline? :since=>time
|
225
|
-
assert_equal("/statuses/public_timeline.json?since=#{CGI::escape(time.httpdate)}",Net::HTTP.request.path)
|
225
|
+
assert_equal("/1/statuses/public_timeline.json?since=#{CGI::escape(time.httpdate)}",Net::HTTP.request.path)
|
226
226
|
end
|
227
227
|
|
228
228
|
def test_simple_http_method_block
|
229
229
|
client = new_client(200,'[{"id":1,"text":"test 1"}]')
|
230
230
|
client.delete { direct_messages.destroy :id=>1, :other=>'value' }
|
231
231
|
assert_equal(:delete,client.transport.method, "delete block should use delete method")
|
232
|
-
assert_equal("/direct_messages/destroy/1.json",Net::HTTP.request.path)
|
232
|
+
assert_equal("/1/direct_messages/destroy/1.json",Net::HTTP.request.path)
|
233
233
|
assert_equal('value',client.transport.options[:params][:other])
|
234
234
|
|
235
235
|
client = new_client(200,'{"id":54321,"screen_name":"test_user"}')
|
@@ -237,8 +237,8 @@ class TestClient < Test::Unit::TestCase
|
|
237
237
|
assert_equal(:get,client.transport.method)
|
238
238
|
assert_equal('http',client.transport.url.scheme)
|
239
239
|
assert(!Net::HTTP.last_instance.use_ssl?,'Net::HTTP instance should not be set to use SSL')
|
240
|
-
assert_equal('twitter.com',client.transport.url.host)
|
241
|
-
assert_equal('/users/show.json',client.transport.url.path)
|
240
|
+
assert_equal('api.twitter.com',client.transport.url.host)
|
241
|
+
assert_equal('/1/users/show.json',client.transport.url.path)
|
242
242
|
assert_equal('test_user',client.transport.options[:params][:screen_name])
|
243
243
|
assert_equal('screen_name=test_user',Net::HTTP.request.path.split(/\?/)[1])
|
244
244
|
assert_equal(54321,value.id)
|
@@ -270,8 +270,8 @@ class TestClient < Test::Unit::TestCase
|
|
270
270
|
assert_equal(:get,client.transport.method)
|
271
271
|
assert_equal('http',client.transport.url.scheme)
|
272
272
|
assert(!Net::HTTP.last_instance.use_ssl?,'Net::HTTP instance should not be set to use SSL')
|
273
|
-
assert_equal('twitter.com',client.transport.url.host)
|
274
|
-
assert_equal('/users/show/12345.json',client.transport.url.path)
|
273
|
+
assert_equal('api.twitter.com',client.transport.url.host)
|
274
|
+
assert_equal('/1/users/show/12345.json',client.transport.url.path)
|
275
275
|
assert_equal(12345,value.id)
|
276
276
|
end
|
277
277
|
|
@@ -296,10 +296,10 @@ class TestClient < Test::Unit::TestCase
|
|
296
296
|
def test_auto_append_ids_is_honored
|
297
297
|
client = new_client(200,'{"id":12345,"screen_name":"test_user"}')
|
298
298
|
client.users.show.json? :id=>12345
|
299
|
-
assert_equal('/users/show/12345.json',client.transport.url.path,"Id should be appended by default")
|
299
|
+
assert_equal('/1/users/show/12345.json',client.transport.url.path,"Id should be appended by default")
|
300
300
|
client.auto_append_ids = false
|
301
301
|
client.users.show.json? :id=>12345
|
302
|
-
assert_equal('/users/show.json',client.transport.url.path,"Id should not be appended")
|
302
|
+
assert_equal('/1/users/show.json',client.transport.url.path,"Id should not be appended")
|
303
303
|
assert_equal(12345,client.transport.options[:params][:id], "Id should be treated as a parameter")
|
304
304
|
assert_equal("id=#{12345}",Net::HTTP.request.path.split(/\?/)[1],"id should be part of the query string")
|
305
305
|
end
|
@@ -307,11 +307,29 @@ class TestClient < Test::Unit::TestCase
|
|
307
307
|
def test_auto_append_ids_can_be_set_in_constructor
|
308
308
|
client = new_client(200,'{"id":12345,"screen_name":"test_user"}',:auto_append_ids=>false)
|
309
309
|
client.users.show.json? :id=>12345
|
310
|
-
assert_equal('/users/show.json',client.transport.url.path,"Id should not be appended")
|
310
|
+
assert_equal('/1/users/show.json',client.transport.url.path,"Id should not be appended")
|
311
311
|
assert_equal(12345,client.transport.options[:params][:id], "Id should be treated as a parameter")
|
312
312
|
assert_equal("id=#{12345}",Net::HTTP.request.path.split(/\?/)[1],"id should be part of the query string")
|
313
313
|
end
|
314
314
|
|
315
|
+
def test_default_api
|
316
|
+
client = Grackle::Client.new
|
317
|
+
assert_equal(:v1,client.api,":v1 should be default api")
|
318
|
+
end
|
319
|
+
|
320
|
+
# Methods like Twitter's DELETE list membership expect that the user id will
|
321
|
+
# be form encoded like a POST request in the body. Net::HTTP seems to think
|
322
|
+
# that DELETEs can't have body parameters so we have to work around that.
|
323
|
+
def test_delete_can_send_body_parameters
|
324
|
+
client = new_client(200,'{"id":12345,"name":"Test List","members":0}')
|
325
|
+
client.delete { some_user.some_list.members? :user_id=>12345 }
|
326
|
+
assert_equal(:delete,client.transport.method,"Expected delete request")
|
327
|
+
assert_equal('http',client.transport.url.scheme,"Expected scheme to be http")
|
328
|
+
assert_equal('api.twitter.com',client.transport.url.host,"Expected request to be against twitter.com")
|
329
|
+
assert_equal('/1/some_user/some_list/members.json',client.transport.url.path)
|
330
|
+
assert_match(/user_id=12345/,Net::HTTP.request.body,"Parameters should be form encoded")
|
331
|
+
end
|
332
|
+
|
315
333
|
private
|
316
334
|
def with_http_responder(responder)
|
317
335
|
Net::HTTP.responder = responder
|
@@ -331,8 +349,8 @@ class TestClient < Test::Unit::TestCase
|
|
331
349
|
value = client.statuses.update! :status=>'test status'
|
332
350
|
assert_equal(:post,client.transport.method,"Expected post request")
|
333
351
|
assert_equal('http',client.transport.url.scheme,"Expected scheme to be http")
|
334
|
-
assert_equal('twitter.com',client.transport.url.host,"Expected request to be against twitter.com")
|
335
|
-
assert_equal('/statuses/update.json',client.transport.url.path)
|
352
|
+
assert_equal('api.twitter.com',client.transport.url.host,"Expected request to be against twitter.com")
|
353
|
+
assert_equal('/1/statuses/update.json',client.transport.url.path)
|
336
354
|
assert_match(/status=test%20status/,Net::HTTP.request.body,"Parameters should be form encoded")
|
337
355
|
assert_equal(12345,value.id)
|
338
356
|
yield(client) if block_given?
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grackle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 15
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 10
|
10
|
+
version: 0.1.10
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Hayes Davis
|
@@ -9,39 +15,51 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date: 2010-
|
18
|
+
date: 2010-06-13 00:00:00 -05:00
|
13
19
|
default_executable:
|
14
20
|
dependencies:
|
15
21
|
- !ruby/object:Gem::Dependency
|
16
22
|
name: json
|
17
|
-
|
18
|
-
|
19
|
-
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
20
26
|
requirements:
|
21
27
|
- - ">="
|
22
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
23
32
|
version: "0"
|
24
|
-
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
25
35
|
- !ruby/object:Gem::Dependency
|
26
36
|
name: mime-types
|
27
|
-
|
28
|
-
|
29
|
-
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
30
40
|
requirements:
|
31
41
|
- - ">="
|
32
42
|
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
33
46
|
version: "0"
|
34
|
-
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
35
49
|
- !ruby/object:Gem::Dependency
|
36
50
|
name: oauth
|
37
|
-
|
38
|
-
|
39
|
-
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
40
54
|
requirements:
|
41
55
|
- - ">="
|
42
56
|
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
43
60
|
version: "0"
|
44
|
-
|
61
|
+
type: :runtime
|
62
|
+
version_requirements: *id003
|
45
63
|
description: Grackle is a lightweight library for the Twitter REST and Search API.
|
46
64
|
email: hayes@appozite.com
|
47
65
|
executables: []
|
@@ -75,21 +93,27 @@ rdoc_options:
|
|
75
93
|
require_paths:
|
76
94
|
- lib
|
77
95
|
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
78
97
|
requirements:
|
79
98
|
- - ">="
|
80
99
|
- !ruby/object:Gem::Version
|
100
|
+
hash: 3
|
101
|
+
segments:
|
102
|
+
- 0
|
81
103
|
version: "0"
|
82
|
-
version:
|
83
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
84
106
|
requirements:
|
85
107
|
- - ">="
|
86
108
|
- !ruby/object:Gem::Version
|
109
|
+
hash: 3
|
110
|
+
segments:
|
111
|
+
- 0
|
87
112
|
version: "0"
|
88
|
-
version:
|
89
113
|
requirements: []
|
90
114
|
|
91
115
|
rubyforge_project: grackle
|
92
|
-
rubygems_version: 1.3.
|
116
|
+
rubygems_version: 1.3.7
|
93
117
|
signing_key:
|
94
118
|
specification_version: 2
|
95
119
|
summary: 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.
|