Class: HyperResource
- Inherits:
-
Object
- Object
- HyperResource
- Includes:
- Enumerable, Modules::HTTP, Modules::InternalAttributes
- Defined in:
- lib/hyper_resource.rb,
lib/hyper_resource/links.rb,
lib/hyper_resource/adapter.rb,
lib/hyper_resource/objects.rb,
lib/hyper_resource/version.rb,
lib/hyper_resource/attributes.rb,
lib/hyper_resource/exceptions.rb,
lib/hyper_resource/modules/http.rb,
lib/hyper_resource/adapter/hal_json.rb,
lib/hyper_resource/modules/http/wrap_errors.rb
Overview
HyperResource is the main resource base class. Normally it will be used through subclassing, though it may also be used directly.
Direct Known Subclasses
Defined Under Namespace
Modules: Modules Classes: Adapter, Attributes, ClientError, Exception, Link, Links, Objects, Response, ResponseError, ServerError
Constant Summary collapse
- VERSION =
'0.2.5'.freeze
- VERSION_DATE =
'2014-04-02'.freeze
Constants included from Modules::HTTP
Modules::HTTP::CONTENT_TYPE_HEADERS, Modules::HTTP::MAX_COORDINATOR_RETRIES
Class Method Summary collapse
-
.get_data_type_from_response(response) ⇒ Object
Inspects the given Faraday::Response, and returns a string describing this resource’s data type.
- .namespaced_class(type_name, namespace) ⇒ Object
-
.response_class(response, namespace) ⇒ Object
Returns the class into which the given response should be cast.
Instance Method Summary collapse
-
#[](i) ⇒ Object
Returns the *i*th object in the first collection of objects embedded in this resource.
-
#_hr_new_from_link(href) ⇒ Object
Return a new HyperResource based on this object and a given href.
- #_hr_response_class ⇒ Object
-
#changed?(*args) ⇒ Boolean
Returns true if one or more of this object’s attributes has been reassigned.
- #deserialized_response ⇒ Object
-
#each(&block) ⇒ Object
Iterates over the objects in the first collection of embedded objects in this resource.
-
#get_data_type_from_response ⇒ Object
Uses
HyperResource.get_response_data_type
to determine the proper data type for this object. -
#incoming_body_filter(attr_hash) ⇒ Object
incoming_body_filter
filters a hash of attribute keys and values on their way from a response body to a HyperResource. -
#initialize(opts = {}) ⇒ HyperResource
constructor
Create a new HyperResource, given a hash of options.
- #inspect ⇒ Object
-
#method_missing(method, *args) ⇒ Object
method_missing will load this resource if not yet loaded, then attempt to delegate to
attributes
, thenobjects
, thenlinks
. -
#outgoing_body_filter(attr_hash) ⇒ Object
outgoing_body_filter
filters a hash of attribute keys and values on their way from a HyperResource to a request body. -
#outgoing_uri_filter(attr_hash) ⇒ Object
outgoing_uri_filter
filters a hash of attribute keys and values on their way from a HyperResource to a URL. -
#response_body ⇒ Object
response_body
,response_object
, anddeserialized_response
are deprecated in favor ofbody
. - #response_object ⇒ Object
Methods included from Modules::InternalAttributes
Methods included from Modules::HTTP
#create, #delete, #get, initialize_http_client!, #patch, #post, #put, #update
Constructor Details
#initialize(opts = {}) ⇒ HyperResource
Create a new HyperResource, given a hash of options. These options include:
- root
-
The root URL of the resource.
- auth
-
Authentication information. Currently only {basic: [‘key’, ‘secret’]} is supported.
- namespace
-
Class or class name, into which resources should be instantiated.
- headers
-
Headers to send along with requests for this resource (as well as its eventual child resources, if any).
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/hyper_resource.rb', line 49 def initialize(opts={}) return init_from_resource(opts) if opts.kind_of?(HyperResource) self.root = opts[:root] || self.class.root self.href = opts[:href] || '' self.auth = (self.class.auth || {}).merge(opts[:auth] || {}) self.namespace = opts[:namespace] || self.class.namespace self.headers = DEFAULT_HEADERS.merge(self.class.headers || {}). merge(opts[:headers] || {}) ## There's a little acrobatics in getting Attributes, Links, and Objects ## into the correct subclass. if self.class != HyperResource if self.class::Attributes == HyperResource::Attributes Object.module_eval( "class #{self.class}::Attributes < HyperResource::Attributes; end" ) end if self.class::Links == HyperResource::Links Object.module_eval( "class #{self.class}::Links < HyperResource::Links; end" ) end if self.class::Objects == HyperResource::Objects Object.module_eval( "class #{self.class}::Objects < HyperResource::Objects; end" ) end end self.attributes = self.class::Attributes.new(self) self.links = self.class::Links.new(self) self.objects = self.class::Objects.new(self) self.loaded = false self.adapter = opts[:adapter] || self.class.adapter || HyperResource::Adapter::HAL_JSON end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args) ⇒ Object
method_missing will load this resource if not yet loaded, then attempt to delegate to attributes
, then objects
, then links
. Override with care.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/hyper_resource.rb', line 143 def method_missing(method, *args) self.get unless self.loaded method = method.to_s if method[-1,1] == '=' return attributes[method[0..-2]] = args.first if attributes[method[0..-2]] else return attributes[method] if attributes && attributes.has_key?(method) return objects[method] if objects && objects[method] if links && links[method] if args.count > 0 return links[method].where(*args) else return links[method] end end end raise NoMethodError, "undefined method `#{method}' for #{self.inspect}" end |
Class Method Details
.get_data_type_from_response(response) ⇒ Object
Inspects the given Faraday::Response, and returns a string describing this resource’s data type.
By default, this method looks for a type=… modifier in the response’s Content-type
and returns that value, capitalized.
Override this method in a subclass to alter HyperResource’s behavior.
257 258 259 260 261 262 |
# File 'lib/hyper_resource.rb', line 257 def self.get_data_type_from_response(response) return nil unless response return nil unless content_type = response['content-type'] return nil unless m=content_type.match(/;\s* type=([0-9A-Za-z:]+)/x) m[1][0,1].upcase + m[1][1..-1] end |
.namespaced_class(type_name, namespace) ⇒ Object
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/hyper_resource.rb', line 225 def self.namespaced_class(type_name, namespace) class_name = "#{namespace}::#{type_name}" class_name.gsub!(/[^_0-9A-Za-z:]/, '') ## sanitize class_name ## Return data type class if it exists klass = eval(class_name) rescue :sorry_dude return klass if klass.is_a?(Class) ## Data type class didn't exist -- create namespace (if necessary), ## then the data type class if namespace != '' nsc = eval(namespace) rescue :bzzzzzt unless nsc.is_a?(Class) Object.module_eval "class #{namespace} < #{self}; end" end end Object.module_eval "class #{class_name} < #{namespace}; end" eval(class_name) end |
.response_class(response, namespace) ⇒ Object
Returns the class into which the given response should be cast. If the object is not loaded yet, or if namespace
is not set, returns self
.
Otherwise, response_class
uses get_data_type_from_response
to determine subclass name, glues it to the given namespace, and creates the class if it’s not there yet. E.g., given a namespace of FooAPI
and a response content-type of “application/vnd.foocorp.fooapi.v1+json;type=User”, this should return FooAPI::User
(even if FooAPI::User
hadn’t existed yet).
212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/hyper_resource.rb', line 212 def self.response_class(response, namespace) if self.to_s == 'HyperResource' return self unless namespace end namespace ||= self.to_s type_name = self.get_data_type_from_response(response) return self unless type_name namespaced_class(type_name, namespace) end |
Instance Method Details
#[](i) ⇒ Object
Returns the *i*th object in the first collection of objects embedded in this resource. Returns nil on failure.
126 127 128 129 |
# File 'lib/hyper_resource.rb', line 126 def [](i) get unless loaded self.objects.first[1][i] end |
#_hr_new_from_link(href) ⇒ Object
Return a new HyperResource based on this object and a given href.
192 193 194 195 196 197 198 199 |
# File 'lib/hyper_resource.rb', line 192 def _hr_new_from_link(href) # @private self.class.new(:root => self.root, :auth => self.auth, :headers => self.headers, :namespace => self.namespace, :token => self.token, :href => href) end |
#_hr_response_class ⇒ Object
245 246 247 248 |
# File 'lib/hyper_resource.rb', line 245 def _hr_response_class # @private self.namespace ||= self.class.to_s unless self.class.to_s=='HyperResource' self.class.response_class(self.response, self.namespace) end |
#changed?(*args) ⇒ Boolean
Returns true if one or more of this object’s attributes has been reassigned.
92 93 94 |
# File 'lib/hyper_resource.rb', line 92 def changed?(*args) attributes.changed?(*args) end |
#deserialized_response ⇒ Object
183 184 185 186 187 |
# File 'lib/hyper_resource.rb', line 183 def deserialized_response # @private _hr_deprecate('HyperResource#deserialized_response is deprecated. '+ 'Please use HyperResource#body instead.') body end |
#each(&block) ⇒ Object
Iterates over the objects in the first collection of embedded objects in this resource.
133 134 135 136 |
# File 'lib/hyper_resource.rb', line 133 def each(&block) get unless loaded self.objects.first[1].each(&block) end |
#get_data_type_from_response ⇒ Object
Uses HyperResource.get_response_data_type
to determine the proper data type for this object. Override to change behavior (though you probably just want to override the class method).
267 268 269 |
# File 'lib/hyper_resource.rb', line 267 def get_data_type_from_response self.class.get_data_type_from_response(self.response) end |
#incoming_body_filter(attr_hash) ⇒ Object
incoming_body_filter
filters a hash of attribute keys and values on their way from a response body to a HyperResource. Override this in a subclass of HyperResource to implement filters on incoming data.
102 103 104 |
# File 'lib/hyper_resource.rb', line 102 def incoming_body_filter(attr_hash) attr_hash end |
#inspect ⇒ Object
165 166 167 168 169 |
# File 'lib/hyper_resource.rb', line 165 def inspect # @private "#<#{self.class}:0x#{"%x" % self.object_id} @root=#{self.root.inspect} "+ "@href=#{self.href.inspect} @loaded=#{self.loaded} "+ "@namespace=#{self.namespace.inspect} ...>" end |
#outgoing_body_filter(attr_hash) ⇒ Object
outgoing_body_filter
filters a hash of attribute keys and values on their way from a HyperResource to a request body. Override this in a subclass of HyperResource to implement filters on outgoing data.
109 110 111 |
# File 'lib/hyper_resource.rb', line 109 def outgoing_body_filter(attr_hash) attr_hash end |
#outgoing_uri_filter(attr_hash) ⇒ Object
outgoing_uri_filter
filters a hash of attribute keys and values on their way from a HyperResource to a URL. Override this in a subclass of HyperResource to implement filters on outgoing URI parameters.
117 118 119 |
# File 'lib/hyper_resource.rb', line 117 def outgoing_uri_filter(attr_hash) attr_hash end |
#response_body ⇒ Object
response_body
, response_object
, and deserialized_response
are deprecated in favor of +body+. (Sorry. Naming things is hard.)
173 174 175 176 177 |
# File 'lib/hyper_resource.rb', line 173 def response_body # @private _hr_deprecate('HyperResource#response_body is deprecated. '+ 'Please use HyperResource#body instead.') body end |
#response_object ⇒ Object
178 179 180 181 182 |
# File 'lib/hyper_resource.rb', line 178 def response_object # @private _hr_deprecate('HyperResource#response_object is deprecated. '+ 'Please use HyperResource#body instead.') body end |