weary 0.6.0 → 0.7.0
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/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
|