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.
Files changed (56) hide show
  1. data/.gitignore +4 -1
  2. data/.rspec +2 -0
  3. data/.travis.yml +10 -0
  4. data/Gemfile +11 -8
  5. data/Gemfile.lock +49 -53
  6. data/LICENSE +1 -1
  7. data/README.md +134 -208
  8. data/Rakefile +6 -47
  9. data/lib/weary.rb +4 -66
  10. data/lib/weary/adapter.rb +23 -0
  11. data/lib/weary/adapters/net_http.rb +68 -0
  12. data/lib/weary/client.rb +243 -0
  13. data/lib/weary/deferred.rb +35 -0
  14. data/lib/weary/env.rb +32 -0
  15. data/lib/weary/middleware.rb +9 -0
  16. data/lib/weary/middleware/basic_auth.rb +17 -0
  17. data/lib/weary/middleware/content_type.rb +28 -0
  18. data/lib/weary/middleware/oauth.rb +31 -0
  19. data/lib/weary/request.rb +137 -124
  20. data/lib/weary/resource.rb +152 -128
  21. data/lib/weary/response.rb +48 -99
  22. data/lib/weary/route.rb +53 -0
  23. data/lib/weary/version.rb +3 -0
  24. data/spec/spec_helper.rb +4 -56
  25. data/spec/support/shared_examples_for_a_rack_app.rb +70 -0
  26. data/spec/support/shared_examples_for_a_rack_env.rb +14 -0
  27. data/spec/support/shared_examples_for_a_uri.rb +9 -0
  28. data/spec/weary/adapter_spec.rb +26 -0
  29. data/spec/weary/adapters/nethttp_spec.rb +88 -0
  30. data/spec/weary/client_spec.rb +258 -0
  31. data/spec/weary/deferred_spec.rb +35 -0
  32. data/spec/weary/env_spec.rb +12 -0
  33. data/spec/weary/middleware/basic_auth_spec.rb +23 -0
  34. data/spec/weary/middleware/content_type_spec.rb +34 -0
  35. data/spec/weary/middleware/oauth_spec.rb +27 -0
  36. data/spec/weary/request_spec.rb +227 -315
  37. data/spec/weary/resource_spec.rb +233 -233
  38. data/spec/weary/response_spec.rb +82 -159
  39. data/spec/weary/route_spec.rb +72 -0
  40. data/spec/weary_spec.rb +3 -56
  41. data/weary.gemspec +16 -79
  42. metadata +138 -98
  43. data/VERSION +0 -1
  44. data/examples/batch.rb +0 -20
  45. data/examples/repo.rb +0 -16
  46. data/examples/status.rb +0 -26
  47. data/lib/weary/base.rb +0 -124
  48. data/lib/weary/batch.rb +0 -37
  49. data/lib/weary/exceptions.rb +0 -15
  50. data/lib/weary/httpverb.rb +0 -32
  51. data/spec/fixtures/github.yml +0 -11
  52. data/spec/fixtures/twitter.xml +0 -763
  53. data/spec/fixtures/vimeo.json +0 -1
  54. data/spec/weary/base_spec.rb +0 -320
  55. data/spec/weary/batch_spec.rb +0 -71
  56. data/spec/weary/httpverb_spec.rb +0 -25
data/.gitignore CHANGED
@@ -1,3 +1,6 @@
1
+ .DS_Store
1
2
  pkg/
2
3
  doc/
3
- .bundle/
4
+ .bundle/
5
+ .yardoc/
6
+ .rbenv-version
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=documentation
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - jruby-18mode
7
+ - jruby-19mode
8
+ - rbx-18mode
9
+ - rbx-19mode
10
+ - ree
data/Gemfile CHANGED
@@ -1,11 +1,14 @@
1
- source :gemcutter
1
+ source "http://rubygems.org"
2
2
 
3
- gem 'crack', '>= 0.1.7'
4
- gem 'oauth', '>= 0.3.5'
3
+ gemspec
5
4
 
6
- group :test do
7
- gem 'rake'
8
- gem 'rspec'
9
- gem 'fakeweb'
10
- gem 'jeweler'
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
- dependencies:
3
- fakeweb:
4
- group:
5
- - :test
6
- version: ">= 0"
7
- rake:
8
- group:
9
- - :test
10
- version: ">= 0"
11
- oauth:
12
- group:
13
- - :default
14
- version: ">= 0.3.5"
15
- rspec:
16
- group:
17
- - :test
18
- version: ">= 0"
19
- crack:
20
- group:
21
- - :default
22
- version: ">= 0.1.7"
23
- jeweler:
24
- group:
25
- - :test
26
- version: ">= 0"
27
- specs:
28
- - json_pure:
29
- version: 1.2.2
30
- - git:
31
- version: 1.2.5
32
- - rubyforge:
33
- version: 2.0.4
34
- - rspec:
35
- version: 1.3.0
36
- - ruby-hmac:
37
- version: 0.4.0
38
- - crack:
39
- version: 0.1.7
40
- - oauth:
41
- version: 0.3.6
42
- - rake:
43
- version: 0.8.7
44
- - gemcutter:
45
- version: 0.4.1
46
- - jeweler:
47
- version: 1.4.0
48
- - fakeweb:
49
- version: 1.2.8
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
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009-2010 Mark Wunsch
1
+ Copyright (c) 2009-2012 Mark Wunsch
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,218 +1,144 @@
1
1
  # Weary
2
2
 
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.
3
+ _Weary is a framework and DSL for building clients for (preferably RESTful) web service APIs._
4
4
 
5
- What does it do:
5
+ At its most minimal, Weary is simply some nice syntactic sugar around Net/HTTP.
6
6
 
7
- + Quickly build an interface to your favorite REST API.
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
- [RDoc](http://rdoc.info/projects/mwunsch/weary) | [Gem](http://rubygems.org/gems/weary) | [Wiki](http://wiki.github.com/mwunsch/weary) | [Metrics](http://getcaliper.com/caliper/project?repo=git://github.com/mwunsch/weary.git)
9
+ It features:
13
10
 
14
- ## Requirements
11
+ * Full Rack integration:
15
12
 
16
- + [Crack](http://github.com/jnunemaker/crack) >= 0.1.7
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
- ## Installation
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
- # http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-users%C2%A0show
28
- class TwitterUser < Weary::Base
29
-
30
- domain "http://twitter.com/users/"
31
-
32
- get "show" do |resource|
33
- resource.with = [:id, :user_id, :screen_name]
34
- end
35
- end
36
-
37
- user = TwitterUser.new
38
- me = user.show(:id => "markwunsch").perform
39
- puts me["name"]
40
-
41
- Hey, that's me!
42
-
43
- ## The Base API/DSL
44
-
45
- Create a class that inherits from `Weary::Base` to give it methods to craft a resource request:
46
-
47
- class Foo < Weary::Base
48
-
49
- declare "foo" do |resource|
50
- resource.url = "http://path/to/foo"
51
- end
52
- end
53
-
54
- If you instantiate this class, you'll get an instance method named `foo` that crafts a GET request to "http://path/to/foo"
55
-
56
- Besides the name of the resource, you can also give `declare` a block like:
57
-
58
- declare "foo" do |r|
59
- r.url = "path/to/foo"
60
- r.via = :post # defaults to :get
61
- r.requires = [:id, :bar] # an array of params that the resource requires to be in the query/body
62
- r.with = [:blah] # an array of params that you can optionally send to the resource
63
- r.authenticates = false # does the method require authentication? defaults to false
64
- r.follows = false # if this is set to false, the formed request will not follow redirects.
65
- r.headers = {'Accept' => 'text/html'} # send custom headers. defaults to nil.
66
- end
67
-
68
- So this would form a method:
69
-
70
- x = Foo.new
71
- x.foo :id => "mwunsch", :bar => 123
72
-
73
- That method would return a `Weary::Request` object. Use the `perform` method and get a `Weary::Response` that you could parse and/or examine.
74
-
75
- ### Parsing the Body
76
-
77
- Once you make your request with the fancy method that Weary created for you, you can do stuff with what it returns...which could be a good reason you're using Weary in the first place. Let's look at the above example:
78
-
79
- x = Foo.new
80
- y = x.foo(:id => "mwunsch", :bar => 123).perform.parse
81
- y["foos"]["user"]
82
-
83
- Weary parses with Crack, but you're not beholden to it. You can get the raw Request body to have your way with:
84
-
85
- x = Foo.new
86
- y = x.foo(:id => "mwunsch", :bar => 123).perform
87
- Nokogiri.parse(y.body)
88
-
89
- *note: Weary used to have Nokogiri built in, using the `#search` method, but that was dropped.*
90
-
91
- ### Shortcuts
92
-
93
- Of course, you don't always have to use `declare`; that is a little too ambiguous. You can also use `get`, `post`, `delete`, etc. Those do the obvious.
94
-
95
- ### Forming URLs
96
-
97
- There are many ways to form URLs in Weary. You can define URLs for the entire class by typing:
98
-
99
- class Foo < Weary::Base
100
-
101
- domain "http://foo.bar/"
102
- format :xml
103
-
104
- get "show_users"
105
- end
106
-
107
- 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.
108
-
109
- ### Weary DSL
110
-
111
- You can create some defaults for all of our resources easily:
112
-
113
- class Foo < Weary::Base
114
-
115
- def initialize(username,password)
116
- self.credentials username,password #basic authentication
117
- self.defaults = {:user => username} #parameters that will be passed in every request
118
- end
119
-
120
- domain "http://foo.bar/"
121
- format :xml
122
- headers {'Accept' => 'text/html'} # set headers
123
-
124
- post "update" {|r| r.authenticates = true} # uses the defaults defined above!
125
- end
126
-
127
- Then you can do something like this:
128
-
129
- f = Foo.new('me','secretz')
130
- f.update
131
-
132
- 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.
133
-
134
- ## Weary Class Methods
135
-
136
- 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`:
137
-
138
- # See examples/repo.rb to see this in practice
139
- class Repository
140
-
141
- def show(user, repo)
142
- Weary.get "http://github.com/api/v2/yaml/repos/show/#{user}/#{repo}"
143
- end
144
-
145
- end
146
-
147
- Repository.new.show 'mwunsch', 'weary'
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).