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::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_typeto determine the proper data type for this object. -
#incoming_body_filter(attr_hash) ⇒ Object
incoming_body_filterfilters 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_filterfilters 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_filterfilters a hash of attribute keys and values on their way from a HyperResource to a URL. -
#response_body ⇒ Object
response_body,response_object, anddeserialized_responseare deprecated in favor ofbody. - #response_object ⇒ Object
Methods included from Modules::InternalAttributes
Methods included from Modules::HTTP
#create, #delete, #faraday_connection, #get, #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).
- faraday_options
-
Configuration passed to
Faraday::Connection.initialize, such as {request: {timeout: 30}}.
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 88 89 90 91 92 |
# File 'lib/hyper_resource.rb', line 52 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] || {}) self. = opts[:faraday_options] || self.class. || {} ## 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.
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/hyper_resource.rb', line 148 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.
264 265 266 267 268 269 |
# File 'lib/hyper_resource.rb', line 264 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
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/hyper_resource.rb', line 231 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).
218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/hyper_resource.rb', line 218 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.
131 132 133 134 |
# File 'lib/hyper_resource.rb', line 131 def [](i) get unless loaded self.objects.first[1][i] rescue nil end |
#_hr_new_from_link(href) ⇒ Object
Return a new HyperResource based on this object and a given href.
197 198 199 200 201 202 203 204 205 |
# File 'lib/hyper_resource.rb', line 197 def _hr_new_from_link(href) # @private self.class.new(:root => self.root, :auth => self.auth, :headers => self.headers, :namespace => self.namespace, :faraday_options => self., :token => self.token, :href => href) end |
#_hr_response_class ⇒ Object
251 252 253 254 |
# File 'lib/hyper_resource.rb', line 251 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.
97 98 99 |
# File 'lib/hyper_resource.rb', line 97 def changed?(*args) attributes.changed?(*args) end |
#deserialized_response ⇒ Object
188 189 190 191 192 |
# File 'lib/hyper_resource.rb', line 188 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.
138 139 140 141 |
# File 'lib/hyper_resource.rb', line 138 def each(&block) get unless loaded self.objects.first[1].each(&block) rescue nil 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).
274 275 276 |
# File 'lib/hyper_resource.rb', line 274 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.
107 108 109 |
# File 'lib/hyper_resource.rb', line 107 def incoming_body_filter(attr_hash) attr_hash end |
#inspect ⇒ Object
170 171 172 173 174 |
# File 'lib/hyper_resource.rb', line 170 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.
114 115 116 |
# File 'lib/hyper_resource.rb', line 114 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.
122 123 124 |
# File 'lib/hyper_resource.rb', line 122 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.)
178 179 180 181 182 |
# File 'lib/hyper_resource.rb', line 178 def response_body # @private _hr_deprecate('HyperResource#response_body is deprecated. '+ 'Please use HyperResource#body instead.') body end |
#response_object ⇒ Object
183 184 185 186 187 |
# File 'lib/hyper_resource.rb', line 183 def response_object # @private _hr_deprecate('HyperResource#response_object is deprecated. '+ 'Please use HyperResource#body instead.') body end |