weary 0.7.2 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -1
- data/.rspec +2 -0
- data/.travis.yml +10 -0
- data/Gemfile +11 -8
- data/Gemfile.lock +49 -53
- data/LICENSE +1 -1
- data/README.md +134 -208
- data/Rakefile +6 -47
- data/lib/weary.rb +4 -66
- data/lib/weary/adapter.rb +23 -0
- data/lib/weary/adapters/net_http.rb +68 -0
- data/lib/weary/client.rb +243 -0
- data/lib/weary/deferred.rb +35 -0
- data/lib/weary/env.rb +32 -0
- data/lib/weary/middleware.rb +9 -0
- data/lib/weary/middleware/basic_auth.rb +17 -0
- data/lib/weary/middleware/content_type.rb +28 -0
- data/lib/weary/middleware/oauth.rb +31 -0
- data/lib/weary/request.rb +137 -124
- data/lib/weary/resource.rb +152 -128
- data/lib/weary/response.rb +48 -99
- data/lib/weary/route.rb +53 -0
- data/lib/weary/version.rb +3 -0
- data/spec/spec_helper.rb +4 -56
- data/spec/support/shared_examples_for_a_rack_app.rb +70 -0
- data/spec/support/shared_examples_for_a_rack_env.rb +14 -0
- data/spec/support/shared_examples_for_a_uri.rb +9 -0
- data/spec/weary/adapter_spec.rb +26 -0
- data/spec/weary/adapters/nethttp_spec.rb +88 -0
- data/spec/weary/client_spec.rb +258 -0
- data/spec/weary/deferred_spec.rb +35 -0
- data/spec/weary/env_spec.rb +12 -0
- data/spec/weary/middleware/basic_auth_spec.rb +23 -0
- data/spec/weary/middleware/content_type_spec.rb +34 -0
- data/spec/weary/middleware/oauth_spec.rb +27 -0
- data/spec/weary/request_spec.rb +227 -315
- data/spec/weary/resource_spec.rb +233 -233
- data/spec/weary/response_spec.rb +82 -159
- data/spec/weary/route_spec.rb +72 -0
- data/spec/weary_spec.rb +3 -56
- data/weary.gemspec +16 -79
- metadata +138 -98
- data/VERSION +0 -1
- data/examples/batch.rb +0 -20
- data/examples/repo.rb +0 -16
- data/examples/status.rb +0 -26
- data/lib/weary/base.rb +0 -124
- data/lib/weary/batch.rb +0 -37
- data/lib/weary/exceptions.rb +0 -15
- data/lib/weary/httpverb.rb +0 -32
- data/spec/fixtures/github.yml +0 -11
- data/spec/fixtures/twitter.xml +0 -763
- data/spec/fixtures/vimeo.json +0 -1
- data/spec/weary/base_spec.rb +0 -320
- data/spec/weary/batch_spec.rb +0 -71
- data/spec/weary/httpverb_spec.rb +0 -25
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
-
source
|
1
|
+
source "http://rubygems.org"
|
2
2
|
|
3
|
-
|
4
|
-
gem 'oauth', '>= 0.3.5'
|
3
|
+
gemspec
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
gem "rake", "~> 0.9.2"
|
6
|
+
|
7
|
+
group :doc do
|
8
|
+
gem "yard", "~> 0.7.5"
|
9
|
+
gem "yard-tomdoc", "~> 0.4.0"
|
10
|
+
end
|
11
|
+
|
12
|
+
platforms :jruby do
|
13
|
+
gem "jruby-openssl"
|
11
14
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,53 +1,49 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
-
|
26
|
-
|
27
|
-
|
28
|
-
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
hash: 840ef225827ef421653168c75a110d1a0a2e39a9
|
51
|
-
sources:
|
52
|
-
- Rubygems:
|
53
|
-
uri: http://gemcutter.org
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
weary (1.0.0.rc1)
|
5
|
+
addressable (~> 2.2.6)
|
6
|
+
multi_json (~> 1.1.0)
|
7
|
+
promise (~> 0.3.0)
|
8
|
+
rack (~> 1.4.0)
|
9
|
+
simple_oauth (~> 0.1.5)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: http://rubygems.org/
|
13
|
+
specs:
|
14
|
+
addressable (2.2.6)
|
15
|
+
crack (0.3.1)
|
16
|
+
diff-lcs (1.1.3)
|
17
|
+
multi_json (1.1.0)
|
18
|
+
promise (0.3.0)
|
19
|
+
rack (1.4.1)
|
20
|
+
rake (0.9.2.2)
|
21
|
+
rspec (2.8.0)
|
22
|
+
rspec-core (~> 2.8.0)
|
23
|
+
rspec-expectations (~> 2.8.0)
|
24
|
+
rspec-mocks (~> 2.8.0)
|
25
|
+
rspec-core (2.8.0)
|
26
|
+
rspec-expectations (2.8.0)
|
27
|
+
diff-lcs (~> 1.1.2)
|
28
|
+
rspec-mocks (2.8.0)
|
29
|
+
simple_oauth (0.1.5)
|
30
|
+
tomparse (0.2.0)
|
31
|
+
webmock (1.7.10)
|
32
|
+
addressable (~> 2.2, > 2.2.5)
|
33
|
+
crack (>= 0.1.7)
|
34
|
+
yard (0.7.5)
|
35
|
+
yard-tomdoc (0.4.0)
|
36
|
+
tomparse
|
37
|
+
yard
|
38
|
+
|
39
|
+
PLATFORMS
|
40
|
+
ruby
|
41
|
+
|
42
|
+
DEPENDENCIES
|
43
|
+
jruby-openssl
|
44
|
+
rake (~> 0.9.2)
|
45
|
+
rspec (~> 2.8.0)
|
46
|
+
weary!
|
47
|
+
webmock (~> 1.7.10)
|
48
|
+
yard (~> 0.7.5)
|
49
|
+
yard-tomdoc (~> 0.4.0)
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,218 +1,144 @@
|
|
1
1
|
# Weary
|
2
2
|
|
3
|
-
|
3
|
+
_Weary is a framework and DSL for building clients for (preferably RESTful) web service APIs._
|
4
4
|
|
5
|
-
|
5
|
+
At its most minimal, Weary is simply some nice syntactic sugar around Net/HTTP.
|
6
6
|
|
7
|
-
|
8
|
-
+ Parse XML and JSON with the [Crack](http://github.com/jnunemaker/crack) library.
|
9
|
-
+ Authentication with Basic Authentication and [OAuth](http://oauth.net/).
|
10
|
-
+ Asynchronous, multi-threaded requests.
|
7
|
+
If you dig a bit deeper, it's a suite of tools built around the [Rack](http://rack.rubyforge.org/) ecosystem. As you build a client, remember that just about every class in Weary is a piece of Rack middleware or a Rack application underneath the covers.
|
11
8
|
|
12
|
-
|
9
|
+
It features:
|
13
10
|
|
14
|
-
|
11
|
+
* Full Rack integration:
|
15
12
|
|
16
|
-
|
17
|
-
+ [OAuth](http://github.com/mojodna/oauth) >= 0.3.5
|
13
|
+
There are points in the stack to hook in Rack middleware and just about every class in Weary is a Rack application in its own right.
|
18
14
|
|
19
|
-
|
15
|
+
* Asynchronous:
|
16
|
+
|
17
|
+
`Weary::Request#perform`, the thing that performs the request, returns a [future](http://en.wikipedia.org/wiki/Futures_and_promises) and only blocks when accessed.
|
18
|
+
|
19
|
+
It takes its inspiration from [HTTParty](https://github.com/jnunemaker/httparty) and [Faraday](https://github.com/technoweenie/faraday).
|
20
20
|
|
21
|
-
gem install weary
|
22
|
-
|
23
|
-
If you're interested in doing development on Weary, clone the repository and run `bundle install` to get the development dependencies.
|
24
|
-
|
25
21
|
## Quick Start
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
That will build the Get request to fetch the YAML info about this repository.
|
150
|
-
|
151
|
-
Pass a block to `Weary.get` to dive further into the Request:
|
152
|
-
|
153
|
-
Weary.get "http://twitter.com/statuses/user_timeline" do |req|
|
154
|
-
req.follows = false
|
155
|
-
req.with = {:id => 'markwunsch'}
|
156
|
-
req.credentials = {:username => 'markwunsch', :password => 'secret'}
|
157
|
-
req.headers = {"User-Agent" => Weary::UserAgents["Safari 4.0.2 - Mac"]}
|
158
|
-
end
|
159
|
-
|
160
|
-
## Request Callbacks
|
161
|
-
|
162
|
-
A `Weary::Request` has a couple of callbacks you can do:
|
163
|
-
|
164
|
-
status = Weary.get("http://twitter.com/statuses/user_timeline") do |r|
|
165
|
-
r.with = {:id => 'markwunsch'}
|
166
|
-
end
|
167
|
-
|
168
|
-
status.before_send do |request|
|
169
|
-
puts "Sending a request to #{request.uri}"
|
170
|
-
end
|
171
|
-
|
172
|
-
status.on_complete do |response|
|
173
|
-
if response.success?
|
174
|
-
puts response.body
|
175
|
-
else
|
176
|
-
puts "Something went wrong: #{response.code}: #{response.message}"
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
`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.
|
181
|
-
|
182
|
-
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:
|
183
|
-
|
184
|
-
status.perform do |response|
|
185
|
-
puts "Request to #{response.url}, complete. Got a #{response.code}."
|
186
|
-
end
|
187
|
-
|
188
|
-
## Multiple Asynchronous Requests with Batch
|
189
|
-
|
190
|
-
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.
|
191
|
-
|
192
|
-
Weary::Batch allows you to make a group of `perform!` requests, firing at will. It takes a group of Requests.
|
193
|
-
|
194
|
-
# see examples/batch.rb
|
195
|
-
resources = %w[http://twitter.com http://github.com http://vimeo.com http://tumblr.com]
|
196
|
-
requests = []
|
197
|
-
|
198
|
-
## build the group of requests:
|
199
|
-
resources.each do |url|
|
200
|
-
requests << Weary.get(url) do |req|
|
201
|
-
req.on_complete {|res| puts "Hello from #{res.url}"}
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
## And fire them off:
|
206
|
-
Weary.batch(requests).perform
|
207
|
-
|
208
|
-
Batch has callbacks, just like the Request:
|
209
|
-
|
210
|
-
Weary.batch(requests).perform do
|
211
|
-
puts 'All done.'
|
212
|
-
end
|
213
|
-
|
214
|
-
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`.
|
215
|
-
|
216
|
-
## And more...
|
217
|
-
|
218
|
-
There's more to discover in the Wiki.
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
# http://developer.github.com/v3/repos/
|
25
|
+
class GithubRepo < Weary::Client
|
26
|
+
domain "https://api.github.com"
|
27
|
+
|
28
|
+
use Rack::Lint
|
29
|
+
|
30
|
+
get :list_user_repos, "/users/{user}/repos" do |resource|
|
31
|
+
resource.optional :type
|
32
|
+
end
|
33
|
+
|
34
|
+
get :get, "/repos/{user}/{repo}"
|
35
|
+
end
|
36
|
+
|
37
|
+
client = GithubRepo.new
|
38
|
+
client.list_user_repos(:user => "mwunsch").perform do |response|
|
39
|
+
puts response.body if response.success?
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
This is a basic example of a client you will build using the Weary framework. If you're coming from a previous version of Weary, you would have created a subclass of `Weary::Base`. That's one of the many changes in the **big rewrite**.
|
44
|
+
|
45
|
+
### Weary::Client
|
46
|
+
|
47
|
+
Inherit from `Weary::Client` for a set of class methods that craft "Resources" (more on that later).
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
MyClass < Weary::Client
|
51
|
+
get :resource, "http://host.com/path/to/resource" do |resource|
|
52
|
+
resource.optional :optional_parameter
|
53
|
+
end
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
The DSL provides methods for all of the HTTP verbs (See `Weary::Client::REQUEST_METHODS`). When you instantiate this class, the object will have an instance method named "resource" that will return a `Weary::Request` object set up to perform a "GET" request on "http://host.com/path/to/resource".
|
58
|
+
|
59
|
+
You can pass a block these methods for access to the `Weary::Resource`.
|
60
|
+
|
61
|
+
Further methods in the DSL include:
|
62
|
+
|
63
|
+
domain - This will be prepended to every path when resources are defined
|
64
|
+
(Particularly useful when using Client's Rack integration, discussed below).
|
65
|
+
optional - See Resource section below.
|
66
|
+
required - See Resource section below.
|
67
|
+
defaults - See Resource section below.
|
68
|
+
headers - See Resource section below.
|
69
|
+
use - A Rack::Middleware to place in the Request stack.
|
70
|
+
(See Rack integration further down)
|
71
|
+
|
72
|
+
|
73
|
+
#### Weary::Resource
|
74
|
+
|
75
|
+
The resource is a building block used in `Client` to describe the requirements of a request.
|
76
|
+
|
77
|
+
optional - A group of keys for parameters that the request expects.
|
78
|
+
required - Keys that the request needs in order to be performed.
|
79
|
+
defaults - Default parameters to be sent in every request.
|
80
|
+
headers - Headers to send in the request.
|
81
|
+
user_agent - A convenience method to set the User Agent header.
|
82
|
+
basic_auth! - Prepare the request to accept a username and password for basic authentication.
|
83
|
+
oauth! - Prepare the request to accept the consumer key and access token in the request.
|
84
|
+
|
85
|
+
Finally, the `request` method of the Resource takes a set of parameters to verify that requirements are met and returns a `Weary::Request` object. It should all look something like this once all is said and done.
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
# https://dev.twitter.com/docs/api/1/post/statuses/update
|
89
|
+
post :update, "http://api.twitter.com/1/statuses/update.json" do |resource|
|
90
|
+
resource.required :status
|
91
|
+
resource.optional :in_reply_to_status_id, :lat, :long, :place_id,
|
92
|
+
:display_coordinates, :trim_user, :include_entities
|
93
|
+
resource.oauth!
|
94
|
+
end
|
95
|
+
|
96
|
+
# After instantiating the client:
|
97
|
+
# (This calls the "update" resource's `request` method)
|
98
|
+
client.update :status => "I'm tweeting from Weary",
|
99
|
+
:consumer_key => "an_oauth_consumer_key",
|
100
|
+
:token => "my_oauth_access_token"
|
101
|
+
|
102
|
+
```
|
103
|
+
|
104
|
+
If a `required` parameter is missing, a `Weary::Resource::UnmetRequirementsError` exception is raised.
|
105
|
+
|
106
|
+
URL's for these methods can also be dynamic. If we alter the above example:
|
107
|
+
|
108
|
+
post :update, "http://api.twitter.com/1/statuses/update.{format}" do |resource|
|
109
|
+
|
110
|
+
Then a key `:format` will be expected to be passed with the other parameters.
|
111
|
+
|
112
|
+
The method that the Client defines (in the above example, the `client.update` method), can take an optional block that allows you to manipulate the underlying `Weary::Request` object.
|
113
|
+
|
114
|
+
### Weary::Request
|
115
|
+
|
116
|
+
No matter how you get there, you'll end up with a Weary::Request object. Call the `perform` method to actually make the request and get back a `Weary::Response`. That's not entirely true `Weary::Request#perform` is asynchronous and non-blocking. It returns a future and will only block once you call a method on the response. You can optionally pass a block that's executed once the response has returned.
|
117
|
+
|
118
|
+
By default, the request is performed through [Net::HTTP](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/Net/HTTP.html). This is done through `Weary::Adapter::NetHttp`. A `Weary::Adapter` is just a special kind of Rack application. `Request#adapter` allows you to hook up your own.
|
119
|
+
|
120
|
+
## Rack
|
121
|
+
|
122
|
+
To maximize the utility of Weary, it's important to remember that driving everything is Rack. Almost every class is built to provide a Rack interface.
|
123
|
+
|
124
|
+
Every class that inherits from `Weary::Client` is a Rack application.
|
125
|
+
|
126
|
+
A `Weary::Request` is a Rack application. When you call `Request#call` it creates its own special Rack environment. In order to preserve your Rack middleware, you can add your middleware to the stack using `Request#use`.
|
127
|
+
|
128
|
+
When using `Weary::Client` the `use` method will add the passed middleware to every Request stack.
|
129
|
+
|
130
|
+
Authentication, by default is done by either `Weary::Middleware::BasicAuth` or `Weary::Middleware::OAuth`. Both are just Rack middleware, and can be used in any Rack stack.
|
131
|
+
|
132
|
+
The point is, **it's just Rack**.
|
133
|
+
|
134
|
+
## Release Candidate
|
135
|
+
|
136
|
+
At this point, I need _your_ help to further Weary along. I'd love to see more examples that utilize the Rackness of Weary: using Devise, Warden, or mounted in a Rails application.
|
137
|
+
|
138
|
+
## Examples
|
139
|
+
|
140
|
+
[**Gilt**](https://github.com/mwunsch/gilt) is a Ruby client to the [Gilt public API](https://dev.gilt.com/). Notice how much of the code is dedicated to the Gilt domain model, and very little to actually interacting with the web service. That's the idea.
|
141
|
+
|
142
|
+
## Copyright
|
143
|
+
|
144
|
+
Copyright (c) 2009 - 2012 Mark Wunsch. Licensed under the [MIT License](http://opensource.org/licenses/mit-license.php).
|