aptible-resource 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.rubocop.yml +22 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.md +22 -0
- data/README.md +52 -0
- data/Rakefile +4 -0
- data/aptible-resource.gemspec +35 -0
- data/lib/aptible/resource.rb +7 -0
- data/lib/aptible/resource/adapter.rb +19 -0
- data/lib/aptible/resource/base.rb +70 -0
- data/lib/aptible/resource/model.rb +115 -0
- data/lib/aptible/resource/token.rb +10 -0
- data/lib/aptible/resource/version.rb +5 -0
- data/lib/hyper_resource.rb +302 -0
- data/lib/hyper_resource/adapter.rb +31 -0
- data/lib/hyper_resource/adapter/hal_json.rb +135 -0
- data/lib/hyper_resource/attributes.rb +100 -0
- data/lib/hyper_resource/exceptions.rb +40 -0
- data/lib/hyper_resource/link.rb +59 -0
- data/lib/hyper_resource/links.rb +63 -0
- data/lib/hyper_resource/modules/http.rb +131 -0
- data/lib/hyper_resource/modules/internal_attributes.rb +90 -0
- data/lib/hyper_resource/objects.rb +60 -0
- data/lib/hyper_resource/response.rb +2 -0
- data/lib/hyper_resource/version.rb +4 -0
- data/spec/aptible/resource/base_spec.rb +36 -0
- data/spec/aptible/resource/model_spec.rb +54 -0
- data/spec/fixtures/api.rb +11 -0
- data/spec/fixtures/mainframe.rb +5 -0
- data/spec/fixtures/token.rb +5 -0
- data/spec/shared/set_env.rb +10 -0
- data/spec/spec_helper.rb +14 -0
- metadata +225 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
class HyperResource
|
2
|
+
|
3
|
+
## HyperResource::Adapter is the interface/abstract base class for
|
4
|
+
## adapters to different hypermedia formats (e.g., HAL+JSON). New
|
5
|
+
## adapters must implement the public methods of this class.
|
6
|
+
|
7
|
+
class Adapter
|
8
|
+
class << self
|
9
|
+
|
10
|
+
## Serialize the given object into a string.
|
11
|
+
def serialize(object)
|
12
|
+
raise NotImplementedError, "This is an abstract method -- subclasses "+
|
13
|
+
"of HyperResource::Adapter must implement it."
|
14
|
+
end
|
15
|
+
|
16
|
+
## Deserialize a given string into an object (Hash).
|
17
|
+
def deserialize(string)
|
18
|
+
raise NotImplementedError, "This is an abstract method -- subclasses "+
|
19
|
+
"of HyperResource::Adapter must implement it."
|
20
|
+
end
|
21
|
+
|
22
|
+
## Use a given deserialized response object (Hash) to update a given
|
23
|
+
## resource (HyperResource), returning the updated resource.
|
24
|
+
def apply(response, resource, opts={})
|
25
|
+
raise NotImplementedError, "This is an abstract method -- subclasses "+
|
26
|
+
"of HyperResource::Adapter must implement it."
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'rubygems' if RUBY_VERSION[0..2] == '1.8'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
class HyperResource
|
5
|
+
class Adapter
|
6
|
+
|
7
|
+
## HyperResource::Adapter::HAL_JSON provides support for the HAL+JSON
|
8
|
+
## hypermedia format by implementing the interface defined in
|
9
|
+
## HyperResource::Adapter.
|
10
|
+
|
11
|
+
class HAL_JSON < Adapter
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def serialize(object)
|
15
|
+
JSON.dump(object)
|
16
|
+
end
|
17
|
+
|
18
|
+
def deserialize(string)
|
19
|
+
JSON.parse(string)
|
20
|
+
end
|
21
|
+
|
22
|
+
def apply(response, resource, opts={})
|
23
|
+
if !response.kind_of?(Hash)
|
24
|
+
raise ArgumentError, "'response' argument must be a Hash"
|
25
|
+
end
|
26
|
+
if !resource.kind_of?(HyperResource)
|
27
|
+
raise ArgumentError, "'resource' argument must be a HyperResource"
|
28
|
+
end
|
29
|
+
|
30
|
+
apply_objects(response, resource)
|
31
|
+
apply_links(response, resource)
|
32
|
+
apply_attributes(response, resource)
|
33
|
+
resource.loaded = true
|
34
|
+
resource.href = response['_links']['self']['href'] rescue nil
|
35
|
+
resource
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def apply_objects(resp, rsrc)
|
42
|
+
return unless resp['_embedded']
|
43
|
+
rc = rsrc.class
|
44
|
+
rsrc.objects = rc::Objects.new(rsrc)
|
45
|
+
objs = rsrc.objects
|
46
|
+
|
47
|
+
resp['_embedded'].each do |name, collection|
|
48
|
+
if collection.is_a? Hash
|
49
|
+
r = rc.new(:root => rsrc.root,
|
50
|
+
:headers => rsrc.headers,
|
51
|
+
:namespace => rsrc.namespace)
|
52
|
+
r.body = collection
|
53
|
+
objs[name] = apply(collection, r)
|
54
|
+
else
|
55
|
+
objs[name] = collection.map do |obj|
|
56
|
+
r = rc.new(:root => rsrc.root,
|
57
|
+
:headers => rsrc.headers,
|
58
|
+
:namespace => rsrc.namespace)
|
59
|
+
r.body = obj
|
60
|
+
r = classify(obj, r)
|
61
|
+
apply(obj, r)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# objs._hr_create_methods!
|
67
|
+
end
|
68
|
+
|
69
|
+
def classify(resp, rsrc)
|
70
|
+
return rsrc unless (type_name = get_data_type_from_object(resp)) &&
|
71
|
+
(namespace = rsrc.namespace)
|
72
|
+
klass = rsrc.class.namespaced_class(type_name, namespace)
|
73
|
+
|
74
|
+
if klass
|
75
|
+
rsrc = klass.new(:root => rsrc.root,
|
76
|
+
:headers => rsrc.headers,
|
77
|
+
:namespace => rsrc.namespace)
|
78
|
+
rsrc.body = resp
|
79
|
+
end
|
80
|
+
rsrc
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_data_type_from_object(object)
|
84
|
+
return nil unless object && object['type']
|
85
|
+
object['type'][0].upcase + object['type'][1..-1]
|
86
|
+
end
|
87
|
+
|
88
|
+
def apply_links(resp, rsrc)
|
89
|
+
return unless resp['_links']
|
90
|
+
rsrc.links = rsrc._hr_response_class::Links.new(rsrc)
|
91
|
+
links = rsrc.links
|
92
|
+
|
93
|
+
resp['_links'].each do |rel, link_spec|
|
94
|
+
keys = [rel]
|
95
|
+
if m=rel.match(/.+:(.+)/)
|
96
|
+
keys << m[1]
|
97
|
+
end
|
98
|
+
keys.each do |key|
|
99
|
+
if link_spec.is_a? Array
|
100
|
+
links[key] = link_spec.map do |link|
|
101
|
+
new_link_from_spec(rsrc, link)
|
102
|
+
end
|
103
|
+
else
|
104
|
+
links[key] = new_link_from_spec(rsrc, link_spec)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# links._hr_create_methods!
|
110
|
+
end
|
111
|
+
|
112
|
+
def new_link_from_spec(resource, link_spec)
|
113
|
+
resource.class::Link.new(resource, link_spec)
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
def apply_attributes(resp, rsrc)
|
118
|
+
rsrc.attributes = rsrc._hr_response_class::Attributes.new(rsrc)
|
119
|
+
|
120
|
+
given_attrs = resp.reject{|k,v| %w(_links _embedded).include?(k)}
|
121
|
+
filtered_attrs = rsrc.incoming_body_filter(given_attrs)
|
122
|
+
|
123
|
+
filtered_attrs.keys.each do |attr|
|
124
|
+
rsrc.attributes[attr] = filtered_attrs[attr]
|
125
|
+
end
|
126
|
+
|
127
|
+
rsrc.attributes._hr_clear_changed
|
128
|
+
# rsrc.attributes._hr_create_methods!
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
class HyperResource
|
2
|
+
class Attributes < Hash
|
3
|
+
|
4
|
+
attr_accessor :_resource # @private
|
5
|
+
|
6
|
+
def initialize(resource=nil) # @private
|
7
|
+
self._resource = resource || HyperResource.new
|
8
|
+
end
|
9
|
+
|
10
|
+
## Creates accessor methods in self.class and self._resource.class.
|
11
|
+
## Protects against method creation into HyperResource::Attributes and
|
12
|
+
## HyperResource classes. Just subclasses, please!
|
13
|
+
def _hr_create_methods!(opts={}) # @private
|
14
|
+
return if self.class.to_s == 'HyperResource::Attributes'
|
15
|
+
return if self._resource.class.to_s == 'HyperResource'
|
16
|
+
return if self.class.send(
|
17
|
+
:class_variable_defined?, :@@_hr_created_attributes_methods)
|
18
|
+
|
19
|
+
self.keys.each do |attr|
|
20
|
+
attr_sym = attr.to_sym
|
21
|
+
attr_eq_sym = "#{attr}=".to_sym
|
22
|
+
|
23
|
+
self.class.send(:define_method, attr_sym) do
|
24
|
+
self[attr]
|
25
|
+
end
|
26
|
+
self.class.send(:define_method, attr_eq_sym) do |val|
|
27
|
+
self[attr] = val
|
28
|
+
end
|
29
|
+
|
30
|
+
## Don't stomp on _resource's methods
|
31
|
+
unless _resource.respond_to?(attr_sym)
|
32
|
+
_resource.class.send(:define_method, attr_sym) do
|
33
|
+
attributes.send(attr_sym)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
unless _resource.respond_to?(attr_eq_sym)
|
37
|
+
_resource.class.send(:define_method, attr_eq_sym) do |val|
|
38
|
+
attributes.send(attr_eq_sym, val)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
## This is a good time to mark this object as not-changed
|
44
|
+
_hr_clear_changed
|
45
|
+
|
46
|
+
self.class.send(:class_variable_set, :@@_hr_created_attributes_methods, true)
|
47
|
+
end
|
48
|
+
|
49
|
+
## Returns +true+ if the given attribute has been changed since creation
|
50
|
+
## time, +false+ otherwise.
|
51
|
+
## If no attribute is given, return whether any attributes have been
|
52
|
+
## changed.
|
53
|
+
def changed?(attr=nil)
|
54
|
+
@_hr_changed ||= Hash.new(false)
|
55
|
+
return @_hr_changed[attr.to_sym] if attr
|
56
|
+
return @_hr_changed.keys.count > 0
|
57
|
+
end
|
58
|
+
|
59
|
+
## Returns a hash of the attributes and values which have been changed
|
60
|
+
## since creation time.
|
61
|
+
def changed_attributes
|
62
|
+
@_hr_changed.select{|k,v| v}.keys.inject({}) {|h,k| h[k]=self[k]; h}
|
63
|
+
end
|
64
|
+
|
65
|
+
def []=(attr, value) # @private
|
66
|
+
return self[attr] if self.has_key?(attr.to_s) && self[attr] == value
|
67
|
+
_hr_mark_changed(attr)
|
68
|
+
super(attr.to_s, value)
|
69
|
+
end
|
70
|
+
|
71
|
+
def [](key) # @private
|
72
|
+
return super(key.to_s) if self.has_key?(key.to_s)
|
73
|
+
return super(key.to_sym) if self.has_key?(key.to_sym)
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def method_missing(method, *args) # @private
|
78
|
+
method = method.to_s
|
79
|
+
if has_key?(method)
|
80
|
+
self[method]
|
81
|
+
elsif method[-1,1] == '='
|
82
|
+
self[method[0..-2]] = args.first
|
83
|
+
else
|
84
|
+
raise NoMethodError, "undefined method `#{method}' for #{self.inspect}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def _hr_clear_changed # @private
|
89
|
+
@_hr_changed = nil
|
90
|
+
end
|
91
|
+
|
92
|
+
def _hr_mark_changed(attr, is_changed=true) # @private
|
93
|
+
attr = attr.to_sym
|
94
|
+
@_hr_changed ||= Hash.new(false)
|
95
|
+
@_hr_changed[attr] = is_changed
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class HyperResource
|
2
|
+
class Exception < ::StandardError
|
3
|
+
## The internal exception which led to this one, if any.
|
4
|
+
attr_accessor :cause
|
5
|
+
|
6
|
+
def initialize(message, attrs={}) # @private
|
7
|
+
self.cause = attrs[:cause]
|
8
|
+
super(message)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class ResponseError < Exception
|
13
|
+
## The +Faraday::Response+ object which led to this exception.
|
14
|
+
attr_accessor :response
|
15
|
+
|
16
|
+
## The deserialized response body which led to this exception.
|
17
|
+
## May be blank, e.g. in case of deserialization errors.
|
18
|
+
attr_accessor :body
|
19
|
+
|
20
|
+
def initialize(message, attrs={}) # @private
|
21
|
+
self.response = attrs[:response]
|
22
|
+
self.body = attrs[:body]
|
23
|
+
|
24
|
+
## Try to help out with the message
|
25
|
+
if self.body
|
26
|
+
if error = self.body['error']
|
27
|
+
message = "#{message} (#{error})"
|
28
|
+
end
|
29
|
+
elsif self.response
|
30
|
+
message = "#{message} (\"#{self.response.inspect}\")"
|
31
|
+
end
|
32
|
+
|
33
|
+
super(message, attrs)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class ClientError < ResponseError; end
|
38
|
+
class ServerError < ResponseError; end
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'uri_template'
|
2
|
+
|
3
|
+
class HyperResource::Link
|
4
|
+
attr_accessor :base_href,
|
5
|
+
:name,
|
6
|
+
:templated,
|
7
|
+
:params,
|
8
|
+
:parent_resource
|
9
|
+
|
10
|
+
## Returns true if this link is templated.
|
11
|
+
def templated?; templated end
|
12
|
+
|
13
|
+
def initialize(resource=nil, link_spec={})
|
14
|
+
self.parent_resource = resource || HyperResource.new
|
15
|
+
self.base_href = link_spec['href']
|
16
|
+
self.name = link_spec['name']
|
17
|
+
self.templated = !!link_spec['templated']
|
18
|
+
self.params = link_spec['params'] || {}
|
19
|
+
end
|
20
|
+
|
21
|
+
## Returns this link's href, applying any URI template params.
|
22
|
+
def href
|
23
|
+
if self.templated?
|
24
|
+
filtered_params = self.parent_resource.outgoing_uri_filter(params)
|
25
|
+
URITemplate.new(self.base_href).expand(filtered_params)
|
26
|
+
else
|
27
|
+
self.base_href
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
## Returns a new scope with the given params; that is, returns a copy of
|
32
|
+
## itself with the given params applied.
|
33
|
+
def where(params)
|
34
|
+
params = Hash[ params.map{|(k,v)| [k.to_s, v]} ]
|
35
|
+
self.class.new(self.parent_resource,
|
36
|
+
'href' => self.base_href,
|
37
|
+
'name' => self.name,
|
38
|
+
'templated' => self.templated,
|
39
|
+
'params' => self.params.merge(params))
|
40
|
+
end
|
41
|
+
|
42
|
+
## Returns a HyperResource representing this link
|
43
|
+
def resource
|
44
|
+
parent_resource._hr_new_from_link(self.href)
|
45
|
+
end
|
46
|
+
|
47
|
+
## Delegate HTTP methods to the resource.
|
48
|
+
def get(*args); self.resource.get(*args) end
|
49
|
+
def post(*args); self.resource.post(*args) end
|
50
|
+
def patch(*args); self.resource.patch(*args) end
|
51
|
+
def put(*args); self.resource.put(*args) end
|
52
|
+
def delete(*args); self.resource.delete(*args) end
|
53
|
+
|
54
|
+
## If we were called with a method we don't know, load this resource
|
55
|
+
## and pass the message along. This achieves implicit loading.
|
56
|
+
def method_missing(method, *args)
|
57
|
+
self.get.send(method, *args)
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class HyperResource
|
2
|
+
class Links < Hash
|
3
|
+
attr_accessor :_resource
|
4
|
+
|
5
|
+
def initialize(resource=nil)
|
6
|
+
self._resource = resource || HyperResource.new
|
7
|
+
end
|
8
|
+
|
9
|
+
## Creates accessor methods in self.class and self._resource.class.
|
10
|
+
## Protects against method creation into HyperResource::Links and
|
11
|
+
## HyperResource classes. Just subclasses, please!
|
12
|
+
def _hr_create_methods!(opts={}) # @private
|
13
|
+
return if self.class.to_s == 'HyperResource::Links'
|
14
|
+
return if self._resource.class.to_s == 'HyperResource'
|
15
|
+
return if self.class.send(
|
16
|
+
:class_variable_defined?, :@@_hr_created_links_methods)
|
17
|
+
|
18
|
+
self.keys.each do |attr|
|
19
|
+
attr_sym = attr.to_sym
|
20
|
+
self.class.send(:define_method, attr_sym) do |*args|
|
21
|
+
if args.count > 0
|
22
|
+
self[attr].where(*args)
|
23
|
+
else
|
24
|
+
self[attr]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
## Don't stomp on _resource's methods
|
29
|
+
unless _resource.respond_to?(attr_sym)
|
30
|
+
_resource.class.send(:define_method, attr_sym) do |*args|
|
31
|
+
links.send(attr_sym, *args)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
self.class.send(:class_variable_set, :@@_hr_created_links_methods, true)
|
37
|
+
end
|
38
|
+
|
39
|
+
def []=(attr, value) # @private
|
40
|
+
super(attr.to_s, value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def [](key) # @private
|
44
|
+
return super(key.to_s) if self.has_key?(key.to_s)
|
45
|
+
return super(key.to_sym) if self.has_key?(key.to_sym)
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def method_missing(method, *args) # @private
|
50
|
+
unless self[method]
|
51
|
+
raise NoMethodError, "undefined method `#{method}' for #{self.inspect}"
|
52
|
+
end
|
53
|
+
|
54
|
+
if args.count > 0
|
55
|
+
self[method].where(*args)
|
56
|
+
else
|
57
|
+
self[method]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'uri'
|
3
|
+
require 'json'
|
4
|
+
require 'digest/md5'
|
5
|
+
|
6
|
+
class HyperResource
|
7
|
+
module Modules
|
8
|
+
module HTTP
|
9
|
+
|
10
|
+
## Loads and returns the resource pointed to by +href+. The returned
|
11
|
+
## resource will be blessed into its "proper" class, if
|
12
|
+
## +self.class.namespace != nil+.
|
13
|
+
def get
|
14
|
+
self.response = faraday_connection.get(self.href || '')
|
15
|
+
finish_up
|
16
|
+
end
|
17
|
+
|
18
|
+
## By default, calls +post+ with the given arguments. Override to
|
19
|
+
## change this behavior.
|
20
|
+
def create(*args)
|
21
|
+
post(*args)
|
22
|
+
end
|
23
|
+
|
24
|
+
## POSTs the given attributes to this resource's href, and returns
|
25
|
+
## the response resource.
|
26
|
+
def post(attrs=nil)
|
27
|
+
attrs || self.attributes
|
28
|
+
self.response = faraday_connection.post do |req|
|
29
|
+
req.body = adapter.serialize(attrs)
|
30
|
+
end
|
31
|
+
finish_up
|
32
|
+
end
|
33
|
+
|
34
|
+
## By default, calls +put+ with the given arguments. Override to
|
35
|
+
## change this behavior.
|
36
|
+
def update(*args)
|
37
|
+
put(*args)
|
38
|
+
end
|
39
|
+
|
40
|
+
## PUTs this resource's attributes to this resource's href, and returns
|
41
|
+
## the response resource. If attributes are given, +put+ uses those
|
42
|
+
## instead.
|
43
|
+
def put(attrs=nil)
|
44
|
+
attrs ||= self.attributes
|
45
|
+
self.response = faraday_connection.put do |req|
|
46
|
+
req.body = adapter.serialize(attrs)
|
47
|
+
end
|
48
|
+
finish_up
|
49
|
+
end
|
50
|
+
|
51
|
+
## PATCHes this resource's changed attributes to this resource's href,
|
52
|
+
## and returns the response resource. If attributes are given, +patch+
|
53
|
+
## uses those instead.
|
54
|
+
def patch(attrs=nil)
|
55
|
+
attrs ||= self.attributes.changed_attributes
|
56
|
+
self.response = faraday_connection.patch do |req|
|
57
|
+
req.body = adapter.serialize(attrs)
|
58
|
+
end
|
59
|
+
finish_up
|
60
|
+
end
|
61
|
+
|
62
|
+
## DELETEs this resource's href, and returns the response resource.
|
63
|
+
def delete
|
64
|
+
self.response = faraday_connection.delete
|
65
|
+
finish_up
|
66
|
+
end
|
67
|
+
|
68
|
+
## Returns a raw Faraday connection to this resource's URL, with proper
|
69
|
+
## headers (including auth). Threadsafe.
|
70
|
+
def faraday_connection(url=nil)
|
71
|
+
url ||= URI.join(self.root, self.href)
|
72
|
+
key = Digest::MD5.hexdigest({
|
73
|
+
'faraday_connection' => {
|
74
|
+
'url' => url,
|
75
|
+
'headers' => self.headers,
|
76
|
+
'ba' => self.auth[:basic]
|
77
|
+
}
|
78
|
+
}.to_json)
|
79
|
+
return Thread.current[key] if Thread.current[key]
|
80
|
+
|
81
|
+
fc = Faraday.new(self.faraday_options.merge(:url => url))
|
82
|
+
fc.headers.merge!('User-Agent' => "HyperResource #{HyperResource::VERSION}")
|
83
|
+
fc.headers.merge!(self.headers || {})
|
84
|
+
if ba=self.auth[:basic]
|
85
|
+
fc.basic_auth(*ba)
|
86
|
+
end
|
87
|
+
Thread.current[key] = fc
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def finish_up
|
93
|
+
begin
|
94
|
+
self.body = self.adapter.deserialize(self.response.body) unless self.response.body.nil?
|
95
|
+
rescue StandardError => e
|
96
|
+
raise HyperResource::ResponseError.new(
|
97
|
+
"Error when deserializing response body",
|
98
|
+
:response => self.response,
|
99
|
+
:cause => e
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
self.adapter.apply(self.body, self)
|
104
|
+
self.loaded = true
|
105
|
+
|
106
|
+
status = self.response.status
|
107
|
+
if status / 100 == 2
|
108
|
+
return to_response_class
|
109
|
+
elsif status / 100 == 3
|
110
|
+
## TODO redirect logic?
|
111
|
+
elsif status / 100 == 4
|
112
|
+
raise HyperResource::ClientError.new(status.to_s,
|
113
|
+
:response => self.response,
|
114
|
+
:body => self.body)
|
115
|
+
elsif status / 100 == 5
|
116
|
+
raise HyperResource::ServerError.new(status.to_s,
|
117
|
+
:response => self.response,
|
118
|
+
:body => self.body)
|
119
|
+
|
120
|
+
else ## 1xx? really?
|
121
|
+
raise HyperResource::ResponseError.new("Got status #{status}, wtf?",
|
122
|
+
:response => self.response,
|
123
|
+
:body => self.body)
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|