weary 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +95 -13
- data/Rakefile +5 -29
- data/VERSION +1 -1
- data/examples/batch.rb +20 -0
- data/examples/repo.rb +7 -11
- data/examples/status.rb +10 -2
- data/lib/weary.rb +40 -7
- data/lib/weary/base.rb +1 -2
- data/lib/weary/batch.rb +37 -0
- data/lib/weary/exceptions.rb +1 -1
- data/lib/weary/httpverb.rb +2 -2
- data/lib/weary/request.rb +116 -33
- data/lib/weary/resource.rb +1 -1
- data/lib/weary/response.rb +19 -23
- data/spec/spec_helper.rb +7 -18
- data/spec/weary/base_spec.rb +10 -11
- data/spec/weary/batch_spec.rb +71 -0
- data/spec/weary/httpverb_spec.rb +5 -0
- data/spec/weary/request_spec.rb +326 -33
- data/spec/weary/resource_spec.rb +2 -2
- data/spec/weary/response_spec.rb +137 -41
- data/spec/weary_spec.rb +54 -0
- data/weary.gemspec +14 -3
- metadata +28 -3
data/README.md
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
# Weary
|
2
2
|
|
3
|
-
|
3
|
+
Weary is a tiny DSL for making the consumption of RESTful web services simple. It has evolved from the ideas put forth by libraries like [HTTParty](http://github.com/jnunemaker/httparty/ "JNunemaker's HTTParty") and [Typhoeus](http://github.com/pauldix/typhoeus "Paul Dix's Typhoeus"). It provides some sweet syntactic sugar over the Net/HTTP standard library.
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
The things it do:
|
5
|
+
What does it do:
|
8
6
|
|
9
7
|
+ Quickly build an interface to your favorite REST API.
|
10
8
|
+ Parse XML and JSON with the [Crack](http://github.com/jnunemaker/crack) library.
|
11
|
-
+
|
12
|
-
+
|
9
|
+
+ Authentication with Basic Authentication and [OAuth](http://oauth.net/).
|
10
|
+
+ Asynchronous, multi-threaded requests.
|
13
11
|
|
14
12
|
Browse the documentation here: [http://rdoc.info/projects/mwunsch/weary](http://rdoc.info/projects/mwunsch/weary)
|
15
13
|
Peruse the [Wiki](http://wiki.github.com/mwunsch/weary) to discover libraries built with Weary and a more thorough review of the API.
|
@@ -19,6 +17,7 @@ Peruse the [Wiki](http://wiki.github.com/mwunsch/weary) to discover libraries bu
|
|
19
17
|
+ [Crack](http://github.com/jnunemaker/crack) >= 0.1.2
|
20
18
|
+ [OAuth](http://github.com/mojodna/oauth) >= 0.3.5
|
21
19
|
+ [RSpec](http://rspec.info/) (for running the tests)
|
20
|
+
+ [FakeWeb](http://github.com/chrisk/fakeweb) (for running the tests)
|
22
21
|
|
23
22
|
## Installation
|
24
23
|
|
@@ -42,10 +41,9 @@ You do have Rubygems right? You do use [Gemcutter](http://gemcutter.org/), right
|
|
42
41
|
me = user.show(:id => "markwunsch").perform
|
43
42
|
puts me["name"]
|
44
43
|
|
45
|
-
Hey, that's me!
|
46
|
-
|
44
|
+
Hey, that's me!
|
47
45
|
|
48
|
-
##
|
46
|
+
## The Base API/DSL
|
49
47
|
|
50
48
|
Create a class that inherits from `Weary::Base` to give it methods to craft a resource request:
|
51
49
|
|
@@ -58,7 +56,7 @@ Create a class that inherits from `Weary::Base` to give it methods to craft a re
|
|
58
56
|
|
59
57
|
If you instantiate this class, you'll get an instance method named `foo` that crafts a GET request to "http://path/to/foo"
|
60
58
|
|
61
|
-
Besides the name of the resource, you can also give `
|
59
|
+
Besides the name of the resource, you can also give `declare` a block like:
|
62
60
|
|
63
61
|
declare "foo" do |r|
|
64
62
|
r.url = "path/to/foo"
|
@@ -73,7 +71,7 @@ Besides the name of the resource, you can also give `declare_resource` a block l
|
|
73
71
|
So this would form a method:
|
74
72
|
|
75
73
|
x = Foo.new
|
76
|
-
x.foo
|
74
|
+
x.foo :id => "mwunsch", :bar => 123
|
77
75
|
|
78
76
|
That method would return a `Weary::Request` object. Use the `perform` method and get a `Weary::Response` that you could parse and/or examine.
|
79
77
|
|
@@ -109,7 +107,7 @@ There are many ways to form URLs in Weary. You can define URLs for the entire cl
|
|
109
107
|
get "show_users"
|
110
108
|
end
|
111
109
|
|
112
|
-
If you don't supply a url when declaring the Resource, Weary will look to see if you've defined a domain, and will make a url for you. The above `get` declaration creates a url that looks like: *http://foo.bar/show_users.xml
|
110
|
+
If you don't supply a url when declaring the Resource, Weary will look to see if you've defined a domain, and will make a url for you. The above `get` declaration creates a url that looks like: *http://foo.bar/show_users.xml*. I think it's better to write the whole URL out. That's unambiguous.
|
113
111
|
|
114
112
|
### Weary DSL
|
115
113
|
|
@@ -135,5 +133,89 @@ Then you can do something like this:
|
|
135
133
|
f.update
|
136
134
|
|
137
135
|
Which will create a POST Request for *http://foo.bar/update.xml* that will authenticate you, using basic authentication, with the username/password of "me"/"secrets" and will send the parameter `{:user => "me"}`. Easy.
|
136
|
+
|
137
|
+
## Weary Class Methods
|
138
|
+
|
139
|
+
Maybe you don't want the baggage that comes with `Weary::Base`. That's okay, Weary provides some basic class-level methods to Easily build a `Weary::Request`:
|
140
|
+
|
141
|
+
# See examples/repo.rb to see this in practice
|
142
|
+
class Repository
|
143
|
+
|
144
|
+
def show(user, repo)
|
145
|
+
Weary.get "http://github.com/api/v2/yaml/repos/show/#{user}/#{repo}"
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
Repository.new.show 'mwunsch', 'weary'
|
151
|
+
|
152
|
+
That will build the Get request to fetch the YAML info about this repository.
|
153
|
+
|
154
|
+
Pass a block to `Weary.get` to dive further into the Request:
|
155
|
+
|
156
|
+
Weary.get "http://twitter.com/statuses/user_timeline" do |req|
|
157
|
+
req.follows = false
|
158
|
+
req.with = {:id => 'markwunsch'}
|
159
|
+
req.credentials = {:username => 'markwunsch', :password => 'secret'}
|
160
|
+
req.headers = {"User-Agent" => Weary::UserAgents["Safari 4.0.2 - Mac"]}
|
161
|
+
end
|
162
|
+
|
163
|
+
## Request Callbacks
|
164
|
+
|
165
|
+
A `Weary::Request` has a couple of callbacks you can do:
|
166
|
+
|
167
|
+
status = Weary.get("http://twitter.com/statuses/user_timeline") do |r|
|
168
|
+
r.with = {:id => 'markwunsch'}
|
169
|
+
end
|
170
|
+
|
171
|
+
status.before_send do |request|
|
172
|
+
puts "Sending a request to #{request.uri}"
|
173
|
+
end
|
174
|
+
|
175
|
+
status.on_complete do |response|
|
176
|
+
if response.success?
|
177
|
+
puts response.body
|
178
|
+
else
|
179
|
+
puts "Something went wrong: #{response.code}: #{response.message}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
`before_send` is sent just before the request is made, and `on_complete` is triggered immediately following. `before_send` passes the Request object to the block and `on_complete` passes the Response object.
|
184
|
+
|
185
|
+
You don't need to define `on_complete`, though. Passing a block to the `perform` method of the Request also defines this callback or will overwrite what you had previously defined:
|
186
|
+
|
187
|
+
status.perform do |response|
|
188
|
+
puts "Request to #{response.url}, complete. Got a #{response.code}."
|
189
|
+
end
|
190
|
+
|
191
|
+
## Multiple Asynchronous Requests with Batch
|
192
|
+
|
193
|
+
Requests, along with the `perform` method, also has a `perform!` method, which spins off a Thread to actually perform the Net::HTTP Request. This method returns a Thread object, and is encapsulated by the `perform` method.
|
194
|
+
|
195
|
+
Weary::Batch allows you to make a group of `perform!` requests, firing at will. It takes a group of Requests.
|
196
|
+
|
197
|
+
# see examples/batch.rb
|
198
|
+
resources = %w[http://twitter.com http://github.com http://vimeo.com http://tumblr.com]
|
199
|
+
requests = []
|
200
|
+
|
201
|
+
## build the group of requests:
|
202
|
+
resources.each do |url|
|
203
|
+
requests << Weary.get(url) do |req|
|
204
|
+
req.on_complete {|res| puts "Hello from #{res.url}"}
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
## And fire them off:
|
209
|
+
Weary.batch(requests).perform
|
210
|
+
|
211
|
+
Batch has callbacks, just like the Request:
|
212
|
+
|
213
|
+
Weary.batch(requests).perform do
|
214
|
+
puts 'All done.'
|
215
|
+
end
|
216
|
+
|
217
|
+
You can investigate the pool of threads once you've called `perform` with `Batch#pool` or look at all the returned responses with `Batch#responses`.
|
218
|
+
|
219
|
+
## And more...
|
138
220
|
|
139
|
-
There's more to discover in the Wiki.
|
221
|
+
There's more to discover in the Wiki.
|
data/Rakefile
CHANGED
@@ -20,42 +20,18 @@ begin
|
|
20
20
|
gemspec.summary = "A little DSL for consuming RESTful web services"
|
21
21
|
gemspec.email = "mark@markwunsch.com"
|
22
22
|
gemspec.homepage = "http://github.com/mwunsch/weary"
|
23
|
-
gemspec.description = "
|
23
|
+
gemspec.description = "A tiny DSL that makes the consumption of RESTful web services simple."
|
24
24
|
gemspec.authors = "Mark Wunsch"
|
25
|
-
gemspec.add_dependency
|
26
|
-
gemspec.add_dependency
|
25
|
+
gemspec.add_dependency 'crack', '>= 0.1.2'
|
26
|
+
gemspec.add_dependency 'oauth', '>= 0.3.5'
|
27
|
+
gemspec.add_development_dependency 'rspec'
|
28
|
+
gemspec.add_development_dependency 'fakeweb'
|
27
29
|
end
|
28
30
|
Jeweler::GemcutterTasks.new
|
29
31
|
rescue LoadError
|
30
32
|
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
31
33
|
end
|
32
34
|
|
33
|
-
begin
|
34
|
-
require 'rake/contrib/sshpublisher'
|
35
|
-
namespace :rubyforge do
|
36
|
-
|
37
|
-
desc "Release gem and RDoc documentation to RubyForge"
|
38
|
-
task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
|
39
|
-
|
40
|
-
namespace :release do
|
41
|
-
desc "Publish RDoc to RubyForge."
|
42
|
-
task :docs => [:rdoc] do
|
43
|
-
config = YAML.load(
|
44
|
-
File.read(File.expand_path('~/.rubyforge/user-config.yml'))
|
45
|
-
)
|
46
|
-
|
47
|
-
host = "#{config['username']}@rubyforge.org"
|
48
|
-
remote_dir = "/var/www/gforge-projects/weary/"
|
49
|
-
local_dir = 'doc'
|
50
|
-
|
51
|
-
Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
rescue LoadError
|
56
|
-
puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
|
57
|
-
end
|
58
|
-
|
59
35
|
desc "Open an irb session preloaded with this library"
|
60
36
|
task :console do
|
61
37
|
sh "irb -rubygems -I lib -r weary.rb"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
data/examples/batch.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'rubygems'
|
3
|
+
require 'weary'
|
4
|
+
require 'fakeweb'
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
hello = "Hello from"
|
8
|
+
resources = %w[http://twitter.com http://github.com http://vimeo.com http://tumblr.com]
|
9
|
+
resources.each {|url| FakeWeb.register_uri :get, url, :body => "#{hello} #{url}" }
|
10
|
+
|
11
|
+
requests = []
|
12
|
+
resources.each do |url|
|
13
|
+
requests << Weary.get(url) do |request|
|
14
|
+
request.on_complete { |response| puts response.body }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Weary.batch(requests).perform
|
19
|
+
|
20
|
+
FakeWeb.clean_registry
|
data/examples/repo.rb
CHANGED
@@ -2,19 +2,15 @@ $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib
|
|
2
2
|
require 'rubygems'
|
3
3
|
require 'weary'
|
4
4
|
|
5
|
-
class Repository
|
5
|
+
class Repository
|
6
6
|
|
7
|
-
def
|
8
|
-
|
9
|
-
r.url = "http://github.com/api/v2/yaml/repos/show/#{user}/#{repo}"
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
get "show" do |r|
|
14
|
-
r.url = "http://github.com/api/v2/yaml/repos/show/__gh_user__/__gh_repo__"
|
7
|
+
def show(user, repo)
|
8
|
+
Weary.get "http://github.com/api/v2/yaml/repos/show/#{user}/#{repo}"
|
15
9
|
end
|
16
10
|
|
17
11
|
end
|
18
12
|
|
19
|
-
weary = Repository.new
|
20
|
-
|
13
|
+
weary = Repository.new
|
14
|
+
weary.show('mwunsch','weary').perform do |response|
|
15
|
+
puts response.body
|
16
|
+
end
|
data/examples/status.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
2
|
require 'rubygems'
|
3
3
|
require 'weary'
|
4
|
+
require 'pp'
|
4
5
|
|
5
6
|
class Status < Weary::Base
|
6
7
|
|
@@ -14,5 +15,12 @@ class Status < Weary::Base
|
|
14
15
|
end
|
15
16
|
|
16
17
|
toots = Status.new
|
17
|
-
|
18
|
-
|
18
|
+
|
19
|
+
toots.user_timeline(:id => "markwunsch").perform do |response|
|
20
|
+
if response.success?
|
21
|
+
recent_toot = response[0]
|
22
|
+
puts "@#{recent_toot['user']['screen_name']}: \"#{recent_toot['text']}\""
|
23
|
+
else
|
24
|
+
puts "#{response.code}: #{response.message}"
|
25
|
+
end
|
26
|
+
end
|
data/lib/weary.rb
CHANGED
@@ -10,19 +10,23 @@ autoload :Yaml, 'yaml'
|
|
10
10
|
require 'weary/request'
|
11
11
|
require 'weary/response'
|
12
12
|
require 'weary/resource'
|
13
|
+
require 'weary/batch'
|
13
14
|
require 'weary/exceptions'
|
14
15
|
require 'weary/httpverb'
|
15
16
|
require 'weary/base'
|
16
17
|
|
17
18
|
module Weary
|
18
19
|
|
20
|
+
# Supported HTTP Verbs
|
19
21
|
Methods = [:get, :post, :put, :delete, :head]
|
22
|
+
|
23
|
+
# Supported Content Types
|
20
24
|
ContentTypes = { :json => [:json, 'json', 'application/json', 'text/json', 'application/javascript', 'text/javascript'],
|
21
25
|
:xml => [:xml, 'xml', 'text/xml', 'application/xml'],
|
22
26
|
:html => [:html, 'html', 'text/html'],
|
23
27
|
:yaml => [:yaml, 'yaml', 'application/x-yaml', 'text/yaml'],
|
24
|
-
:plain => [:plain, 'plain', 'text/plain']
|
25
|
-
|
28
|
+
:plain => [:plain, 'plain', 'text/plain'] }
|
29
|
+
|
26
30
|
# A collection of User Agent strings that I stole from HURL (http://hurl.it)
|
27
31
|
UserAgents = {
|
28
32
|
"Firefox 1.5.0.12 - Mac" => "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.12) Gecko/20070508 Firefox/1.5.0.12",
|
@@ -33,7 +37,7 @@ module Weary
|
|
33
37
|
"Firefox 3.0.4 - Windows" => "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/2008102920 Firefox/3.0.4",
|
34
38
|
"Firefox 3.5.2 - Mac" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2",
|
35
39
|
"Firefox 3.5.2 - Windows" => "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2",
|
36
|
-
"Internet Explorer 5.2.3
|
40
|
+
"Internet Explorer 5.2.3 - Mac" => "Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC)",
|
37
41
|
"Internet Explorer 5.5" => "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.1)",
|
38
42
|
"Internet Explorer 6.0" => "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)",
|
39
43
|
"Internet Explorer 7.0" => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
|
@@ -55,10 +59,39 @@ module Weary
|
|
55
59
|
"Safari 4.0.2 - Windows" => "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/4.0.2 Safari/530.19.1"
|
56
60
|
}
|
57
61
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
+
class << self
|
63
|
+
def get(url,&block)
|
64
|
+
request url, :get, block
|
65
|
+
end
|
66
|
+
|
67
|
+
def post(url,&block)
|
68
|
+
request url, :post, block
|
69
|
+
end
|
70
|
+
|
71
|
+
def put(url,&block)
|
72
|
+
request url, :put, block
|
73
|
+
end
|
74
|
+
|
75
|
+
def delete(url,&block)
|
76
|
+
request url, :delete, block
|
77
|
+
end
|
78
|
+
|
79
|
+
def head(url,&block)
|
80
|
+
request url, :head, block
|
81
|
+
end
|
82
|
+
|
83
|
+
# Create a Request for the URL.
|
84
|
+
# Defaults to a GET Request. Use a block to further modify the Request
|
85
|
+
def request(url,via = :get,block = nil)
|
86
|
+
req = Request.new(url,via)
|
87
|
+
block.call(req) if block
|
88
|
+
req
|
89
|
+
end
|
90
|
+
|
91
|
+
# Create a Batch for a group of Requests
|
92
|
+
def batch(*requests)
|
93
|
+
Batch.new(requests)
|
94
|
+
end
|
62
95
|
end
|
63
96
|
|
64
97
|
end
|
data/lib/weary/base.rb
CHANGED
@@ -16,8 +16,7 @@ module Weary
|
|
16
16
|
|
17
17
|
# Each Weary::Base object has its own set of Resources
|
18
18
|
def resources
|
19
|
-
@resources
|
20
|
-
@resources
|
19
|
+
@resources ||= Marshal.load(Marshal.dump(@@resources))
|
21
20
|
end
|
22
21
|
|
23
22
|
# Make changes to a Resource given and rebuild the Request method for this object
|
data/lib/weary/batch.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Weary
|
2
|
+
class Batch
|
3
|
+
|
4
|
+
attr_accessor :requests, :pool, :responses
|
5
|
+
|
6
|
+
def initialize(*requests)
|
7
|
+
@requests = requests.flatten
|
8
|
+
end
|
9
|
+
|
10
|
+
# A callback that is triggered after all the Responses have been received.
|
11
|
+
def on_complete(&block)
|
12
|
+
@on_complete = block if block_given?
|
13
|
+
@on_complete
|
14
|
+
end
|
15
|
+
|
16
|
+
# A callback that is triggered before the Requests are performed
|
17
|
+
def before_send(&block)
|
18
|
+
@before_send = block if block_given?
|
19
|
+
@before_send
|
20
|
+
end
|
21
|
+
|
22
|
+
# Perform each Request in a separate Thread.
|
23
|
+
# The Threads are collected in `pool`.
|
24
|
+
# The Responses are collected in `responses`.
|
25
|
+
# Pass in a block to use as the on_complete callback.
|
26
|
+
def perform(&block)
|
27
|
+
@on_complete = block if block_given?
|
28
|
+
@responses = []
|
29
|
+
@pool = []
|
30
|
+
before_send.call if before_send
|
31
|
+
requests.each {|req| @pool << req.perform! }
|
32
|
+
pool.each {|res| @responses << res.value }
|
33
|
+
on_complete.call if on_complete
|
34
|
+
responses
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/weary/exceptions.rb
CHANGED
@@ -11,5 +11,5 @@ module Weary
|
|
11
11
|
class NotFound < ClientError; end #404
|
12
12
|
class MethodNotAllowed < ClientError; end #405
|
13
13
|
class ResourceConflict < ClientError; end #409
|
14
|
-
class UnprocessableEntity < ClientError; end #422
|
14
|
+
class UnprocessableEntity < ClientError; end #422
|
15
15
|
end
|
data/lib/weary/httpverb.rb
CHANGED
@@ -6,7 +6,7 @@ module Weary
|
|
6
6
|
def initialize(http_verb = :get)
|
7
7
|
self.verb = http_verb
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def normalize
|
11
11
|
return verb.to_s.strip.downcase.intern
|
12
12
|
end
|
@@ -24,7 +24,7 @@ module Weary
|
|
24
24
|
when :head
|
25
25
|
Net::HTTP::Head
|
26
26
|
else
|
27
|
-
|
27
|
+
raise "Weary does not recognize the HTTP verb '#{normalize.inspect}'."
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
data/lib/weary/request.rb
CHANGED
@@ -1,20 +1,34 @@
|
|
1
1
|
module Weary
|
2
2
|
class Request
|
3
3
|
|
4
|
-
attr_reader :uri
|
5
|
-
attr_accessor :
|
4
|
+
attr_reader :uri, :with, :credentials
|
5
|
+
attr_accessor :headers
|
6
6
|
|
7
7
|
def initialize(url, http_verb= :get, options={})
|
8
|
-
self.method = http_verb
|
9
8
|
self.uri = url
|
10
|
-
self.
|
9
|
+
self.via = http_verb
|
10
|
+
self.credentials = {:username => options[:basic_auth][:username],
|
11
|
+
:password => options[:basic_auth][:password]} if options[:basic_auth]
|
12
|
+
self.credentials = options[:oauth] if options[:oauth]
|
13
|
+
if (options[:body])
|
14
|
+
self.with = options[:body]
|
15
|
+
end
|
16
|
+
self.headers = options[:headers] if options[:headers]
|
17
|
+
self.follows = true
|
18
|
+
if options.has_key?(:no_follow)
|
19
|
+
self.follows = options[:no_follow] ? false : true
|
20
|
+
end
|
11
21
|
end
|
12
|
-
|
22
|
+
|
23
|
+
# Create a URI object for the given URL
|
13
24
|
def uri=(url)
|
14
25
|
@uri = URI.parse(url)
|
26
|
+
if (with && !request_preparation.request_body_permitted?)
|
27
|
+
@uri.query = with
|
28
|
+
end
|
15
29
|
end
|
16
30
|
|
17
|
-
def
|
31
|
+
def via=(http_verb)
|
18
32
|
verb = HTTPVerb.new(http_verb).normalize
|
19
33
|
@http_verb = if Methods.include?(verb)
|
20
34
|
verb
|
@@ -23,44 +37,113 @@ module Weary
|
|
23
37
|
end
|
24
38
|
end
|
25
39
|
|
26
|
-
def
|
40
|
+
def via
|
27
41
|
@http_verb
|
28
42
|
end
|
29
43
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
44
|
+
# Set parameters to send with the Request.
|
45
|
+
# If this Request does not accept a body (a GET request for instance),
|
46
|
+
# set the query string for the url.
|
47
|
+
def with=(params)
|
48
|
+
@with = (params.respond_to?(:to_params) ? params.to_params : params)
|
49
|
+
if (!request_preparation.request_body_permitted?)
|
50
|
+
uri.query = @with
|
36
51
|
end
|
37
|
-
response
|
38
52
|
end
|
39
53
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
54
|
+
# Credentials to send to Authorize the Request
|
55
|
+
# For basic auth, use a hash with keys :username and :password
|
56
|
+
# For OAuth, use an Access Token
|
57
|
+
def credentials=(auth)
|
58
|
+
if auth.is_a?(OAuth::AccessToken)
|
59
|
+
@credentials = auth
|
60
|
+
else
|
61
|
+
@credentials = {:username => auth[:username], :password => auth[:password]}
|
46
62
|
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Should the Request follow redirects?
|
66
|
+
def follows=(bool)
|
67
|
+
@follows = (bool ? true : false)
|
68
|
+
end
|
69
|
+
|
70
|
+
def follows?
|
71
|
+
@follows
|
72
|
+
end
|
73
|
+
|
74
|
+
# A callback that is triggered after the Response is received.
|
75
|
+
def on_complete(&block)
|
76
|
+
@on_complete = block if block_given?
|
77
|
+
@on_complete
|
78
|
+
end
|
47
79
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
80
|
+
# A callback that is sent before the Request is fired.
|
81
|
+
def before_send(&block)
|
82
|
+
@before_send = block if block_given?
|
83
|
+
@before_send
|
84
|
+
end
|
85
|
+
|
86
|
+
# Perform the Request, returns the Response. Pass a block in to use
|
87
|
+
# as the on_complete callback.
|
88
|
+
def perform(&block)
|
89
|
+
@on_complete = block if block_given?
|
90
|
+
response = perform!
|
91
|
+
response.value
|
92
|
+
end
|
93
|
+
|
94
|
+
# Spins off a new thread to perform the Request.
|
95
|
+
def perform!(&block)
|
96
|
+
@on_complete = block if block_given?
|
97
|
+
Thread.new {
|
98
|
+
before_send.call(self) if before_send
|
99
|
+
req = http.request(request)
|
100
|
+
response = Response.new(req, self)
|
101
|
+
if response.redirected? && follows?
|
102
|
+
response.follow_redirect
|
103
|
+
else
|
104
|
+
on_complete.call(response) if on_complete
|
105
|
+
response
|
58
106
|
end
|
59
|
-
|
60
|
-
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
# Build the HTTP connection.
|
111
|
+
def http
|
112
|
+
connection = Net::HTTP.new(uri.host, uri.port)
|
113
|
+
connection.verify_mode = OpenSSL::SSL::VERIFY_NONE if connection.use_ssl?
|
114
|
+
connection
|
115
|
+
end
|
116
|
+
|
117
|
+
# Build the HTTP Request.
|
118
|
+
def request
|
119
|
+
req = request_preparation
|
120
|
+
|
121
|
+
req.body = with if (with && req.request_body_permitted?)
|
122
|
+
if (credentials)
|
123
|
+
if (credentials.is_a?(OAuth::AccessToken))
|
124
|
+
credentials.sign!(req)
|
125
|
+
else
|
126
|
+
req.basic_auth(credentials[:username], credentials[:password])
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
if headers
|
131
|
+
headers.each_pair do |key, value|
|
132
|
+
req[key] = value
|
61
133
|
end
|
62
|
-
prepare
|
63
134
|
end
|
135
|
+
|
136
|
+
req
|
137
|
+
end
|
138
|
+
|
139
|
+
# Prepare the HTTP Request.
|
140
|
+
# The Request has a lifecycle:
|
141
|
+
# Prepare with `request_preparation`
|
142
|
+
# Build with `request`
|
143
|
+
# Fire with `perform`
|
144
|
+
def request_preparation
|
145
|
+
HTTPVerb.new(via).request_class.new(uri.request_uri)
|
146
|
+
end
|
64
147
|
|
65
148
|
end
|
66
149
|
end
|