weary 0.4.3 → 0.5.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 +29 -4
- data/Rakefile +5 -0
- data/VERSION +1 -1
- data/lib/weary.rb +41 -0
- data/lib/weary/request.rb +3 -0
- data/lib/weary/resource.rb +31 -4
- data/lib/weary/response.rb +7 -1
- data/spec/weary/request_spec.rb +8 -0
- data/spec/weary/resource_spec.rb +27 -0
- data/spec/weary_spec.rb +33 -0
- data/weary.gemspec +2 -2
- metadata +2 -2
data/README.md
CHANGED
@@ -8,14 +8,18 @@ The things it do:
|
|
8
8
|
|
9
9
|
+ Quickly build an interface to your favorite REST API.
|
10
10
|
+ Parse XML and JSON with the [Crack](http://github.com/jnunemaker/crack) library.
|
11
|
+
+ Authenticate, basically, with Basic Authentication.
|
12
|
+
+ Consume with [OAuth](http://oauth.net/)
|
11
13
|
|
12
14
|
Browse the documentation here: [http://rdoc.info/projects/mwunsch/weary](http://rdoc.info/projects/mwunsch/weary)
|
15
|
+
Peruse the [Wiki](http://wiki.github.com/mwunsch/weary) to discover libraries built with Weary and a more thorough review of the API.
|
13
16
|
|
14
17
|
## Requirements
|
15
18
|
|
16
|
-
+ Crack >= 0.1.2
|
17
|
-
+ Nokogiri >= 1.3.1 (if you want to use the #search method)
|
18
|
-
+
|
19
|
+
+ [Crack](http://github.com/jnunemaker/crack) >= 0.1.2
|
20
|
+
+ [Nokogiri](http://github.com/tenderlove/nokogiri) >= 1.3.1 (if you want to use the #search method)
|
21
|
+
+ [OAuth](http://github.com/mojodna/oauth) >= 0.3.5 (if you want to use OAuth)
|
22
|
+
+ [RSpec](http://rspec.info/) (for running the tests)
|
19
23
|
|
20
24
|
## Installation
|
21
25
|
|
@@ -66,6 +70,8 @@ Besides the name of the resource, you can also give `declare_resource` a block l
|
|
66
70
|
r.requires = [:id, :bar] # an array of params that the resource requires to be in the query/body
|
67
71
|
r.with = [:blah] # an array of params that you can optionally send to the resource
|
68
72
|
r.authenticates = false # does the method require basic authentication? defaults to false
|
73
|
+
r.oauth = false # does this resource use OAuth to authorize you? it's boolean
|
74
|
+
r.access_token = nil # if you're using OAuth, you should provide the user's access token.
|
69
75
|
r.follows = false # if this is set to false, the formed request will not follow redirects.
|
70
76
|
r.headers = {'Accept' => 'text/html'} # send custom headers. defaults to nil.
|
71
77
|
end
|
@@ -116,4 +122,23 @@ There are many ways to form URLs in Weary. You can define URLs for the entire cl
|
|
116
122
|
The string `<domain><resource>.<format>` helps define a simple pattern for creating URLs. These will be filled in by your resource declaration. The above `get` declaration creates a url that looks like: *http://foo.bar/show_users.xml*
|
117
123
|
|
118
124
|
If you use the `<domain>` flag but don't define a domain, an exception will be raised.
|
119
|
-
|
125
|
+
|
126
|
+
### Weary DSL
|
127
|
+
|
128
|
+
You can create some defaults for all of our resources easily:
|
129
|
+
|
130
|
+
class Foo
|
131
|
+
extend Weary
|
132
|
+
|
133
|
+
domain "http://foo.bar/"
|
134
|
+
url "<domain><resource>.<format>"
|
135
|
+
format :xml
|
136
|
+
headers {'Accept' => 'text/html'} # set headers
|
137
|
+
authenticates "basic_username","basic_password" # basic authentication
|
138
|
+
with [:login, :token] # params that should be sent with every request
|
139
|
+
oauth OAuth::AccessToken.new(consumer, "token", "secret") # an access token for OAuth
|
140
|
+
|
141
|
+
post "update" # uses the defaults defined above!
|
142
|
+
end
|
143
|
+
|
144
|
+
There's more to discover in the Wiki.
|
data/Rakefile
CHANGED
@@ -54,6 +54,11 @@ rescue LoadError
|
|
54
54
|
puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
|
55
55
|
end
|
56
56
|
|
57
|
+
desc "Open an irb session preloaded with this library"
|
58
|
+
task :console do
|
59
|
+
sh "irb -rubygems -I lib -r weary.rb"
|
60
|
+
end
|
61
|
+
|
57
62
|
Spec::Rake::SpecTask.new do |t|
|
58
63
|
t.spec_files = FileList['spec/**/*_spec.rb']
|
59
64
|
t.spec_opts = ['--color','--format nested']
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/lib/weary.rb
CHANGED
@@ -8,8 +8,10 @@ require 'rubygems'
|
|
8
8
|
require 'crack'
|
9
9
|
|
10
10
|
gem 'nokogiri'
|
11
|
+
gem 'oauth'
|
11
12
|
autoload :Yaml, 'yaml'
|
12
13
|
autoload :Nokogiri, 'nokogiri'
|
14
|
+
autoload :OAuth, 'oauth'
|
13
15
|
|
14
16
|
require 'weary/request'
|
15
17
|
require 'weary/response'
|
@@ -90,6 +92,14 @@ module Weary
|
|
90
92
|
@headers = headers
|
91
93
|
end
|
92
94
|
alias set_headers headers
|
95
|
+
|
96
|
+
# Set the Access Token for OAuth. This must be an OAuth::AccessToken object.
|
97
|
+
# See http://github.com/mojodna/oauth/ to learn how to create Tokens
|
98
|
+
# Setting this will make resources use OAuth and this token by default.
|
99
|
+
def oauth(token)
|
100
|
+
raise ArgumentError, "Token needs to be an OAuth::AccessToken object" unless token.is_a?(OAuth::AccessToken)
|
101
|
+
@oauth = token
|
102
|
+
end
|
93
103
|
|
94
104
|
# Declare a resource. Use it with a block to setup the resource
|
95
105
|
#
|
@@ -98,10 +108,13 @@ module Weary
|
|
98
108
|
# [<tt>with</tt>] An array of parameters that will be passed to the body or query of the request. If you pass a hash, it will define default <tt>values</tt> for params <tt>keys</tt>
|
99
109
|
# [<tt>requires</tt>] Array of members of <tt>:with</tt> that are required by the resource.
|
100
110
|
# [<tt>authenticates</tt>] Boolean value; does the resource require authentication?
|
111
|
+
# [<tt>oauth</tt>] Boolean value; does the resource use OAuth?
|
112
|
+
# [<tt>access_token</tt>] Provide the Token for OAuth. Must be an OAuth::AccessToken object.
|
101
113
|
# [<tt>url</tt>] The url of the resource. You can use the same flags as #construct_url
|
102
114
|
# [<tt>format</tt>] The format you would like to request. Defaults to json
|
103
115
|
# [<tt>follows</tt>] Boolean; Does this follow redirects? Defaults to true
|
104
116
|
# [<tt>domain</tt>] Sets the domain you would like this individual resource to be on (if you include the domain flag in <tt>url</tt>)
|
117
|
+
# [<tt>headers</tt>] Set headers for the HTTP Request
|
105
118
|
def declare(name)
|
106
119
|
resource = prepare_resource(name,:get)
|
107
120
|
yield resource if block_given?
|
@@ -141,6 +154,10 @@ module Weary
|
|
141
154
|
preparation.url = (@url_pattern || "<domain><resource>.<format>")
|
142
155
|
preparation.with = @always_with unless @always_with.nil?
|
143
156
|
preparation.headers = @headers unless (@headers.nil? || @headers.empty?)
|
157
|
+
if !@oauth.nil?
|
158
|
+
preparation.oauth = true
|
159
|
+
preparation.access_token = @oauth
|
160
|
+
end
|
144
161
|
return preparation
|
145
162
|
end
|
146
163
|
|
@@ -148,6 +165,12 @@ module Weary
|
|
148
165
|
if resource.authenticates?
|
149
166
|
raise StandardError, "Can not authenticate unless username and password are defined" unless (@username && @password)
|
150
167
|
end
|
168
|
+
if resource.oauth?
|
169
|
+
if resource.access_token.nil?
|
170
|
+
raise StandardError, "Access Token is not provided" if @oauth.nil?
|
171
|
+
resource.access_token = @oauth
|
172
|
+
end
|
173
|
+
end
|
151
174
|
@resources ||= []
|
152
175
|
@resources << resource.to_hash
|
153
176
|
craft_methods(resource)
|
@@ -214,6 +237,24 @@ module Weary
|
|
214
237
|
if resource.authenticates?
|
215
238
|
code << %Q{options[:basic_auth] = {:username => "#{@username}", :password => "#{@password}"} \n}
|
216
239
|
end
|
240
|
+
if resource.oauth?
|
241
|
+
consumer_options = ""
|
242
|
+
resource.access_token.consumer.options.each_pair {|k,v|
|
243
|
+
if k.is_a?(Symbol)
|
244
|
+
k_string = ":#{k}"
|
245
|
+
else
|
246
|
+
k_string = "'#{k}'"
|
247
|
+
end
|
248
|
+
if v.is_a?(Symbol)
|
249
|
+
v_string = ":#{v}"
|
250
|
+
else
|
251
|
+
v_string = "'#{v}'"
|
252
|
+
end
|
253
|
+
consumer_options << "#{k_string} => #{v_string},"
|
254
|
+
}
|
255
|
+
code << %Q{ oauth_consumer = OAuth::Consumer.new("#{resource.access_token.consumer.key}","#{resource.access_token.consumer.secret}",#{consumer_options.chop}) \n}
|
256
|
+
code << %Q{ options[:oauth] = OAuth::AccessToken.new(oauth_consumer, "#{resource.access_token.token}", "#{resource.access_token.secret}") \n}
|
257
|
+
end
|
217
258
|
unless resource.follows_redirects?
|
218
259
|
code << %Q{options[:no_follow] = true \n}
|
219
260
|
end
|
data/lib/weary/request.rb
CHANGED
data/lib/weary/resource.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Weary
|
2
2
|
class Resource
|
3
|
-
attr_accessor :name, :domain, :with, :requires, :via, :format, :url, :authenticates, :follows, :headers
|
3
|
+
attr_accessor :name, :domain, :with, :requires, :via, :format, :url, :authenticates, :follows, :headers, :oauth, :access_token
|
4
4
|
|
5
5
|
def initialize(name)
|
6
6
|
self.name = name
|
@@ -9,6 +9,7 @@ module Weary
|
|
9
9
|
self.follows = true
|
10
10
|
self.with = []
|
11
11
|
self.requires = []
|
12
|
+
self.oauth = false
|
12
13
|
end
|
13
14
|
|
14
15
|
def name=(resource_name)
|
@@ -82,14 +83,38 @@ module Weary
|
|
82
83
|
@url = pattern
|
83
84
|
end
|
84
85
|
|
85
|
-
def
|
86
|
-
if
|
86
|
+
def oauth=(bool)
|
87
|
+
@authenticates = false if bool
|
88
|
+
@oauth = if bool
|
89
|
+
true
|
90
|
+
else
|
91
|
+
false
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def authenticates=(bool)
|
96
|
+
@oauth = false if bool
|
97
|
+
@authenticates = if bool
|
87
98
|
true
|
88
99
|
else
|
89
100
|
false
|
90
101
|
end
|
91
102
|
end
|
92
103
|
|
104
|
+
def authenticates?
|
105
|
+
@authenticates
|
106
|
+
end
|
107
|
+
|
108
|
+
def oauth?
|
109
|
+
@oauth
|
110
|
+
end
|
111
|
+
|
112
|
+
def access_token=(token)
|
113
|
+
raise ArgumentError, "Token needs to be an OAuth::AccessToken object" unless token.is_a?(OAuth::AccessToken)
|
114
|
+
@oauth = true
|
115
|
+
@access_token = token
|
116
|
+
end
|
117
|
+
|
93
118
|
def follows_redirects?
|
94
119
|
if @follows
|
95
120
|
true
|
@@ -107,7 +132,9 @@ module Weary
|
|
107
132
|
:format => @format,
|
108
133
|
:url => @url,
|
109
134
|
:domain => @domain,
|
110
|
-
:headers => @headers
|
135
|
+
:headers => @headers,
|
136
|
+
:oauth => oauth?,
|
137
|
+
:access_token => @access_token}}
|
111
138
|
end
|
112
139
|
|
113
140
|
end
|
data/lib/weary/response.rb
CHANGED
@@ -17,14 +17,17 @@ module Weary
|
|
17
17
|
self.format = http_response.content_type
|
18
18
|
end
|
19
19
|
|
20
|
+
# Is this an HTTP redirect?
|
20
21
|
def redirected?
|
21
22
|
@raw.is_a?(Net::HTTPRedirection)
|
22
23
|
end
|
23
24
|
|
25
|
+
# Was this Request successful?
|
24
26
|
def success?
|
25
27
|
(200..299).include?(@code)
|
26
28
|
end
|
27
29
|
|
30
|
+
# Returns a symbol corresponding to the Response's Content Type
|
28
31
|
def format=(type)
|
29
32
|
@format = case type
|
30
33
|
when *ContentTypes[:json]
|
@@ -42,6 +45,7 @@ module Weary
|
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
48
|
+
# Follow the Redirect
|
45
49
|
def follow_redirect
|
46
50
|
if redirected?
|
47
51
|
Request.new(@raw['location'], @method).perform
|
@@ -66,11 +70,13 @@ module Weary
|
|
66
70
|
end
|
67
71
|
end
|
68
72
|
|
73
|
+
# Same as parse[key]
|
69
74
|
def [](key)
|
70
75
|
parse[key]
|
71
76
|
end
|
72
77
|
|
73
|
-
# Search the body with a CSS/XPath selector with Nokogiri
|
78
|
+
# Search the body with a CSS/XPath selector with Nokogiri.
|
79
|
+
# If the document is not XMLish, fall back to #parse and ditch the selector.
|
74
80
|
def search(selector)
|
75
81
|
if @format == (:xml || :html)
|
76
82
|
doc = Nokogiri.parse(@body)
|
data/spec/weary/request_spec.rb
CHANGED
@@ -38,4 +38,12 @@ describe Weary::Request do
|
|
38
38
|
# not exactly kosher.
|
39
39
|
end
|
40
40
|
|
41
|
+
it "should prepare an oauth scheme if a token is provided" do
|
42
|
+
consumer = OAuth::Consumer.new("consumer_token","consumer_secret",{:site => 'http://foo.bar'})
|
43
|
+
token = OAuth::AccessToken.new(consumer, "token", "secret")
|
44
|
+
test = Weary::Request.new("http://foo.bar", :post, {:oauth => token})
|
45
|
+
test.send(:request).oauth_helper.options[:token].should == token
|
46
|
+
# seems a good a way as any to test if OAuth helpers have been added to the request
|
47
|
+
end
|
48
|
+
|
41
49
|
end
|
data/spec/weary/resource_spec.rb
CHANGED
@@ -35,6 +35,33 @@ describe Weary::Resource do
|
|
35
35
|
@test.authenticates?.should == false
|
36
36
|
end
|
37
37
|
|
38
|
+
it "oauth should be boolean" do
|
39
|
+
@test.oauth = "foobar"
|
40
|
+
@test.oauth?.should == true
|
41
|
+
@test.oauth = false
|
42
|
+
@test.oauth?.should == false
|
43
|
+
end
|
44
|
+
|
45
|
+
it "oauth should override basic authentication" do
|
46
|
+
@test.authenticates = true
|
47
|
+
@test.oauth = true
|
48
|
+
@test.authenticates?.should == false
|
49
|
+
@test.oauth?.should == true
|
50
|
+
end
|
51
|
+
|
52
|
+
it "providing an access token should set oauth to true" do
|
53
|
+
consumer = OAuth::Consumer.new("consumer_token","consumer_secret",{:site => 'http://foo.bar'})
|
54
|
+
token = OAuth::AccessToken.new(consumer, "token", "secret")
|
55
|
+
@test.oauth = false
|
56
|
+
@test.access_token = token
|
57
|
+
@test.oauth?.should == true
|
58
|
+
@test.access_token.should == token
|
59
|
+
end
|
60
|
+
|
61
|
+
it "an access token must contain an OAuth::AccessToken" do
|
62
|
+
lambda { @test.access_token = "foobar" }.should raise_error
|
63
|
+
end
|
64
|
+
|
38
65
|
it 'follows_redirects? should be boolean' do
|
39
66
|
@test.follows = "false"
|
40
67
|
@test.follows_redirects?.should == true
|
data/spec/weary_spec.rb
CHANGED
@@ -57,6 +57,39 @@ describe Weary do
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
describe "OAuth" do
|
61
|
+
before do
|
62
|
+
consumer = OAuth::Consumer.new("consumer_token","consumer_secret",{:site => 'http://foo.bar'})
|
63
|
+
@token = OAuth::AccessToken.new(consumer, "token", "secret")
|
64
|
+
@test.oauth @token
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should accept an OAuth Access Token" do
|
68
|
+
@test.instance_variable_get(:@oauth).should == @token
|
69
|
+
lambda { @test.oauth "foobar" }.should raise_error
|
70
|
+
end
|
71
|
+
it "should notify the Resource that this is using OAuth" do
|
72
|
+
@test.domain "http://foo.bar"
|
73
|
+
r = @test.declare("show")
|
74
|
+
r.oauth?.should == true
|
75
|
+
r.access_token.should == @token
|
76
|
+
end
|
77
|
+
it "should be able to handle tokens set within the resource intelligently" do
|
78
|
+
test = Class.new
|
79
|
+
test.instance_eval { extend Weary }
|
80
|
+
test.domain "http://foo.bar"
|
81
|
+
r = test.declare("show")
|
82
|
+
r.oauth?.should == false
|
83
|
+
r.access_token.should == nil
|
84
|
+
r.oauth = true
|
85
|
+
lambda { test.send(:form_resource, r) }.should raise_error
|
86
|
+
r.access_token = @token
|
87
|
+
r.access_token.should == @token
|
88
|
+
test.send(:form_resource, r)[:show][:oauth].should == true
|
89
|
+
test.send(:form_resource, r)[:show][:access_token].should == @token
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
60
93
|
describe "Set Headers" do
|
61
94
|
it "should be a hash of values to pass in the Request head" do
|
62
95
|
@test.on_domain "http://foo.bar"
|
data/weary.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{weary}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.5.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Mark Wunsch"]
|
9
|
-
s.date = %q{2009-
|
9
|
+
s.date = %q{2009-07-15}
|
10
10
|
s.description = %q{The Weary need REST: a tiny DSL that makes the consumption of RESTful web services simple.}
|
11
11
|
s.email = %q{mark@markwunsch.com}
|
12
12
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: weary
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Wunsch
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-07-15 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|