weary 0.7.2 → 1.0.0.rc1

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.
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).