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
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.4'
- VERSION_DATE =
'2014-04-02'
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, #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}}.
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 88 89 90 91 |
# File 'lib/hyper_resource.rb', line 51 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.
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/hyper_resource.rb', line 147 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.
262 263 264 265 266 267 |
# File 'lib/hyper_resource.rb', line 262 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
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/hyper_resource.rb', line 229 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).
216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/hyper_resource.rb', line 216 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.
130 131 132 133 |
# File 'lib/hyper_resource.rb', line 130 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.
196 197 198 199 200 201 202 203 |
# File 'lib/hyper_resource.rb', line 196 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., :href => href) end |
#_hr_response_class ⇒ Object
249 250 251 252 |
# File 'lib/hyper_resource.rb', line 249 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.
96 97 98 |
# File 'lib/hyper_resource.rb', line 96 def changed?(*args) attributes.changed?(*args) end |
#deserialized_response ⇒ Object
187 188 189 190 191 |
# File 'lib/hyper_resource.rb', line 187 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.
137 138 139 140 |
# File 'lib/hyper_resource.rb', line 137 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).
272 273 274 |
# File 'lib/hyper_resource.rb', line 272 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.
106 107 108 |
# File 'lib/hyper_resource.rb', line 106 def incoming_body_filter(attr_hash) attr_hash end |
#inspect ⇒ Object
169 170 171 172 173 |
# File 'lib/hyper_resource.rb', line 169 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.
113 114 115 |
# File 'lib/hyper_resource.rb', line 113 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.
121 122 123 |
# File 'lib/hyper_resource.rb', line 121 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.)
177 178 179 180 181 |
# File 'lib/hyper_resource.rb', line 177 def response_body # @private _hr_deprecate('HyperResource#response_body is deprecated. '+ 'Please use HyperResource#body instead.') body end |
#response_object ⇒ Object
182 183 184 185 186 |
# File 'lib/hyper_resource.rb', line 182 def response_object # @private _hr_deprecate('HyperResource#response_object is deprecated. '+ 'Please use HyperResource#body instead.') body end |