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
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'weary/response'
|
2
|
+
|
3
|
+
module Weary
|
4
|
+
# A handy abstract proxy class that is used to proxy a domain model
|
5
|
+
# in an asynchronous fashion. Useful if you're not interested in a
|
6
|
+
# Weary::Response object, but you want to pass that into a domain object
|
7
|
+
# when the response is available.
|
8
|
+
class Deferred < defined?(::BasicObject) ? ::BasicObject : ::Object
|
9
|
+
|
10
|
+
instance_methods.each {|m| undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^object_id$)/ } \
|
11
|
+
unless defined? ::BasicObject
|
12
|
+
|
13
|
+
attr_reader :callable
|
14
|
+
|
15
|
+
def initialize(future, model, callable=nil)
|
16
|
+
@future = future
|
17
|
+
@model = model
|
18
|
+
@callable = callable || ::Proc.new{|klass, response| klass.new(response) }
|
19
|
+
@target = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def complete?
|
23
|
+
!!@target
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing(method, *args, &block)
|
27
|
+
if @model.method_defined? method
|
28
|
+
@target ||= @callable.call @model, @future.force
|
29
|
+
@target.send(method, *args, &block)
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/weary/env.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Weary
|
2
|
+
class Env
|
3
|
+
def initialize(request)
|
4
|
+
@request = request
|
5
|
+
end
|
6
|
+
|
7
|
+
def headers
|
8
|
+
Hash[@request.headers.map {|k,v| ["HTTP_#{k.to_s.upcase.gsub('-','_')}", v] }]
|
9
|
+
end
|
10
|
+
|
11
|
+
def env
|
12
|
+
{
|
13
|
+
'REQUEST_METHOD' => @request.method,
|
14
|
+
'SCRIPT_NAME' => "",
|
15
|
+
'PATH_INFO' => @request.uri.path,
|
16
|
+
'QUERY_STRING' => @request.uri.query || "",
|
17
|
+
'SERVER_NAME' => @request.uri.host,
|
18
|
+
'SERVER_PORT' => port,
|
19
|
+
'REQUEST_URI' => @request.uri.request_uri,
|
20
|
+
'HTTP_HOST' => @request.uri.host,
|
21
|
+
'rack.url_scheme' => @request.uri.scheme,
|
22
|
+
'rack.input' => @request.body,
|
23
|
+
'weary.request' => @request
|
24
|
+
}.update headers
|
25
|
+
end
|
26
|
+
|
27
|
+
def port
|
28
|
+
(@request.uri.port || @request.uri.inferred_port).to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Weary
|
2
|
+
module Middleware
|
3
|
+
class BasicAuth
|
4
|
+
AUTH_HEADER = "HTTP_AUTHORIZATION"
|
5
|
+
|
6
|
+
def initialize(app, credentials)
|
7
|
+
@app = app
|
8
|
+
@auth = [credentials.join(':')].pack('m*')
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
env.update AUTH_HEADER => "Basic #{@auth}"
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Weary
|
2
|
+
module Middleware
|
3
|
+
class ContentType
|
4
|
+
|
5
|
+
CONTENT_TYPE = 'CONTENT_TYPE'
|
6
|
+
CONTENT_LENGTH = 'CONTENT_LENGTH'
|
7
|
+
FORM_URL_ENCODED = 'application/x-www-form-urlencoded'
|
8
|
+
MULTIPART_FORM = 'multipart/form-data'
|
9
|
+
|
10
|
+
attr_reader :type
|
11
|
+
|
12
|
+
def initialize(app, type = FORM_URL_ENCODED)
|
13
|
+
@app = app
|
14
|
+
@type = type
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
env.update CONTENT_TYPE => @type
|
19
|
+
env.update CONTENT_LENGTH => length(env['rack.input'])
|
20
|
+
@app.call(env)
|
21
|
+
end
|
22
|
+
|
23
|
+
def length(input)
|
24
|
+
input.size.to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'weary/middleware'
|
2
|
+
require 'simple_oauth'
|
3
|
+
|
4
|
+
module Weary
|
5
|
+
module Middleware
|
6
|
+
class OAuth
|
7
|
+
AUTH_HEADER = "HTTP_AUTHORIZATION"
|
8
|
+
|
9
|
+
def initialize(app, consumer_key, access_token)
|
10
|
+
@app = app
|
11
|
+
@oauth = {
|
12
|
+
:consumer_key => consumer_key,
|
13
|
+
:token => access_token
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
env.update AUTH_HEADER => sign(env).to_s
|
19
|
+
@app.call(env)
|
20
|
+
end
|
21
|
+
|
22
|
+
def sign(env)
|
23
|
+
req = Rack::Request.new(env)
|
24
|
+
SimpleOAuth::Header.new req.request_method,
|
25
|
+
req.url,
|
26
|
+
req.params,
|
27
|
+
@oauth
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/weary/request.rb
CHANGED
@@ -1,140 +1,153 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
require 'future'
|
3
|
+
require 'rack'
|
4
|
+
|
5
|
+
require 'weary/env'
|
6
|
+
require 'weary/adapter'
|
7
|
+
|
8
|
+
autoload :Middleware, 'weary/middleware'
|
9
|
+
autoload :MultiJson, 'multi_json'
|
10
|
+
|
1
11
|
module Weary
|
12
|
+
# A Request is an interface to an http request. It doesn't actually make the
|
13
|
+
# request. Instead, it builds itself up into a Rack environment. A Request
|
14
|
+
# object is technically a Rack middleware, with a call method. The Request
|
15
|
+
# manipulates the passed in environment, then passes on to the adapter: A
|
16
|
+
# Rack application. Because the Request performs so much manipulation on
|
17
|
+
# the Rack env, you can attach middleware to it to act on its mutated env.
|
2
18
|
class Request
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(url, http_verb= :get, options={})
|
19
|
+
attr_reader :uri
|
20
|
+
|
21
|
+
def initialize(url, method='GET')
|
8
22
|
self.uri = url
|
9
|
-
self.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
self.follows = options[:no_follow] ? false : true
|
16
|
-
end
|
17
|
-
|
18
|
-
# Create a URI object for the given URL
|
23
|
+
self.method = method
|
24
|
+
@middlewares = []
|
25
|
+
yield self if block_given?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Set and normalize the url for the Request.
|
19
29
|
def uri=(url)
|
20
|
-
|
21
|
-
|
22
|
-
|
30
|
+
uri = Addressable::URI.parse(url).normalize!
|
31
|
+
@uri = uri
|
32
|
+
end
|
33
|
+
|
34
|
+
# A Rack interface for the Request. Applies itself and whatever
|
35
|
+
# middlewares to the env and passes the new env into the adapter.
|
36
|
+
#
|
37
|
+
# environment - A Hash for the Rack env.
|
38
|
+
#
|
39
|
+
# Returns an Array of three items; a Rack tuple.
|
40
|
+
def call(environment)
|
41
|
+
app = adapter.new
|
42
|
+
middlewares = @middlewares
|
43
|
+
stack = Rack::Builder.new do
|
44
|
+
middlewares.each do |middleware|
|
45
|
+
klass, *args = middleware
|
46
|
+
use klass, *args[0...-1].flatten, &args.last
|
47
|
+
end
|
48
|
+
run app
|
23
49
|
end
|
50
|
+
stack.call rack_env_defaults.merge(environment.update(env))
|
51
|
+
end
|
52
|
+
|
53
|
+
# Build a Rack environment representing this Request.
|
54
|
+
def env
|
55
|
+
Weary::Env.new(self).env
|
24
56
|
end
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@
|
29
|
-
|
30
|
-
|
31
|
-
|
57
|
+
|
58
|
+
# The HTTP request method for this Request.
|
59
|
+
def method
|
60
|
+
@method
|
61
|
+
end
|
62
|
+
|
63
|
+
# Set and normalize the HTTP request method.
|
64
|
+
def method=(verb)
|
65
|
+
@method = verb.to_s.upcase
|
66
|
+
end
|
67
|
+
|
68
|
+
def headers(hash=nil)
|
69
|
+
@headers = hash unless hash.nil?
|
70
|
+
@headers ||= {}
|
71
|
+
end
|
72
|
+
|
73
|
+
def user_agent(agent)
|
74
|
+
headers.update 'User-Agent' => agent
|
75
|
+
end
|
76
|
+
|
77
|
+
def params(parameters=nil)
|
78
|
+
if !parameters.nil?
|
79
|
+
if ["POST", "PUT"].include? method
|
80
|
+
@body = query_params_from_hash(parameters)
|
81
|
+
body StringIO.new(@body)
|
82
|
+
use Weary::Middleware::ContentType
|
83
|
+
else
|
84
|
+
uri.query_values = parameters
|
85
|
+
@body = uri.query
|
86
|
+
end
|
32
87
|
end
|
88
|
+
@body
|
89
|
+
end
|
90
|
+
|
91
|
+
def json(parameters)
|
92
|
+
json = MultiJson.encode(parameters)
|
93
|
+
body StringIO.new(json)
|
94
|
+
json
|
33
95
|
end
|
34
|
-
|
35
|
-
def
|
36
|
-
@
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
96
|
+
|
97
|
+
def body(io=nil)
|
98
|
+
@attachment = io unless io.nil?
|
99
|
+
@attachment ||= StringIO.new('')
|
100
|
+
end
|
101
|
+
|
102
|
+
def adapter(connection=nil)
|
103
|
+
@connection = connection unless connection.nil?
|
104
|
+
@connection ||= Weary::Adapter::NetHttp
|
105
|
+
end
|
106
|
+
|
107
|
+
def basic_auth(*credentials)
|
108
|
+
if !credentials.empty?
|
109
|
+
@basic_auth = true
|
110
|
+
use Weary::Middleware::BasicAuth, credentials
|
46
111
|
end
|
112
|
+
@basic_auth
|
47
113
|
end
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
if auth.is_a?(OAuth::AccessToken)
|
54
|
-
@credentials = auth
|
55
|
-
else
|
56
|
-
@credentials = {:username => auth[:username], :password => auth[:password]}
|
114
|
+
|
115
|
+
def oauth(consumer_key=nil, access_token=nil)
|
116
|
+
if !consumer_key.nil? && !access_token.nil?
|
117
|
+
@oauth = true
|
118
|
+
use Weary::Middleware::OAuth, [consumer_key, access_token]
|
57
119
|
end
|
120
|
+
@oauth
|
58
121
|
end
|
59
|
-
|
60
|
-
#
|
61
|
-
def
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
# A callback that is triggered after the Response is received.
|
70
|
-
def on_complete(&block)
|
71
|
-
@on_complete = block if block_given?
|
72
|
-
@on_complete
|
73
|
-
end
|
74
|
-
|
75
|
-
# A callback that is sent before the Request is fired.
|
76
|
-
def before_send(&block)
|
77
|
-
@before_send = block if block_given?
|
78
|
-
@before_send
|
79
|
-
end
|
80
|
-
|
81
|
-
# Perform the Request, returns the Response. Pass a block in to use
|
82
|
-
# as the on_complete callback.
|
83
|
-
def perform(&block)
|
84
|
-
@on_complete = block if block_given?
|
85
|
-
response = perform!
|
86
|
-
response.value
|
87
|
-
end
|
88
|
-
|
89
|
-
# Spins off a new thread to perform the Request.
|
90
|
-
def perform!(&block)
|
91
|
-
@on_complete = block if block_given?
|
92
|
-
Thread.new {
|
93
|
-
before_send.call(self) if before_send
|
94
|
-
req = http.request(request)
|
95
|
-
response = Response.new(req, self)
|
96
|
-
if response.redirected? && follows?
|
97
|
-
response.follow_redirect
|
98
|
-
else
|
99
|
-
on_complete.call(response) if on_complete
|
100
|
-
response
|
101
|
-
end
|
102
|
-
}
|
103
|
-
end
|
104
|
-
|
105
|
-
# Build the HTTP connection.
|
106
|
-
def http
|
107
|
-
socket = Net::HTTP.new(uri.host, uri.port)
|
108
|
-
socket.use_ssl = uri.is_a?(URI::HTTPS)
|
109
|
-
socket.verify_mode = OpenSSL::SSL::VERIFY_NONE if socket.use_ssl?
|
110
|
-
socket
|
111
|
-
end
|
112
|
-
|
113
|
-
# Build the HTTP Request.
|
114
|
-
def request
|
115
|
-
req = connection
|
116
|
-
|
117
|
-
req.body = with if (with && req.request_body_permitted?)
|
118
|
-
if (credentials)
|
119
|
-
if (credentials.is_a?(OAuth::AccessToken))
|
120
|
-
credentials.sign!(req)
|
121
|
-
else
|
122
|
-
req.basic_auth(credentials[:username], credentials[:password])
|
123
|
-
end
|
122
|
+
|
123
|
+
# Returns a future-wrapped Response.
|
124
|
+
def perform
|
125
|
+
future do
|
126
|
+
status, headers, body = call(rack_env_defaults)
|
127
|
+
response = Weary::Response.new body, status, headers
|
128
|
+
yield response if block_given?
|
129
|
+
response
|
124
130
|
end
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
end
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
131
|
+
end
|
132
|
+
|
133
|
+
def use(middleware, *args, &block)
|
134
|
+
@middlewares << [middleware, args, block]
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def query_params_from_hash(hash)
|
140
|
+
tmp_uri = Addressable::URI.new
|
141
|
+
tmp_uri.query_values = hash
|
142
|
+
tmp_uri.query
|
143
|
+
end
|
144
|
+
|
145
|
+
def rack_env_defaults
|
146
|
+
{ 'rack.version' => Rack::VERSION,
|
147
|
+
'rack.errors' => $stderr,
|
148
|
+
'rack.multithread' => true,
|
149
|
+
'rack.multiprocess' => false,
|
150
|
+
'rack.run_once' => false }
|
138
151
|
end
|
139
152
|
|
140
153
|
end
|
data/lib/weary/resource.rb
CHANGED
@@ -1,135 +1,159 @@
|
|
1
|
+
require 'addressable/template'
|
2
|
+
require 'weary/request'
|
3
|
+
|
1
4
|
module Weary
|
5
|
+
# A description of a resource made available by an HTTP request. That
|
6
|
+
# description is composed primarily of a url template, the HTTP method to
|
7
|
+
# retrieve the resource and some constraints on the parameters necessary
|
8
|
+
# to complete the request.
|
2
9
|
class Resource
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
self.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
#
|
25
|
-
def
|
26
|
-
@
|
27
|
-
@
|
28
|
-
end
|
29
|
-
|
30
|
-
#
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
10
|
+
UnmetRequirementsError = Class.new(StandardError)
|
11
|
+
|
12
|
+
attr_reader :method
|
13
|
+
|
14
|
+
def initialize(method, uri)
|
15
|
+
@method = method
|
16
|
+
self.url uri
|
17
|
+
end
|
18
|
+
|
19
|
+
# An accessor method to set the url to retrieve the resource. Use either
|
20
|
+
# brackets to delimit url variables or prefix them with a colon, like
|
21
|
+
# Sinatra.
|
22
|
+
#
|
23
|
+
# Returns an Addressable::Template
|
24
|
+
def url(uri=nil)
|
25
|
+
@uri = Addressable::Template.new(uri.gsub(/:(\w+)/) { "{#{$1}}" }) unless uri.nil?
|
26
|
+
@uri
|
27
|
+
end
|
28
|
+
|
29
|
+
# An accessor to set optional parameters permitted by the resource.
|
30
|
+
#
|
31
|
+
# Returns an Array of parameters.
|
32
|
+
def optional(*params)
|
33
|
+
@optional = params unless params.empty?
|
34
|
+
@optional ||= []
|
35
|
+
end
|
36
|
+
|
37
|
+
# An accessor to set optional parameters required in order to access the
|
38
|
+
# resource.
|
39
|
+
#
|
40
|
+
# Returns an Array of parameters.
|
41
|
+
def required(*params)
|
42
|
+
@required = params unless params.empty?
|
43
|
+
@required ||= []
|
44
|
+
end
|
45
|
+
|
46
|
+
# An accessor to set default paramers to send to the resource.
|
47
|
+
def defaults(hash=nil)
|
48
|
+
@defaults = hash unless hash.nil?
|
49
|
+
@defaults ||= {}
|
50
|
+
end
|
51
|
+
|
52
|
+
# An accessor to set HTTP request headers.
|
53
|
+
def headers(hash=nil)
|
54
|
+
@headers = hash unless hash.nil?
|
55
|
+
@headers ||= {}
|
56
|
+
end
|
57
|
+
|
58
|
+
# Set up a Rack::Middleware to be used by the Request (which is
|
59
|
+
# Rack-friendly).
|
60
|
+
def use(middleware, *args, &block)
|
61
|
+
@middlewares ||= []
|
62
|
+
@middlewares << [middleware, args, block]
|
63
|
+
end
|
64
|
+
|
65
|
+
# Convenience method to set a User Agent Header
|
66
|
+
def user_agent(agent)
|
67
|
+
headers.update 'User-Agent' => agent
|
68
|
+
end
|
69
|
+
|
70
|
+
# Tell the Resource to anticipate Basic Authentication. Optionally,
|
71
|
+
# tell the Resource what parameters to use as credentials.
|
72
|
+
#
|
73
|
+
# user - The parameter in which to expect the username (defaults to :username)
|
74
|
+
# pass - The parameter in which to expect the password (defaults to :password)
|
75
|
+
def basic_auth!(user = :username, pass = :password)
|
76
|
+
@authenticates = :basic_auth
|
77
|
+
@credentials = [user, pass]
|
78
|
+
end
|
79
|
+
|
80
|
+
# Tell the Resource to anticipate OAuth. Optionally, tell the Resource
|
81
|
+
# what parameters to use as the consumer key and access token
|
82
|
+
#
|
83
|
+
# key - The parameter in which to expect the consumer key (defaults to
|
84
|
+
# :consumer_key)
|
85
|
+
# token - The parameter in which to expect the user access token (defaults
|
86
|
+
# to :token)
|
87
|
+
def oauth!(key = :consumer_key, token = :token)
|
88
|
+
@authenticates = :oauth
|
89
|
+
@credentials = [key, token]
|
90
|
+
end
|
91
|
+
|
92
|
+
# Does the Resource anticipate some sort of authentication parameters?
|
42
93
|
def authenticates?
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
#
|
47
|
-
def
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
#
|
52
|
-
def
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
#
|
57
|
-
def
|
58
|
-
|
59
|
-
end
|
60
|
-
|
61
|
-
#
|
62
|
-
def
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
#
|
73
|
-
def
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
# Search the given parameters to see if they are missing any required params
|
89
|
-
def find_missing_requirements(params)
|
90
|
-
if (@requires && !@requires.empty?)
|
91
|
-
missing_requirements = @requires - params.keys
|
92
|
-
raise ArgumentError, "This resource is missing required parameters: '#{missing_requirements.inspect}'" unless missing_requirements.empty?
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# Remove params that have not been specified with #with
|
97
|
-
def remove_unnecessary_params(params)
|
98
|
-
params.delete_if {|k,v| !@with.include?(k) } if (@with && !@with.empty?)
|
99
|
-
end
|
100
|
-
|
101
|
-
# Setup the options to be passed into the Request
|
102
|
-
def setup_options(params={}, credentials=nil)
|
103
|
-
options = {}
|
104
|
-
prepare_request_body(params, options)
|
105
|
-
setup_authentication(options, credentials)
|
106
|
-
options[:no_follow] = true if !follows?
|
107
|
-
options[:headers] = @headers if !@headers.blank?
|
108
|
-
options
|
109
|
-
end
|
110
|
-
|
111
|
-
# Prepare the Request query or body depending on the HTTP method
|
112
|
-
def prepare_request_body(params, options={})
|
113
|
-
if (@via == :post || @via == :put)
|
114
|
-
options[:body] = params unless params.blank?
|
115
|
-
else
|
116
|
-
options[:query] = params unless params.blank?
|
117
|
-
end
|
118
|
-
options
|
119
|
-
end
|
120
|
-
|
121
|
-
# Prepare authentication credentials for the Request
|
122
|
-
def setup_authentication(options, credentials=nil)
|
123
|
-
if authenticates?
|
124
|
-
raise ArgumentError, "This resource requires authentication and no credentials were given." if credentials.blank?
|
125
|
-
if credentials.is_a?(OAuth::AccessToken)
|
126
|
-
options[:oauth] = credentials
|
127
|
-
else
|
128
|
-
options[:basic_auth] = credentials
|
94
|
+
!!@authenticates
|
95
|
+
end
|
96
|
+
|
97
|
+
# The keys expected as parameters to the Request.
|
98
|
+
def expected_params
|
99
|
+
defaults.keys.map(&:to_s) | optional.map(&:to_s) | required.map(&:to_s)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Does the Resource expect this parameter to be used to make the Request?
|
103
|
+
def expects?(param)
|
104
|
+
expected_params.include? param.to_s
|
105
|
+
end
|
106
|
+
|
107
|
+
# The parameter keys that must be fulfilled to create the Request.
|
108
|
+
def requirements
|
109
|
+
required.map(&:to_s) | url.keys
|
110
|
+
end
|
111
|
+
|
112
|
+
# Given a hash of Request parameters, do they meet the requirements?
|
113
|
+
def meets_requirements?(params)
|
114
|
+
requirements.reject {|k| params.keys.map(&:to_s).include? k.to_s }.empty?
|
115
|
+
end
|
116
|
+
|
117
|
+
# Construct the request from the given parameters.
|
118
|
+
#
|
119
|
+
# Yields the Request
|
120
|
+
#
|
121
|
+
# Returns the Request.
|
122
|
+
# Raises a Weary::Resource::UnmetRequirementsError if the requirements
|
123
|
+
# are not met.
|
124
|
+
def request(params={})
|
125
|
+
params.delete_if {|k,v| v.nil? || v.to_s.empty? }
|
126
|
+
params.update(defaults)
|
127
|
+
raise UnmetRequirementsError, "Required parameters: #{requirements}" \
|
128
|
+
unless meets_requirements? params
|
129
|
+
credentials = pull_credentials params if authenticates?
|
130
|
+
mapping = url.keys.map {|k| [k, params.delete(k) || params.delete(k.to_sym)] }
|
131
|
+
request = Weary::Request.new url.expand(Hash[mapping]), @method do |r|
|
132
|
+
r.headers headers
|
133
|
+
if !expected_params.empty?
|
134
|
+
r.params params.reject {|k,v| !expects? k }
|
135
|
+
end
|
136
|
+
r.send @authenticates, *credentials if authenticates?
|
137
|
+
if !@middlewares.nil? && !@middlewares.empty?
|
138
|
+
@middlewares.each {|middleware| r.use *middleware }
|
129
139
|
end
|
130
140
|
end
|
131
|
-
|
132
|
-
|
133
|
-
|
141
|
+
yield request if block_given?
|
142
|
+
request
|
143
|
+
end
|
144
|
+
alias build request
|
145
|
+
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
# Private: Separate the credentials for authentication from the other
|
150
|
+
# request parameters.
|
151
|
+
def pull_credentials(params)
|
152
|
+
(@credentials || []).map do |credential|
|
153
|
+
params.delete(credential) || params.delete(credential.to_s)
|
154
|
+
end.compact
|
155
|
+
end
|
156
|
+
|
157
|
+
|
134
158
|
end
|
135
159
|
end
|