grackle 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,9 @@
1
+ == 0.3.0 (2013-03-31)
2
+ * Make Twitter API 1.1 endpoint the default. This will be a breaking change if you expect 1.0 out of the box
3
+
4
+ == 0.2.2 (2013-01-24, Unreleased)
5
+ * Add :v1_1 api endpoint to client mapping to api.twitter.com/1.1; the default is still :v1. (Thanks @jcsalterego)
6
+
1
7
  == 0.2.1 (2012-08-14)
2
8
  * Add :valid_http_codes option that tells grackle not to raise an error when encountering those statuses.
3
9
 
@@ -3,22 +3,22 @@ by Hayes Davis
3
3
  - http://twitter.com/hayesdavis
4
4
  - hayes [at] unionmetrics [dot] com
5
5
  - http://unionmetrics.com
6
- - http://hayesdavis.net
6
+ - http://hayesdavis.tumblr.com
7
7
 
8
8
  == DESCRIPTION
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.
9
+ Grackle is a lightweight Ruby wrapper around the Twitter REST API. It's based on
10
+ my experience using the Twitter API to build http://tweetreach.com. The main
11
+ goal of Grackle is to never require a release when the Twitter API changes
12
+ (which it often does) or in the face of a particular Twitter API bug. As such
13
+ it's somewhat different from other Twitter API libraries. It doesn't try to hide
14
+ the Twitter "methods" under an access layer nor does it introduce concrete
15
+ classes for the various objects returned by Twitter. Instead, calls to the
16
+ Grackle client map directly to Twitter API URLs. The objects returned by API
17
+ calls are generated as OpenStructs on the fly and make no assumptions about the
18
+ presence or absence of any particular attributes. Taking this approach means
19
+ that changes to URLs used by Twitter, parameters required by those URLs or
20
+ return values will not require a new release. It will potentially require,
21
+ however, some modifications to your code that uses Grackle.
22
22
 
23
23
  === Support and Announcements
24
24
  The preferred forum for questions and discussions is the Google group at
@@ -26,7 +26,14 @@ http://groups.google.com/group/gracklerb. You can email me directly or @reply me
26
26
  on Twitter, but the group is better since the questions and responses will be
27
27
  available to everyone. I'll also make announcements there. There are some
28
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].
29
+ your information in 140 characters, follow
30
+ @gracklerb[http://twitter.com/gracklerb].
31
+
32
+ === Twitter API 1.1 and Grackle 0.3.0
33
+ Grackle 0.3.0 defaults to Twitter API 1.1 out of the box. If you have code that
34
+ still relies on API 1.0, you can upgrade Grackle and still use API 1.0 by
35
+ specifying that the client use the :v1 API:
36
+ client = Grackle::Client.new(:api=>:v1)
30
37
 
31
38
  ==USING GRACKLE
32
39
 
@@ -40,12 +47,15 @@ Before you do anything else, you'll need to
40
47
  :consumer_key=>'SOMECONSUMERKEYFROMTWITTER', :consumer_secret=>'SOMECONSUMERTOKENFROMTWITTER',
41
48
  :token=>'ACCESSTOKENACQUIREDONUSERSBEHALF', :token_secret=>'SUPERSECRETACCESSTOKENSECRET'
42
49
  })
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
50
+
51
+ OAuth can be a bit complicated. See the wiki[http://wiki.github.com/hayesdavis/grackle/grackle-and-oauth]
52
+ for more information on acquiring the keys, tokens and secrets needed to
46
53
  successfully authenticate with OAuth.
47
54
 
48
- ====Using No Auth
55
+ ====Using No Auth (DEPRECATED)
56
+ As of May 7th, 2013, Twitter will be shutting down all API 1 endpoints and
57
+ requiring all clients to use API 1.1 which requires OAuth authentication for all
58
+ API calls.
49
59
  client = Grackle::Client.new
50
60
 
51
61
  ====Using Basic Auth (DEPRECATED)
@@ -55,23 +65,24 @@ As of August 31st, 2010, Twitter has deprecated basic authentication in favor of
55
65
  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.
56
66
 
57
67
  ===Grackle Method Syntax
58
- Grackle uses a method syntax that corresponds to the Twitter API URLs with a few twists. Where you would have a slash in
59
- a Twitter URL, that becomes a "." in a chained set of Grackle method calls. Each call in the method chain is used to build
60
- Twitter URL path until a particular call is encountered which causes the request to be sent. Methods which will cause a
61
- request to be execute include:
68
+ Grackle uses a method syntax that corresponds to the Twitter API URLs with a few
69
+ twists. Where you would have a slash in a Twitter URL, that becomes a "." in a
70
+ chained set of Grackle method calls. Each call in the method chain is used to
71
+ build Twitter URL path until a particular call is encountered which causes the
72
+ request to be sent. Methods which will cause a request to be execute include:
62
73
  - A method call ending in "?" will cause an HTTP GET to be executed
63
74
  - A method call ending in "!" will cause an HTTP POST to be executed
64
75
  - If a valid format such as .json, .xml, .rss or .atom is encounted, a get will be executed with that format
65
76
  - A format method can also include a ? or ! to determine GET or POST in that format respectively
66
77
 
67
78
  ===GETting Data
68
- The preferred and simplest way of executing a GET is to use the "?" method notation. This will use the default client
79
+ The preferred and simplest way of executing a GET is to use the "?" method notation. This will use the default client
69
80
  format (usually JSON, but see Formats section below):
70
81
  client.users.show? :screen_name=>'some_user' #http://twitter.com/users/show.json?screen_name=some_user
71
82
 
72
83
  You can force XML format by doing:
73
84
  client.users.show.xml? :screen_name=>'some_user' #http://twitter.com/users/show.xml?screen_name=some_user
74
-
85
+
75
86
  You can force JSON:
76
87
  client.users.show.json? :screen_name=>'some_user' #http://twitter.com/users/show.json?screen_name=some_user
77
88
 
@@ -92,37 +103,42 @@ You can force a format. To update the authenticated user's status using the XML
92
103
 
93
104
  Or, with JSON
94
105
  client.statuses.update.json! :status=>'this status is from grackle' #POST to http://twitter.com/statuses/update.json
95
-
106
+
96
107
  ===Using Other HTTP Verbs
97
108
  To use HTTP verbs like DELETE or PUT, Grackle provides a slightly different syntax:
98
109
  client.put{ hayesdavis.lists.my_list :name=>'New Name' } #HTTP PUT
99
110
  client.delete{ direct_messages.destroy :id=>1 } #HTTP DELETE
100
-
101
- You may specify any method chain you wish in the block. Note that if your method chain inside the block
111
+
112
+ You may specify any method chain you wish in the block. Note that if your method chain inside the block
102
113
  ends in a ! or ?, that the HTTP verb for the block will still be used. This means that
103
114
  client.delete{ direct_messages.destroy! :id=>1 } #Uses HTTP DELETE, not POST
104
115
  client.direct_messages.destroy! :id=>1 #Uses HTTP POST
105
116
 
106
- If for some reason you don't like the preferred block syntax above, you may specify a
117
+ If for some reason you don't like the preferred block syntax above, you may specify a
107
118
  parameter to your method chain called :__method (note the double underscores) to specify the HTTP verb:
108
119
  client.direct_messages.destroy! :id=>1, :__method=>:delete #HTTP DELETE
109
120
 
110
121
  ===Toggling APIs
111
- DEPRECATION NOTICE: The :rest API key (pointing to twitter.com) has been
112
- deprecated in favor of the versioned API :v1 (pointing to api.twitter.com/1).
113
- :v1 is now the default if you do not specify an API. Please do not use :rest
114
- in your code.
122
+ As of Grackle 0.3.0, the Grackle::Client sends all requests to the 1.1 Twitter
123
+ API by default. If you want to send requests to the Twitter 1.0 API (which has
124
+ been deprecated by Twitter and will be unavailable after May 7th, 2013), just
125
+ use the Grackle::Client#api= method and set it to :v1. To toggle back, set it
126
+ to :v1_1. All requests made after setting this attribute will go to that API.
115
127
 
116
- By default, the Grackle::Client sends all requests to the versioned Twitter REST API. If you want to send requests to
117
- the Twitter Search API, just set Grackle::Client.api to :search. To toggle back, set it to be :v1. All requests made
118
- after setting this attribute will go to that API.
128
+ For convenience, you can also set the desired API in the Client constructor:
129
+ client = Grackle::Client.new(:api=>:v1)
119
130
 
120
- 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
121
- bracket syntax like so:
122
- client[:search].trends.daily? :exclude=>'hashtags'
123
- client[:v1].users.show? :id=>'hayesdavis'
124
-
125
- Search and REST requests are all built using the same method chaining and termination conventions.
131
+ If you want to make a specific request to one API and not change the Client's
132
+ overall api setting beyond that request, you can use the bracket syntax like so:
133
+ client[:v1].users.show? :screen_name=>'hayesdavis'
134
+ client[:v1_1].users.show? :screen_name=>'hayesdavis'
135
+
136
+ All APIs use the same method chaining and termination conventions.
137
+
138
+ DEPRECATION NOTICE: The :rest API key (pointing to twitter.com), the :search API
139
+ key (pointing to search.twitter.com) and the :v1 API key
140
+ (pointing to api.twitter.com/1) have all been deprecated in favor of the
141
+ the :v1_1 API (pointing to api.twitter.com/1.1).
126
142
 
127
143
  ===Parameter handling
128
144
  - All parameters are URL encoded as necessary.
@@ -130,8 +146,9 @@ Search and REST requests are all built using the same method chaining and termin
130
146
  - If you use a Time object as a parameter, .httpdate will be called on it and that value will be used
131
147
 
132
148
  ===Return Values
133
- Regardless of the format used, Grackle returns an OpenStruct (actually a Grackle::TwitterStruct) of data. The attributes
134
- available on these structs correspond to the data returned by Twitter.
149
+ Regardless of the format used, Grackle returns an OpenStruct (actually a
150
+ Grackle::TwitterStruct) of data. The attributes available on these structs
151
+ correspond to the data returned by Twitter.
135
152
 
136
153
  ===Rate Limits and the Response
137
154
  The Grackle client has a response method which is populated with information
@@ -142,7 +159,13 @@ because they can be used to retrieve the rate limit information that Twitter
142
159
  includes in a response.
143
160
 
144
161
  user = client.users.show.hayesdavis?
145
- client.response.headers["X-Ratelimit-Remaining"]
162
+ client.response.headers["X-Rate-Limit-Remaining"] # 1.1 API
163
+
164
+ user = client[:v1].users.show.hayesdavis?
165
+ client.response.headers["X-Ratelimit-Remaining"] # 1.0 API
166
+
167
+ Note that Twitter has renamed the rate limit headers in API 1.1 to use
168
+ "rate-limit" instead of API 1.0's "ratelimit".
146
169
 
147
170
  Not all headers returned by Twitter are included by default. You can control
148
171
  which headers are accessible with the response_headers attribute on the Client.
@@ -151,28 +174,33 @@ header values will be Strings so you'll need to convert rate limits, etc to ints
151
174
  in your code.
152
175
 
153
176
  ===Dealing with Errors
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,
155
- the full request URI, the response status, the response body in text and a response object build by parsing the formatted error
156
- returned by Twitter. It's a good idea to wrap your API calls with rescue clauses for Grackle::TwitterError.
177
+ If the request to Twitter does not return a status code of 200, then a
178
+ TwitterError is thrown. This contains the HTTP method used, the full request
179
+ URI, the response status, the response body in text and a response object build
180
+ by parsing the formatted error returned by Twitter. It's a good idea to wrap
181
+ your API calls with rescue clauses for Grackle::TwitterError.
157
182
 
158
- If there is an unexpected connection error or Twitter returns data in the wrong format (which it can do), you'll still get a TwitterError.
183
+ If there is an unexpected connection error or Twitter returns data in the wrong
184
+ format (which it can do), you'll still get a TwitterError.
159
185
 
160
186
  ===Formats
161
- Twitter allows you to request data in particular formats. Grackle automatically
162
- parses JSON and XML formatted responses and returns an OpenStruct. The
163
- Grackle::Client has a default_format you can specify. By default, the
164
- default_format is :json. If you don't include a named format in your method
165
- chain as described above, but use a "?" or "!" then the
187
+ Twitter allows you to request data in particular formats. Grackle automatically
188
+ parses JSON and XML formatted responses and returns an OpenStruct. The
189
+ Grackle::Client has a default_format you can specify. By default, the
190
+ default_format is :json. If you don't include a named format in your method
191
+ chain as described above, but use a "?" or "!" then the
166
192
  Grackle::Client.default_format is used.
167
193
 
168
- If you specify a format that Grackle doesn't parse for you, you'll receive a
169
- string containing the raw response body. If you want to receive the raw
170
- response body even for XML or JSON formatted responses, tell the Grackle client
171
- to use the +StringHandler+ handler. For example, the following code sets the
194
+ If you specify a format that Grackle doesn't parse for you, you'll receive a
195
+ string containing the raw response body. If you want to receive the raw
196
+ response body even for XML or JSON formatted responses, tell the Grackle client
197
+ to use the +StringHandler+ handler. For example, the following code sets the
172
198
  Grackle client to return JSON instead of an OpenStruct:
173
199
 
174
200
  client = Grackle::Client.new(:handlers=>{:json=>Grackle::Handlers::StringHandler.new })
175
201
 
202
+ DEPRECATION NOTICE: As to Twitter API 1.1, XML is no longer an accepted format.
203
+
176
204
  ===Odds and Ends
177
205
  If you need to append something to the request path that isn't a valid ruby method, e.g.
178
206
  /1user/lists.json #1user isn't a valid Ruby method
@@ -183,7 +211,7 @@ you can use the Grackle::Client#_ method like so:
183
211
 
184
212
  You'll need the following gems to use all features of Grackle:
185
213
  - json
186
- - oauth
214
+ - oauth
187
215
  - mime-types
188
216
 
189
217
  === Ruby Version Support
@@ -87,16 +87,23 @@ module Grackle
87
87
  # refer to it wherever Grackle::Client uses an API symbol. You may wish
88
88
  # to do this when Twitter introduces API versions greater than 1.
89
89
  TWITTER_API_HOSTS = {
90
- :search=>'search.twitter.com', :v1=>'api.twitter.com/1',
90
+ :v1=>'api.twitter.com/1', :v1_1=>'api.twitter.com/1.1',
91
+ :search=>'search.twitter.com',
91
92
  :upload=>'upload.twitter.com/1'
92
93
  }
93
94
  TWITTER_API_HOSTS[:rest] = TWITTER_API_HOSTS[:v1]
95
+ DEFAULT_API_HOST = :v1_1
94
96
 
95
97
  # Contains the response headers from twitter
96
- DEFAULT_RESPONSE_HEADERS =[
98
+ DEFAULT_RESPONSE_HEADERS = [
99
+ # These are API 1 rate limit header names
97
100
  'x-ratelimit-limit',
98
101
  'x-ratelimit-remaining',
99
- 'x-ratelimit-reset'
102
+ 'x-ratelimit-reset',
103
+ # These are API 1.1 rate limit header names
104
+ 'x-rate-limit-limit',
105
+ 'x-rate-limit-remaining',
106
+ 'x-rate-limit-reset'
100
107
  ]
101
108
 
102
109
  #Basic OAuth information needed to communicate with Twitter
@@ -117,10 +124,10 @@ module Grackle
117
124
  # - :default_format - Symbol of format to use when no format is specified in an API call (e.g. :json, :xml)
118
125
  # - :headers - Hash of string keys and values for headers to pass in the HTTP request to twitter
119
126
  # - :ssl - true or false to turn SSL on or off. Default is off (i.e. http://)
120
- # - :api - one of :rest, :search or :v1. :v1 is the default and :rest is now deprecated
127
+ # - :api - one of :rest, :search, :v1 or :v1_1. :v1_1 is the default. :rest and :search are now deprecated
121
128
  # - :auth - Hash of authentication type and credentials. Must have :type key with value one of :basic or :oauth
122
- # - :type=>:basic - Include :username and :password keys
123
129
  # - :type=>:oauth - Include :consumer_key, :consumer_secret, :token and :token_secret keys
130
+ # - :type=>:basic - DEPRECATED. Include :username and :password keys
124
131
  # - :auto_append_format - true or false to include format in URI (e.g. /test.json). Default is true
125
132
  # - :response_headers - array of headers to return from the response
126
133
  # - :valid_http_codes - array of HTTP codes to consider valid (non-error)
@@ -128,11 +135,11 @@ module Grackle
128
135
  self.transport = Transport.new
129
136
  self.handlers = {:json=>Handlers::JSONHandler.new,:xml=>Handlers::XMLHandler.new,:unknown=>Handlers::StringHandler.new}
130
137
  self.handlers.merge!(options[:handlers]||{})
131
- self.default_format = options[:default_format] || :json
138
+ self.default_format = options[:default_format] || :json
132
139
  self.auto_append_format = options[:auto_append_format] == false ? false : true
133
140
  self.headers = {"User-Agent"=>"Grackle/#{Grackle::VERSION}"}.merge!(options[:headers]||{})
134
141
  self.ssl = options[:ssl] == true
135
- self.api = options[:api] || :v1
142
+ self.api = options[:api] || DEFAULT_API_HOST
136
143
  self.api_hosts = TWITTER_API_HOSTS.clone
137
144
  self.timeout = options[:timeout] || 60
138
145
  self.auto_append_ids = options[:auto_append_ids] == false ? false : true
@@ -140,7 +147,7 @@ module Grackle
140
147
  self.response_headers = options[:response_headers] || DEFAULT_RESPONSE_HEADERS.clone
141
148
  self.valid_http_codes = options[:valid_http_codes] || VALID_HTTP_CODES.clone
142
149
  if options.has_key?(:username) || options.has_key?(:password)
143
- #Use basic auth if :username and :password args are passed in
150
+ # DEPRECATED: Use basic auth if :username and :password args are passed in
144
151
  self.auth.merge!({:type=>:basic,:username=>options[:username],:password=>options[:password]})
145
152
  end
146
153
  #Handle auth mechanism that permits basic or oauth
@@ -151,7 +158,7 @@ module Grackle
151
158
  end
152
159
  end
153
160
  end
154
-
161
+
155
162
  def method_missing(name,*args,&block)
156
163
  if block_given?
157
164
  return request_with_http_method_block(name,&block)
@@ -1,9 +1,9 @@
1
1
  module Grackle
2
2
 
3
- VERSION = "0.2.1"
3
+ VERSION = "0.3.0"
4
4
 
5
5
  def self.version
6
6
  VERSION
7
7
  end
8
8
 
9
- end
9
+ end
@@ -119,7 +119,7 @@ class ClientTest < Test::Unit::TestCase
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
121
  assert_equal('api.twitter.com',client.transport.url.host)
122
- assert_equal('/1/users/show.json',client.transport.url.path)
122
+ assert_equal('/1.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)
@@ -167,30 +167,47 @@ class ClientTest < Test::Unit::TestCase
167
167
  client.statuses.public_timeline?
168
168
  assert_match(/\.xml$/,client.transport.url.path)
169
169
  end
170
-
171
- def test_api
172
- client = new_client(200,'[{"id":1,"text":"test 1"}]',:api=>:search)
173
- client.search? :q=>'test'
174
- assert_equal('search.twitter.com',client.transport.url.host)
175
170
 
176
- client[:rest].users.show.some_user?
177
- assert_equal('api.twitter.com',client.transport.url.host)
171
+ def test_api_selection_with_api_accessor_changes_api_for_subsequent_requests
172
+ client = new_client(200,'[{"id":1,"text":"test 1"}]')
173
+
174
+ # :rest and :v1 are DEPRECATED
175
+ {:rest=>"1", :v1=>"1",:v1_1=>"1.1"}.each do |api_key,version|
176
+ client.api = api_key
177
+ client.users.show.some_user?
178
+ assert_equal('api.twitter.com',client.transport.url.host)
179
+ assert_equal("/#{version}/users/show/some_user.json",client.transport.url.path)
180
+ assert_equal(api_key,client.api,"API changed for all requests")
181
+ end
178
182
 
183
+ # :search is DEPRECATED
179
184
  client.api = :search
180
185
  client.trends?
181
186
  assert_equal('search.twitter.com',client.transport.url.host)
182
-
183
- client.api = :v1
184
- client.search? :q=>'test'
185
- assert_equal('api.twitter.com',client.transport.url.host)
186
- assert_match(%r{^/1/search},client.transport.url.path)
187
+ assert_equal("/trends.json",client.transport.url.path)
188
+ assert_equal(:search,client.api,"API changed to search for all requests")
189
+ end
187
190
 
188
- client.api = :rest
189
- client[:v1].users.show.some_user?
190
- assert_equal('api.twitter.com',client.transport.url.host)
191
- assert_match(%r{^/1/users/show/some_user},client.transport.url.path)
191
+ def test_api_selection_with_api_override_changes_api_for_specific_request
192
+ client = new_client(200,'[{"id":1,"text":"test 1"}]')
193
+
194
+ original_api = client.api
195
+
196
+ # :rest and :v1 are DEPRECATED
197
+ {:rest=>"1", :v1=>"1",:v1_1=>"1.1"}.each do |api_key,version|
198
+ client[api_key].users.show.some_user?
199
+ assert_equal('api.twitter.com',client.transport.url.host)
200
+ assert_equal("/#{version}/users/show/some_user.json",client.transport.url.path)
201
+ assert_equal(original_api,client.api,"API should not change")
202
+ end
203
+
204
+ # :search is DEPRECATED
205
+ client[:search].trends?
206
+ assert_equal('search.twitter.com',client.transport.url.host)
207
+ assert_equal("/trends.json",client.transport.url.path)
208
+ assert_equal(original_api,client.api,"API should not change")
192
209
  end
193
-
210
+
194
211
  def test_headers
195
212
  client = new_client(200,'[{"id":1,"text":"test 1"}]',:headers=>{'User-Agent'=>'TestAgent/1.0','X-Test-Header'=>'Header Value'})
196
213
  client.statuses.public_timeline?
@@ -259,14 +276,14 @@ class ClientTest < Test::Unit::TestCase
259
276
  client = new_client(200,'[{"id":1,"text":"test 1"}]')
260
277
  time = Time.now-60*60
261
278
  client.statuses.public_timeline? :since=>time
262
- assert_equal("/1/statuses/public_timeline.json?since=#{CGI::escape(time.httpdate)}",Net::HTTP.request.path)
279
+ assert_equal("/1.1/statuses/public_timeline.json?since=#{CGI::escape(time.httpdate)}",Net::HTTP.request.path)
263
280
  end
264
281
 
265
282
  def test_simple_http_method_block
266
283
  client = new_client(200,'[{"id":1,"text":"test 1"}]')
267
284
  client.delete { direct_messages.destroy :id=>1, :other=>'value' }
268
285
  assert_equal(:delete,client.transport.method, "delete block should use delete method")
269
- assert_equal("/1/direct_messages/destroy/1.json",Net::HTTP.request.path)
286
+ assert_equal("/1.1/direct_messages/destroy/1.json",Net::HTTP.request.path)
270
287
  assert_equal('value',client.transport.options[:params][:other])
271
288
 
272
289
  client = new_client(200,'{"id":54321,"screen_name":"test_user"}')
@@ -275,7 +292,7 @@ class ClientTest < Test::Unit::TestCase
275
292
  assert_equal('http',client.transport.url.scheme)
276
293
  assert(!Net::HTTP.last_instance.use_ssl?,'Net::HTTP instance should not be set to use SSL')
277
294
  assert_equal('api.twitter.com',client.transport.url.host)
278
- assert_equal('/1/users/show.json',client.transport.url.path)
295
+ assert_equal('/1.1/users/show.json',client.transport.url.path)
279
296
  assert_equal('test_user',client.transport.options[:params][:screen_name])
280
297
  assert_equal('screen_name=test_user',Net::HTTP.request.path.split(/\?/)[1])
281
298
  assert_equal(54321,value.id)
@@ -308,7 +325,7 @@ class ClientTest < Test::Unit::TestCase
308
325
  assert_equal('http',client.transport.url.scheme)
309
326
  assert(!Net::HTTP.last_instance.use_ssl?,'Net::HTTP instance should not be set to use SSL')
310
327
  assert_equal('api.twitter.com',client.transport.url.host)
311
- assert_equal('/1/users/show/12345.json',client.transport.url.path)
328
+ assert_equal('/1.1/users/show/12345.json',client.transport.url.path)
312
329
  assert_equal(12345,value.id)
313
330
  end
314
331
 
@@ -333,10 +350,10 @@ class ClientTest < Test::Unit::TestCase
333
350
  def test_auto_append_ids_is_honored
334
351
  client = new_client(200,'{"id":12345,"screen_name":"test_user"}')
335
352
  client.users.show.json? :id=>12345
336
- assert_equal('/1/users/show/12345.json',client.transport.url.path,"Id should be appended by default")
353
+ assert_equal('/1.1/users/show/12345.json',client.transport.url.path,"Id should be appended by default")
337
354
  client.auto_append_ids = false
338
355
  client.users.show.json? :id=>12345
339
- assert_equal('/1/users/show.json',client.transport.url.path,"Id should not be appended")
356
+ assert_equal('/1.1/users/show.json',client.transport.url.path,"Id should not be appended")
340
357
  assert_equal(12345,client.transport.options[:params][:id], "Id should be treated as a parameter")
341
358
  assert_equal("id=#{12345}",Net::HTTP.request.path.split(/\?/)[1],"id should be part of the query string")
342
359
  end
@@ -344,7 +361,7 @@ class ClientTest < Test::Unit::TestCase
344
361
  def test_auto_append_ids_can_be_set_in_constructor
345
362
  client = new_client(200,'{"id":12345,"screen_name":"test_user"}',:auto_append_ids=>false)
346
363
  client.users.show.json? :id=>12345
347
- assert_equal('/1/users/show.json',client.transport.url.path,"Id should not be appended")
364
+ assert_equal('/1.1/users/show.json',client.transport.url.path,"Id should not be appended")
348
365
  assert_equal(12345,client.transport.options[:params][:id], "Id should be treated as a parameter")
349
366
  assert_equal("id=#{12345}",Net::HTTP.request.path.split(/\?/)[1],"id should be part of the query string")
350
367
  end
@@ -352,23 +369,23 @@ class ClientTest < Test::Unit::TestCase
352
369
  def test_auto_append_format_is_honored
353
370
  client = new_client(200,'{"id":12345,"screen_name":"test_user"}')
354
371
  client.users.show.hayesdavis?
355
- assert_equal('/1/users/show/hayesdavis.json',client.transport.url.path,"Format should be appended by default")
372
+ assert_equal('/1.1/users/show/hayesdavis.json',client.transport.url.path,"Format should be appended by default")
356
373
  client.auto_append_format = false
357
374
  client.users.show.hayesdavis?
358
- assert_equal('/1/users/show/hayesdavis',client.transport.url.path,"Format should not be appended to the URI")
375
+ assert_equal('/1.1/users/show/hayesdavis',client.transport.url.path,"Format should not be appended to the URI")
359
376
  end
360
377
 
361
378
  def test_auto_append_format_can_be_set_in_constructor
362
379
  client = new_client(200,'{"id":12345,"screen_name":"test_user"}',:auto_append_format=>false)
363
380
  client.users.show.hayesdavis?
364
- assert_equal('/1/users/show/hayesdavis',client.transport.url.path,"Format should not be appended to the URI")
381
+ assert_equal('/1.1/users/show/hayesdavis',client.transport.url.path,"Format should not be appended to the URI")
365
382
  end
366
383
 
367
384
  def test_default_api
368
385
  client = Grackle::Client.new
369
- assert_equal(:v1,client.api,":v1 should be default api")
386
+ assert_equal(:v1_1,client.api,":v1_1 should be default api")
370
387
  end
371
-
388
+
372
389
  # Methods like Twitter's DELETE list membership expect that the user id will
373
390
  # be form encoded like a POST request in the body. Net::HTTP seems to think
374
391
  # that DELETEs can't have body parameters so we have to work around that.
@@ -378,7 +395,7 @@ class ClientTest < Test::Unit::TestCase
378
395
  assert_equal(:delete,client.transport.method,"Expected delete request")
379
396
  assert_equal('http',client.transport.url.scheme,"Expected scheme to be http")
380
397
  assert_equal('api.twitter.com',client.transport.url.host,"Expected request to be against twitter.com")
381
- assert_equal('/1/some_user/some_list/members.json',client.transport.url.path)
398
+ assert_equal('/1.1/some_user/some_list/members.json',client.transport.url.path)
382
399
  assert_match(/user_id=12345/,Net::HTTP.request.body,"Parameters should be form encoded")
383
400
  end
384
401
 
@@ -414,7 +431,7 @@ class ClientTest < Test::Unit::TestCase
414
431
  assert_equal(:post,client.transport.method,"Expected post request")
415
432
  assert_equal('http',client.transport.url.scheme,"Expected scheme to be http")
416
433
  assert_equal('api.twitter.com',client.transport.url.host,"Expected request to be against twitter.com")
417
- assert_equal('/1/statuses/update.json',client.transport.url.path)
434
+ assert_equal('/1.1/statuses/update.json',client.transport.url.path)
418
435
 
419
436
  if RUBY_VERSION >= "1.9.3"
420
437
  # 1.9.3 encodes a space with a + instead of %20
metadata CHANGED
@@ -1,73 +1,75 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: grackle
3
- version: !ruby/object:Gem::Version
4
- version: 0.2.1
5
- prerelease:
3
+ version: !ruby/object:Gem::Version
4
+ hash: 19
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Hayes Davis
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2012-08-15 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2013-03-31 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
15
22
  name: json
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :runtime
23
23
  prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: '0'
30
- - !ruby/object:Gem::Dependency
31
- name: mime-types
32
- requirement: !ruby/object:Gem::Requirement
24
+ requirement: &id001 !ruby/object:Gem::Requirement
33
25
  none: false
34
- requirements:
35
- - - ! '>='
36
- - !ruby/object:Gem::Version
37
- version: '0'
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
38
33
  type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: mime-types
39
37
  prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ! '>='
44
- - !ruby/object:Gem::Version
45
- version: '0'
46
- - !ruby/object:Gem::Dependency
47
- name: oauth
48
- requirement: !ruby/object:Gem::Requirement
38
+ requirement: &id002 !ruby/object:Gem::Requirement
49
39
  none: false
50
- requirements:
51
- - - ! '>='
52
- - !ruby/object:Gem::Version
53
- version: '0'
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
54
47
  type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: oauth
55
51
  prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
52
+ requirement: &id003 !ruby/object:Gem::Requirement
57
53
  none: false
58
- requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- description: ! " Grackle is a library for the Twitter REST and Search API designed
63
- to not\n require a new release in the face Twitter API changes or errors.\n"
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :runtime
62
+ version_requirements: *id003
63
+ description: " Grackle is a lightweight library for the Twitter REST API designed to be\n resilient to Twitter API changes or errors.\n"
64
64
  email: hayes@unionmetrics.com
65
65
  executables: []
66
+
66
67
  extensions: []
67
- extra_rdoc_files:
68
+
69
+ extra_rdoc_files:
68
70
  - README.rdoc
69
71
  - CHANGELOG.rdoc
70
- files:
72
+ files:
71
73
  - README.rdoc
72
74
  - CHANGELOG.rdoc
73
75
  - lib/grackle/client.rb
@@ -79,28 +81,39 @@ files:
79
81
  - test/client_test.rb
80
82
  - test/handlers_test.rb
81
83
  - test/test_helper.rb
84
+ has_rdoc: true
82
85
  homepage: http://github.com/hayesdavis/grackle
83
86
  licenses: []
87
+
84
88
  post_install_message:
85
89
  rdoc_options: []
86
- require_paths:
90
+
91
+ require_paths:
87
92
  - lib
88
- required_ruby_version: !ruby/object:Gem::Requirement
93
+ required_ruby_version: !ruby/object:Gem::Requirement
89
94
  none: false
90
- requirements:
91
- - - ! '>='
92
- - !ruby/object:Gem::Version
93
- version: '0'
94
- required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ hash: 3
99
+ segments:
100
+ - 0
101
+ version: "0"
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
103
  none: false
96
- requirements:
97
- - - ! '>='
98
- - !ruby/object:Gem::Version
99
- version: '0'
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 0
110
+ version: "0"
100
111
  requirements: []
112
+
101
113
  rubyforge_project:
102
- rubygems_version: 1.8.23
114
+ rubygems_version: 1.3.7
103
115
  signing_key:
104
116
  specification_version: 3
105
- summary: Grackle is a lightweight library for the Twitter REST and Search API.
117
+ summary: Grackle is a lightweight library for the Twitter REST API.
106
118
  test_files: []
119
+