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