grackle 0.1.5 → 0.1.6

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/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.1.6 (2009-10-29)
2
+ * Added support for HTTP methods beside GET and POST using block syntax
3
+ * Added method for appending to the request path something that's not a valid ruby method
4
+
1
5
  == 0.1.5 (2009-10-28)
2
6
  Added support for the Twitter version 1 API as a API symbol :v1
3
7
 
data/README.rdoc CHANGED
@@ -79,6 +79,20 @@ You can force a format. To update the authenticated user's status using the XML
79
79
 
80
80
  Or, with JSON
81
81
  client.statuses.update.json! :status=>'this status is from grackle' #POST to http://twitter.com/statuses/update.json
82
+
83
+ ===Using Other HTTP Verbs
84
+ To use HTTP verbs like DELETE or PUT, Grackle provides a slightly different syntax:
85
+ client.put{ hayesdavis.lists.my_list :name=>'New Name' } #HTTP PUT
86
+ client.delete{ direct_messages.destroy :id=>1 } #HTTP DELETE
87
+
88
+ You may specify any method chain you wish in the block. Note that if your method chain inside the block
89
+ ends in a ! or ?, that the HTTP verb for the block will still be used. This means that
90
+ client.delete{ direct_messages.destroy! :id=>1 } #Uses HTTP DELETE, not POST
91
+ client.direct_messages.destroy! :id=>1 #Uses HTTP POST
92
+
93
+ If for some reason you don't like the preferred block syntax above, you may specify a
94
+ parameter to your method chain called :__method (note the double underscores) to specify the HTTP verb:
95
+ client.direct_messages.destroy! :id=>1, :__method=>:delete #HTTP DELETE
82
96
 
83
97
  ===Toggling APIs
84
98
  By default, the Grackle::Client sends all requests to the unversioned Twitter REST API. If you want to send requests to
@@ -125,6 +139,12 @@ the raw response body. The Grackle::Client has a default_format you can specify.
125
139
  If you don't include a named format in your method chain as described above, but use a "?" or "!" then the
126
140
  Grackle::Client.default_format is used.
127
141
 
142
+ ===Odds and Ends
143
+ If you need to append something to the request path that isn't a valid ruby method, e.g.
144
+ /1user/lists.json #1user isn't a valid Ruby method
145
+ you can use the Grackle::Client#_ method like so:
146
+ client._('1user').lists.json
147
+
128
148
  == REQUIREMENTS:
129
149
 
130
150
  You'll need the following gems to use all features of Grackle:
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"
5
+ s.version = "0.1.6"
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{2009-05-23}
9
+ s.date = %q{2009-10-29}
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"]
@@ -45,13 +45,12 @@ module Grackle
45
45
  class Client
46
46
 
47
47
  class Request #:nodoc:
48
- attr_accessor :client, :path, :method, :api, :ssl
48
+ attr_accessor :client, :path, :method, :api, :ssl, :params
49
49
 
50
50
  def initialize(client,api=:rest,ssl=true)
51
51
  self.client = client
52
52
  self.api = api
53
53
  self.ssl = ssl
54
- self.method = :get
55
54
  self.path = ''
56
55
  end
57
56
 
@@ -74,9 +73,12 @@ module Grackle
74
73
  def scheme
75
74
  ssl ? 'https' :'http'
76
75
  end
76
+
77
+ def params
78
+ @params ||= {}
79
+ end
77
80
  end
78
81
 
79
- VALID_METHODS = [:get,:post,:put,:delete]
80
82
  VALID_FORMATS = [:json,:xml,:atom,:rss]
81
83
 
82
84
  # Contains the mapping of API name symbols to actual host (and path)
@@ -133,26 +135,11 @@ module Grackle
133
135
  end
134
136
  end
135
137
 
136
- def method_missing(name,*args)
137
- #If method is a format name, execute using that format
138
- if format_invocation?(name)
139
- return call_with_format(name,*args)
140
- end
141
- #If method ends in ! or ? use that to determine post or get
142
- if name.to_s =~ /^(.*)(!|\?)$/
143
- name = $1.to_sym
144
- #! is a post, ? is a get
145
- self.request.method = ($2 == '!' ? :post : :get)
146
- if format_invocation?(name)
147
- return call_with_format(name,*args)
148
- else
149
- self.request << "/#{$1}"
150
- return call_with_format(self.default_format,*args)
151
- end
138
+ def method_missing(name,*args,&block)
139
+ if block_given?
140
+ return request_with_http_method_block(name,&block)
152
141
  end
153
- #Else add to the request path
154
- self.request << "/#{name}"
155
- self
142
+ append(name,*args)
156
143
  end
157
144
 
158
145
  # Used to toggle APIs for a particular request without setting the Client's default API
@@ -197,21 +184,53 @@ module Grackle
197
184
  auth[:password] = value
198
185
  end
199
186
 
187
+ def append(name,*args)
188
+ name = name.to_sym
189
+ #The args will be a hash, store them if they're specified
190
+ self.request.params = *args
191
+ #If method is a format name, execute using that format
192
+ if format_invocation?(name)
193
+ return call_with_format(name)
194
+ end
195
+ #If method ends in ! or ? use that to determine post or get
196
+ if name.to_s =~ /^(.*)(!|\?)$/
197
+ name = $1.to_sym
198
+ #! is a post, ? is a get - only set this if the method hasn't been set
199
+ self.request.method ||= ($2 == '!' ? :post : :get)
200
+ if format_invocation?(name)
201
+ return call_with_format(name)
202
+ else
203
+ self.request << "/#{$1}"
204
+ return call_with_format(self.default_format)
205
+ end
206
+ end
207
+ #Else add to the request path
208
+ self.request << "/#{name}"
209
+ self
210
+ end
211
+
212
+ alias_method :_, :append
213
+
200
214
  protected
201
- def call_with_format(format,params={})
202
- id = params.delete(:id)
215
+ def call_with_format(format)
216
+ id = request.params.delete(:id)
203
217
  request << "/#{id}" if id
204
218
  request << ".#{format}"
205
- res = send_request(params)
219
+ res = send_request
206
220
  process_response(format,res)
207
221
  ensure
208
222
  clear
209
223
  end
210
224
 
211
- def send_request(params)
225
+ def send_request
212
226
  begin
227
+ http_method = (
228
+ request.params.delete(:__method) or request.method or :get
229
+ )
213
230
  transport.request(
214
- request.method,request.url,:auth=>auth,:headers=>headers,:params=>params, :timeout => timeout
231
+ http_method, request.url,
232
+ :auth=>auth,:headers=>headers,
233
+ :params=>request.params,:timeout => timeout
215
234
  )
216
235
  rescue => e
217
236
  puts e
@@ -251,5 +270,19 @@ module Grackle
251
270
  def format_invocation?(name)
252
271
  self.request.path? && VALID_FORMATS.include?(name)
253
272
  end
273
+
274
+ def pending_request?
275
+ !@request.nil?
276
+ end
277
+
278
+ def request_with_http_method_block(method,&block)
279
+ request.method = method
280
+ response = instance_eval(&block)
281
+ if pending_request?
282
+ call_with_format(self.default_format)
283
+ else
284
+ response
285
+ end
286
+ end
254
287
  end
255
288
  end
@@ -19,12 +19,7 @@ module Grackle
19
19
  DEFAULT_REDIRECT_LIMIT = 5
20
20
 
21
21
  def req_class(method)
22
- case method
23
- when :get then Net::HTTP::Get
24
- when :post then Net::HTTP::Post
25
- when :put then Net::HTTP::Put
26
- when :delete then Net::HTTP::Delete
27
- end
22
+ Net::HTTP.const_get(method.to_s.capitalize)
28
23
  end
29
24
 
30
25
  # Options are one of
data/lib/grackle.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Grackle
2
2
 
3
3
  # :stopdoc:
4
- VERSION = '0.1.5'
4
+ VERSION = '0.1.6'
5
5
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
6
6
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
7
7
  # :startdoc:
data/test/test_client.rb CHANGED
@@ -195,6 +195,45 @@ class TestClient < Test::Unit::TestCase
195
195
  client.statuses.public_timeline? :since=>time
196
196
  assert_equal("/statuses/public_timeline.json?since=#{CGI::escape(time.httpdate)}",Net::HTTP.request.path)
197
197
  end
198
+
199
+ def test_simple_http_method_block
200
+ client = new_client(200,'[{"id":1,"text":"test 1"}]')
201
+ client.delete { direct_messages.destroy :id=>1, :other=>'value' }
202
+ assert_equal(:delete,client.transport.method, "delete block should use delete method")
203
+ assert_equal("/direct_messages/destroy/1.json",Net::HTTP.request.path)
204
+ assert_equal('value',client.transport.options[:params][:other])
205
+
206
+ client = new_client(200,'{"id":54321,"screen_name":"test_user"}')
207
+ value = client.get { users.show.json? :screen_name=>'test_user' }
208
+ assert_equal(:get,client.transport.method)
209
+ assert_equal('http',client.transport.url.scheme)
210
+ assert(!Net::HTTP.last_instance.use_ssl?,'Net::HTTP instance should not be set to use SSL')
211
+ assert_equal('twitter.com',client.transport.url.host)
212
+ assert_equal('/users/show.json',client.transport.url.path)
213
+ assert_equal('test_user',client.transport.options[:params][:screen_name])
214
+ assert_equal('screen_name=test_user',Net::HTTP.request.path.split(/\?/)[1])
215
+ assert_equal(54321,value.id)
216
+ end
217
+
218
+ def test_http_method_blocks_choose_right_method
219
+ client = new_client(200,'[{"id":1,"text":"test 1"}]')
220
+ client.get { search :q=>'test' }
221
+ assert_equal(:get,client.transport.method, "Get block should choose get method")
222
+ client.delete { direct_messages.destroy :id=>1 }
223
+ assert_equal(:delete,client.transport.method, "Delete block should choose delete method")
224
+ client.post { direct_messages.destroy :id=>1 }
225
+ assert_equal(:post,client.transport.method, "Post block should choose post method")
226
+ client.put { direct_messages :id=>1 }
227
+ assert_equal(:put,client.transport.method, "Put block should choose put method")
228
+ end
229
+
230
+ def test_http_method_selection_precedence
231
+ client = new_client(200,'[{"id":1,"text":"test 1"}]')
232
+ client.get { search! :q=>'test' }
233
+ assert_equal(:get,client.transport.method, "Get block should override method even if post bang is used")
234
+ client.delete { search? :q=>'test', :__method=>:post }
235
+ assert_equal(:post,client.transport.method, ":__method=>:post should override block setting and method suffix")
236
+ end
198
237
 
199
238
  private
200
239
  def with_http_responder(responder)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grackle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hayes Davis
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-23 00:00:00 -05:00
12
+ date: 2009-10-29 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency