weary 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +31 -36
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/examples/repo.rb +12 -15
- data/examples/status.rb +5 -4
- data/lib/weary.rb +35 -232
- data/lib/weary/base.rb +126 -0
- data/lib/weary/request.rb +4 -8
- data/lib/weary/resource.rb +92 -88
- data/lib/weary/response.rb +0 -11
- data/spec/spec_helper.rb +3 -2
- data/spec/weary/base_spec.rb +321 -0
- data/spec/weary/request_spec.rb +2 -0
- data/spec/weary/resource_spec.rb +230 -74
- data/spec/weary/response_spec.rb +7 -11
- data/spec/weary_spec.rb +0 -157
- data/weary.gemspec +11 -4
- metadata +15 -2
data/lib/weary/base.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
module Weary
|
2
|
+
class Base
|
3
|
+
@@resources = {}
|
4
|
+
|
5
|
+
attr_accessor :defaults
|
6
|
+
|
7
|
+
# Assign credentials to be used when authenticating to a Resource.
|
8
|
+
# Can be a username/password combo, or an OAuth::AccessToken
|
9
|
+
def credentials(username,password='')
|
10
|
+
if username.is_a?(OAuth::AccessToken)
|
11
|
+
@credentials = username
|
12
|
+
else
|
13
|
+
@credentials = {:username => username, :password => password}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Each Weary::Base object has its own set of Resources
|
18
|
+
def resources
|
19
|
+
@resources = Marshal.load(Marshal.dump(@@resources)) if !@resources
|
20
|
+
@resources
|
21
|
+
end
|
22
|
+
|
23
|
+
# Make changes to a Resource given and rebuild the Request method for this object
|
24
|
+
def modify_resource(name)
|
25
|
+
yield resources[name] if block_given?
|
26
|
+
rebuild_method(resources[name])
|
27
|
+
end
|
28
|
+
|
29
|
+
# Rebuild the Request Method for a given Resource. This only affects the current instance.
|
30
|
+
def rebuild_method(resource)
|
31
|
+
instance_eval %Q{
|
32
|
+
def #{resource.name}(params={})
|
33
|
+
resources[:#{resource.name}].build!(params, @defaults, @credentials)
|
34
|
+
end
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
class << self
|
39
|
+
|
40
|
+
# Getter for class-level resources
|
41
|
+
def resources
|
42
|
+
@@resources
|
43
|
+
end
|
44
|
+
|
45
|
+
# Declare a resource. Use it with a block to setup the resource
|
46
|
+
#
|
47
|
+
# Methods that are understood are:
|
48
|
+
# [<tt>via</tt>] Get, Post, etc. Defaults to a GET request
|
49
|
+
# [<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>
|
50
|
+
# [<tt>requires</tt>] Array of members of <tt>:with</tt> that are required by the resource.
|
51
|
+
# [<tt>authenticates</tt>] Boolean value; does the resource require authentication?
|
52
|
+
# [<tt>url</tt>] The url of the resource. You can use the same flags as #construct_url
|
53
|
+
# [<tt>follows</tt>] Boolean; Does this follow redirects? Defaults to true
|
54
|
+
# [<tt>headers</tt>] Set headers for the HTTP Request
|
55
|
+
def get(name,&block)
|
56
|
+
build_resource(name, :get, block)
|
57
|
+
end
|
58
|
+
alias declare get
|
59
|
+
|
60
|
+
# Declares a Resource to be requested via POST
|
61
|
+
def post(name,&block)
|
62
|
+
build_resource(name, :post, block)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Declares a Resource to be requested via PUT
|
66
|
+
def put(name,&block)
|
67
|
+
build_resource(name, :put, block)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Declares a Resource to be requested via DELETE
|
71
|
+
def delete(name,&block)
|
72
|
+
build_resource(name, :delete, block)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Set custom default Headers for your Request
|
76
|
+
def headers(headers)
|
77
|
+
@headers = headers
|
78
|
+
end
|
79
|
+
|
80
|
+
# Sets the domain to be used to build default url's
|
81
|
+
def domain(dom)
|
82
|
+
domain = URI.extract(dom)
|
83
|
+
raise ArgumentError, 'The domain must be a URL.' if domain.blank?
|
84
|
+
@domain = URI.parse(domain[0]).normalize.to_s
|
85
|
+
end
|
86
|
+
|
87
|
+
# Sets a default format, used to build default Resource url's
|
88
|
+
def format(format)
|
89
|
+
@format = format
|
90
|
+
end
|
91
|
+
|
92
|
+
# Prepare and store the Resource
|
93
|
+
def build_resource(name,verb,block=nil)
|
94
|
+
resource = prepare_resource(name,verb)
|
95
|
+
block.call(resource) if block
|
96
|
+
store_resource(resource)
|
97
|
+
build_method(resource)
|
98
|
+
resource
|
99
|
+
end
|
100
|
+
|
101
|
+
# Prepare a Resource with set defaults
|
102
|
+
def prepare_resource(name,via = :get)
|
103
|
+
preparation = Weary::Resource.new(name)
|
104
|
+
preparation.via = via
|
105
|
+
preparation.headers = @headers unless @headers.blank?
|
106
|
+
preparation.url = "#{@domain}#{preparation.name}." + (@format || :json).to_s if @domain
|
107
|
+
preparation
|
108
|
+
end
|
109
|
+
|
110
|
+
# Store the resource for future use
|
111
|
+
def store_resource(resource)
|
112
|
+
@@resources[resource.name.to_sym] = resource
|
113
|
+
resource
|
114
|
+
end
|
115
|
+
|
116
|
+
# Build a method to form a Request for the given Resource
|
117
|
+
def build_method(resource)
|
118
|
+
define_method resource.name.to_sym do |*args|
|
119
|
+
args.blank? ? params = {} : params = args[0]
|
120
|
+
resource.build!(params, @defaults, @credentials)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/weary/request.rb
CHANGED
@@ -30,15 +30,11 @@ module Weary
|
|
30
30
|
def perform
|
31
31
|
req = http.request(request)
|
32
32
|
response = Response.new(req, @http_verb)
|
33
|
-
|
34
|
-
if
|
35
|
-
|
36
|
-
else
|
37
|
-
response
|
38
|
-
end
|
39
|
-
else
|
40
|
-
response
|
33
|
+
if response.redirected?
|
34
|
+
return response if options[:no_follow]
|
35
|
+
response.follow_redirect
|
41
36
|
end
|
37
|
+
response
|
42
38
|
end
|
43
39
|
|
44
40
|
private
|
data/lib/weary/resource.rb
CHANGED
@@ -1,22 +1,21 @@
|
|
1
1
|
module Weary
|
2
2
|
class Resource
|
3
|
-
|
3
|
+
attr_reader :name, :via, :with, :requires, :url
|
4
|
+
attr_accessor :headers
|
4
5
|
|
5
6
|
def initialize(name)
|
6
7
|
self.name = name
|
7
8
|
self.via = :get
|
8
9
|
self.authenticates = false
|
9
10
|
self.follows = true
|
10
|
-
self.with = []
|
11
|
-
self.requires = []
|
12
|
-
self.oauth = false
|
13
11
|
end
|
14
12
|
|
13
|
+
# The name of the Resource. Will be a lowercase string, whitespace replaced with underscores.
|
15
14
|
def name=(resource_name)
|
16
|
-
|
17
|
-
@name = resource_name.downcase.strip.gsub(/\s/,'_')
|
15
|
+
@name = resource_name.to_s.downcase.strip.gsub(/\s/,'_')
|
18
16
|
end
|
19
17
|
|
18
|
+
# The HTTP Method used to fetch the Resource
|
20
19
|
def via=(http_verb)
|
21
20
|
verb = HTTPVerb.new(http_verb).normalize
|
22
21
|
@via = if Methods.include?(verb)
|
@@ -26,109 +25,114 @@ module Weary
|
|
26
25
|
end
|
27
26
|
end
|
28
27
|
|
29
|
-
|
30
|
-
type = type.downcase if type.is_a?(String)
|
31
|
-
@format = case type
|
32
|
-
when *ContentTypes[:json]
|
33
|
-
:json
|
34
|
-
when *ContentTypes[:xml]
|
35
|
-
:xml
|
36
|
-
when *ContentTypes[:html]
|
37
|
-
:html
|
38
|
-
when *ContentTypes[:yaml]
|
39
|
-
:yaml
|
40
|
-
when *ContentTypes[:plain]
|
41
|
-
:plain
|
42
|
-
else
|
43
|
-
raise ArgumentError, "#{type} is not a recognized format."
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
28
|
+
# Optional params. Should be an array. Merges with requires if that is set.
|
47
29
|
def with=(params)
|
48
|
-
|
49
|
-
|
50
|
-
@with = params
|
51
|
-
else
|
52
|
-
if @requires.nil?
|
53
|
-
@with = params.collect {|x| x.to_sym}
|
54
|
-
else
|
55
|
-
@with = params.collect {|x| x.to_sym} | @requires
|
56
|
-
end
|
57
|
-
end
|
30
|
+
@with = [params].flatten.collect {|x| x.to_sym}
|
31
|
+
@with = (requires | @with) if requires
|
58
32
|
end
|
59
33
|
|
34
|
+
# Required params. Should be an array. Merges with `with` or sets `with`.
|
60
35
|
def requires=(params)
|
61
|
-
|
62
|
-
|
63
|
-
@requires = params.collect {|x| x.to_sym}
|
64
|
-
else
|
65
|
-
@with = @with | params.collect {|x| x.to_sym}
|
66
|
-
@requires = params.collect {|x| x.to_sym}
|
67
|
-
end
|
36
|
+
@requires = [params].flatten.collect {|x| x.to_sym}
|
37
|
+
with ? @with = (with | @requires) : (@with = @requires)
|
68
38
|
end
|
69
39
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
pattern = pattern.gsub("<domain>", @domain)
|
74
|
-
end
|
75
|
-
pattern = pattern.gsub("<resource>", @name)
|
76
|
-
pattern = pattern.gsub("<format>", @format.to_s)
|
77
|
-
@url = pattern
|
40
|
+
# Sets whether the Resource requires authentication. Always sets to a boolean value.
|
41
|
+
def authenticates=(bool)
|
42
|
+
@authenticates = bool ? true : false
|
78
43
|
end
|
79
44
|
|
80
|
-
|
81
|
-
|
82
|
-
@
|
83
|
-
true
|
84
|
-
else
|
85
|
-
false
|
86
|
-
end
|
45
|
+
# Does the Resource require authentication?
|
46
|
+
def authenticates?
|
47
|
+
@authenticates
|
87
48
|
end
|
88
49
|
|
89
|
-
|
90
|
-
|
91
|
-
@
|
92
|
-
true
|
93
|
-
else
|
94
|
-
false
|
95
|
-
end
|
50
|
+
# Sets whether the Resource should follow redirection. Always sets to a boolean value.
|
51
|
+
def follows=(bool)
|
52
|
+
@follows = (bool ? true : false)
|
96
53
|
end
|
97
54
|
|
98
|
-
|
99
|
-
|
55
|
+
# Should the resource follow redirection?
|
56
|
+
def follows?
|
57
|
+
@follows
|
100
58
|
end
|
101
59
|
|
102
|
-
|
103
|
-
|
60
|
+
# Set the Resource's URL as a URI
|
61
|
+
def url=(uri)
|
62
|
+
@url = URI.parse(uri)
|
104
63
|
end
|
105
64
|
|
106
|
-
|
107
|
-
|
108
|
-
@
|
109
|
-
|
65
|
+
# A hash representation of the Resource
|
66
|
+
def to_hash
|
67
|
+
{@name.to_sym => { :via => via,
|
68
|
+
:with => with,
|
69
|
+
:requires => requires,
|
70
|
+
:follows => follows?,
|
71
|
+
:authenticates => authenticates?,
|
72
|
+
:url => url,
|
73
|
+
:headers => headers}}
|
74
|
+
end
|
75
|
+
|
76
|
+
# Take parameters, default params, and credentials and build a Request object for this Resource
|
77
|
+
def build!(params={}, defaults=nil, credentials=nil)
|
78
|
+
uri = @url
|
79
|
+
parameters = setup_parameters(params, defaults)
|
80
|
+
request_opts = setup_options(parameters, credentials)
|
81
|
+
uri.query = request_opts[:query].to_params if request_opts[:query]
|
82
|
+
Weary::Request.new(uri.normalize.to_s, @via, request_opts)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Setup the parameters to make the Request with
|
86
|
+
def setup_parameters(params={}, defaults=nil)
|
87
|
+
params = defaults ? defaults.merge(params) : params
|
88
|
+
find_missing_requirements(params)
|
89
|
+
remove_unnecessary_params(params)
|
110
90
|
end
|
111
91
|
|
112
|
-
|
113
|
-
|
114
|
-
|
92
|
+
# Search the given parameters to see if they are missing any required params
|
93
|
+
def find_missing_requirements(params)
|
94
|
+
if (@requires && !@requires.empty?)
|
95
|
+
missing_requirements = @requires - params.keys
|
96
|
+
raise ArgumentError, "This resource is missing required parameters: '#{missing_requirements.inspect}'" unless missing_requirements.empty?
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Remove params that have not been specified with #with
|
101
|
+
def remove_unnecessary_params(params)
|
102
|
+
params.delete_if {|k,v| !@with.include?(k) } if (@with && !@with.empty?)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Setup the options to be passed into the Request
|
106
|
+
def setup_options(params={}, credentials=nil)
|
107
|
+
options = {}
|
108
|
+
prepare_request_body(params, options)
|
109
|
+
setup_authentication(options, credentials)
|
110
|
+
options[:no_follow] = true if !follows?
|
111
|
+
options[:headers] = @headers if !@headers.blank?
|
112
|
+
options
|
113
|
+
end
|
114
|
+
|
115
|
+
# Prepare the Request query or body depending on the HTTP method
|
116
|
+
def prepare_request_body(params, options={})
|
117
|
+
if (@via == :post || @via == :put)
|
118
|
+
options[:body] = params unless params.blank?
|
115
119
|
else
|
116
|
-
|
120
|
+
options[:query] = params unless params.blank?
|
117
121
|
end
|
122
|
+
options
|
118
123
|
end
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
:access_token => @access_token}}
|
124
|
+
|
125
|
+
# Prepare authentication credentials for the Request
|
126
|
+
def setup_authentication(options, credentials=nil)
|
127
|
+
if authenticates?
|
128
|
+
raise ArgumentError, "This resource requires authentication and no credentials were given." if credentials.blank?
|
129
|
+
if credentials.is_a?(OAuth::AccessToken)
|
130
|
+
options[:oauth] = credentials
|
131
|
+
else
|
132
|
+
options[:basic_auth] = credentials
|
133
|
+
end
|
134
|
+
end
|
135
|
+
options
|
132
136
|
end
|
133
137
|
|
134
138
|
end
|
data/lib/weary/response.rb
CHANGED
@@ -75,17 +75,6 @@ module Weary
|
|
75
75
|
parse[key]
|
76
76
|
end
|
77
77
|
|
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.
|
80
|
-
def search(selector)
|
81
|
-
if @format == (:xml || :html)
|
82
|
-
doc = Nokogiri.parse(@body)
|
83
|
-
doc.search(selector)
|
84
|
-
else
|
85
|
-
parse
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
78
|
private
|
90
79
|
def handle_errors
|
91
80
|
case @code
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
|
1
3
|
require 'rubygems'
|
2
|
-
gem 'rspec'
|
3
4
|
require 'spec'
|
4
|
-
require
|
5
|
+
require 'weary'
|
5
6
|
|
6
7
|
def get_fixture(filename)
|
7
8
|
open(File.join(File.dirname(__FILE__), 'fixtures', "#{filename.to_s}")).read
|
@@ -0,0 +1,321 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe Weary::Base do
|
4
|
+
describe 'Class' do
|
5
|
+
|
6
|
+
describe 'Resource Defaults' do
|
7
|
+
before do
|
8
|
+
@headers = {"User-Agent" => Weary::UserAgents["Safari 4.0.2 - Mac"]}
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'sets default headers' do
|
12
|
+
test = Class.new(Weary::Base)
|
13
|
+
test.headers @headers
|
14
|
+
test.instance_variable_get(:@headers).should == @headers
|
15
|
+
end
|
16
|
+
|
17
|
+
it "sets a domain to be used in default url's" do
|
18
|
+
test = Class.new(Weary::Base)
|
19
|
+
test.domain 'http://github.com'
|
20
|
+
test.instance_variable_get(:@domain).should == 'http://github.com/'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'panics when a domain that is not a url is given' do
|
24
|
+
test = Class.new(Weary::Base)
|
25
|
+
lambda { test.domain 'foobar' }.should raise_error
|
26
|
+
end
|
27
|
+
|
28
|
+
it "sets a format to use in default url's" do
|
29
|
+
test = Class.new(Weary::Base)
|
30
|
+
test.format(:json)
|
31
|
+
test.instance_variable_get(:@format).should == :json
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'Resource Preparation' do
|
36
|
+
before do
|
37
|
+
@headers = {"User-Agent" => Weary::UserAgents["Safari 4.0.2 - Mac"]}
|
38
|
+
prepTest = Class.new(Weary::Base)
|
39
|
+
prepTest.headers @headers
|
40
|
+
prepTest.domain 'http://foobar.com'
|
41
|
+
prepTest.format :xml
|
42
|
+
@t = prepTest.prepare_resource("test",:get)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'prepares a Resource' do
|
46
|
+
@t.class.should == Weary::Resource
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'has a name' do
|
50
|
+
@t.name.should == "test"
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'has an http method' do
|
54
|
+
@t.via.should == :get
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'has headers' do
|
58
|
+
@t.headers.should == @headers
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'builds a default url if a domain is provided' do
|
62
|
+
@t.url.normalize.to_s.should == 'http://foobar.com/test.xml'
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'builds a default url with a json extension if no format is explicitly named' do
|
66
|
+
t = Class.new(Weary::Base)
|
67
|
+
t.domain 'http://foobar.com'
|
68
|
+
p = t.prepare_resource("test",:get)
|
69
|
+
p.url.normalize.to_s.should == 'http://foobar.com/test.json'
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'ignores the url if no domain is provided' do
|
73
|
+
t = Class.new(Weary::Base).prepare_resource("test",:get)
|
74
|
+
t.url.should == nil
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'ignores headers if no headers are defined' do
|
78
|
+
t = Class.new(Weary::Base).prepare_resource("test",:get)
|
79
|
+
t.headers.should == nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'Resource Storage' do
|
84
|
+
before do
|
85
|
+
@headers = {"User-Agent" => Weary::UserAgents["Safari 4.0.2 - Mac"]}
|
86
|
+
@restest = Class.new(Weary::Base)
|
87
|
+
@restest.headers @headers
|
88
|
+
@restest.domain 'http://foobar.com'
|
89
|
+
@r = @restest.prepare_resource("test",:get)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'has a store for resources' do
|
93
|
+
@restest.class_variable_defined?(:@@resources).should == true
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'stores the resource for future use' do
|
97
|
+
@restest.store_resource(@r).should == @r
|
98
|
+
@restest.resources.include?(:test).should == true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe 'Resource Construction' do
|
103
|
+
before do
|
104
|
+
@contest = Class.new(Weary::Base)
|
105
|
+
@contest.domain 'http://foobar.com'
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'prepares a resource to be used' do
|
109
|
+
r = @contest.build_resource "test", :post
|
110
|
+
r.name.should == "test"
|
111
|
+
r.via.should == :post
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'passes the resource into a block for further refinement' do
|
115
|
+
r = @contest.build_resource("test", :post, Proc.new {|res| res.via = :put })
|
116
|
+
r.name.should == "test"
|
117
|
+
r.via.should == :put
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'stores the resource' do
|
121
|
+
r = @contest.build_resource("test 2", :get)
|
122
|
+
@contest.resources.include?(:test_2).should == true
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'builds the method for the resource' do
|
126
|
+
r = @contest.build_resource("test 3", :get)
|
127
|
+
@contest.public_method_defined?(:test_3).should == true
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'Resource Declaration' do
|
132
|
+
before do
|
133
|
+
@dectest = Class.new(Weary::Base)
|
134
|
+
@dectest.domain 'http://foobar.com'
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'gets a resource' do
|
138
|
+
r = @dectest.get "get test"
|
139
|
+
r.via.should == :get
|
140
|
+
r.name.should == "get_test"
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'posts a resource' do
|
144
|
+
r = @dectest.post "post test"
|
145
|
+
r.via.should == :post
|
146
|
+
r.name.should == "post_test"
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'puts a resource' do
|
150
|
+
r = @dectest.put "put test"
|
151
|
+
r.via.should == :put
|
152
|
+
r.name.should == "put_test"
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'deletes a resource' do
|
156
|
+
r = @dectest.delete "del test"
|
157
|
+
r.via.should == :delete
|
158
|
+
r.name.should == "del_test"
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'declares a resource' do
|
162
|
+
r = @dectest.declare "generic test"
|
163
|
+
r.via.should == :get
|
164
|
+
r.name.should == "generic_test"
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'stores the resource' do
|
168
|
+
@dectest.get "storage test"
|
169
|
+
@dectest.resources.include?(:storage_test).should == true
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe 'Method Building' do
|
174
|
+
before do
|
175
|
+
@methtest = Class.new(Weary::Base)
|
176
|
+
@methtest.domain 'http://foobar.com'
|
177
|
+
|
178
|
+
r = @methtest.prepare_resource("method_test",:get)
|
179
|
+
@methtest.build_method(r)
|
180
|
+
|
181
|
+
a = @methtest.prepare_resource("authentication_test",:post)
|
182
|
+
a.authenticates = true
|
183
|
+
@methtest.build_method(a)
|
184
|
+
|
185
|
+
d = @methtest.prepare_resource("params_test",:post)
|
186
|
+
d.requires = :id
|
187
|
+
d.with = [:message, :user]
|
188
|
+
@methtest.build_method(d)
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'builds a method with the name of the resource' do
|
192
|
+
n = @methtest.new
|
193
|
+
n.respond_to?(:method_test).should == true
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'forms a Request according to the guidelines of the Resource' do
|
197
|
+
n = @methtest.new
|
198
|
+
n.method_test.class.should == Weary::Request
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'passes in authentication credentials if defined' do
|
202
|
+
n = @methtest.new
|
203
|
+
cred = {:username => 'mwunsch', :password => 'secret'}
|
204
|
+
lambda { n.authentication_test }.should raise_error
|
205
|
+
n.credentials cred[:username], cred[:password]
|
206
|
+
n.authentication_test.options[:basic_auth].should == cred
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'passes in default parameters if defined' do
|
210
|
+
n = @methtest.new
|
211
|
+
defaults = {:id => 1234, :message => "Hello world"}
|
212
|
+
lambda { n.params_test }.should raise_error
|
213
|
+
n.defaults = defaults
|
214
|
+
n.params_test.options[:body].should == defaults
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'accepts parameters when given' do
|
218
|
+
n = @methtest.new
|
219
|
+
req = n.params_test :id => 1234, :message => "Hello world", :foo => "Bar"
|
220
|
+
req.options[:body].should == {:id => 1234, :message => "Hello world"}
|
221
|
+
req.options[:body].has_key?(:foo).should == false
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
describe 'Object' do
|
230
|
+
before do
|
231
|
+
@klass = Class.new(Weary::Base)
|
232
|
+
@klass.domain 'http://foobar.com'
|
233
|
+
@klass.format :xml
|
234
|
+
@klass.headers({"User-Agent" => Weary::UserAgents["Safari 4.0.2 - Mac"]})
|
235
|
+
@klass.get "thing" do |r|
|
236
|
+
r.requires = :id
|
237
|
+
r.with = [:message, :user]
|
238
|
+
end
|
239
|
+
@klass.post "important" do |r|
|
240
|
+
r.requires = :id
|
241
|
+
r.authenticates = true
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'has methods defined by the class' do
|
246
|
+
obj = @klass.new
|
247
|
+
obj.respond_to?(:thing).should == true
|
248
|
+
obj.respond_to?(:important).should == true
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'can set authentication credentials' do
|
252
|
+
obj = @klass.new
|
253
|
+
|
254
|
+
obj.credentials "username", "password"
|
255
|
+
obj.instance_variable_get(:@credentials).should == {:username => "username", :password => "password"}
|
256
|
+
obj.important(:id => 1234).options[:basic_auth].should == obj.instance_variable_get(:@credentials)
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'credentials can be an OAuth access token' do
|
260
|
+
oauth_consumer = OAuth::Consumer.new("consumer_token","consumer_secret",{:site => 'http://foo.bar'})
|
261
|
+
oauth_token = OAuth::AccessToken.new(oauth_consumer, "token", "secret")
|
262
|
+
obj = @klass.new
|
263
|
+
|
264
|
+
obj.credentials oauth_token
|
265
|
+
obj.instance_variable_get(:@credentials).class.should == OAuth::AccessToken
|
266
|
+
obj.important(:id => 1234).options.has_key?(:oauth).should == true
|
267
|
+
obj.important(:id => 1234).options.has_key?(:basic_auth).should == false
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'can set defaults to pass into requests' do
|
271
|
+
obj = @klass.new
|
272
|
+
|
273
|
+
obj.defaults = {:user => "mwunsch", :message => "hello world"}
|
274
|
+
obj.defaults.should == {:user => "mwunsch", :message => "hello world"}
|
275
|
+
obj.thing(:id => 1234).options[:query].should == {:user => "mwunsch", :message => "hello world", :id => 1234}
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'has a list of resources' do
|
279
|
+
obj = @klass.new
|
280
|
+
|
281
|
+
obj.resources == @klass.resources
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'should keep its resources separate' do
|
285
|
+
obj = @klass.new
|
286
|
+
|
287
|
+
obj.resources[:foo] = 'bar'
|
288
|
+
obj.resources.has_key?(:foo).should == true
|
289
|
+
@klass.resources.has_key?(:foo).should == false
|
290
|
+
obj.resources.delete(:foo)
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'is able to rebuild its request method, like a singleton' do
|
294
|
+
obj1 = @klass.new
|
295
|
+
require 'pp'
|
296
|
+
|
297
|
+
obj1.resources[:thing].follows = false
|
298
|
+
obj1.rebuild_method(obj1.resources[:thing])
|
299
|
+
|
300
|
+
obj1.thing(:id => 1234).options[:no_follow].should == true
|
301
|
+
@klass.new.thing(:id => 1234).options[:no_follow].should == nil
|
302
|
+
end
|
303
|
+
|
304
|
+
it 'can modify a resource without modifying the resources of its class' do
|
305
|
+
obj = @klass.new
|
306
|
+
|
307
|
+
obj.modify_resource(:thing) {|r| r.url = "http://bar.foo" }
|
308
|
+
obj.resources[:thing].url.normalize.to_s.should == "http://bar.foo/"
|
309
|
+
obj.class.resources[:thing].url.normalize.to_s.should_not == "http://bar.foo/"
|
310
|
+
end
|
311
|
+
|
312
|
+
it 'modifying a resource rebuilds the method' do
|
313
|
+
obj = @klass.new
|
314
|
+
|
315
|
+
obj.credentials "username", "password"
|
316
|
+
obj.modify_resource(:important) {|r| r.follows = false }
|
317
|
+
obj.important(:id => 1234).options[:no_follow].should == true
|
318
|
+
end
|
319
|
+
|
320
|
+
end
|
321
|
+
end
|