Class: HyperResource
- Inherits:
-
Object
- Object
- HyperResource
- Includes:
- Modules::HTTP, Modules::Utils
- 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/adapter/hal_json.rb
Overview
TODO: incoming_filter, outgoing_filter as_json, to_json (in adapter?) save, update, create, delete
Defined Under Namespace
Modules: Modules Classes: Adapter, Attributes, ClientError, Exception, Link, Links, Objects, Response, ResponseError, ServerError
Constant Summary collapse
- DEFAULT_HEADERS =
:nodoc:
{ 'Accept' => 'application/json' }
- VERSION =
'0.1.9'- VERSION_DATE =
'2013-09-27'
Class Method Summary collapse
- ._hr_attributes ⇒ Object
- ._hr_class_attributes ⇒ Object
-
.get_response_class(response, namespace) ⇒ Object
Returns the class into which the given response should be cast.
-
.get_response_data_type(response) ⇒ Object
Inspects the given response, and returns a string describing this resource's data type.
Instance Method Summary collapse
-
#[](i) ⇒ Object
Returns the ith object in the first collection of objects embedded in this resource.
-
#_new_from_link(href) ⇒ Object
Returns a new HyperResource based on the given link href.
- #changed?(*args) ⇒ Boolean
-
#first ⇒ Object
Returns the first object in the first collection of objects embedded in this resource.
- #get_response_class ⇒ Object
- #get_response_data_type ⇒ Object
- #incoming_filter(attr_hash) ⇒ Object
-
#initialize(opts = {}) ⇒ HyperResource
constructor
Create a new HyperResource, given a hash of options.
-
#inspect ⇒ Object
:nodoc:.
-
#method_missing(method, *args) ⇒ Object
method_missing will load this resource if not yet loaded, then attempt to delegate to
attributes, thenobjects, thenlinks. - #outgoing_filter(attr_hash) ⇒ Object
-
#response_body ⇒ Object
response_bodyis deprecated in favor ofresponse_object. - #to_response_class ⇒ Object
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).
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/hyper_resource.rb', line 81 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.
236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/hyper_resource.rb', line 236 def method_missing(method, *args) self.get unless self.loaded method = method.to_s if method[-1] == '=' return attributes[method[0..-2]] = args.first if attributes[method[0..-2]] else return attributes[method] if attributes && attributes[method] return objects[method] if objects && objects[method] return links[method] if links && links[method] end raise NoMethodError, "undefined method `#{method}' for #{self.inspect}" end |
Class Method Details
._hr_attributes ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/hyper_resource.rb', line 37 def self._hr_attributes [ :root, :href, :auth, :headers, :namespace, :adapter, :request, :response, :response_object, :attributes, :links, :objects, :loaded ] end |
._hr_class_attributes ⇒ Object
28 29 30 31 32 33 34 35 |
# File 'lib/hyper_resource.rb', line 28 def self._hr_class_attributes [ :root, ## e.g. 'https://example.com/api/v1' :auth, ## e.g. {:basic => ['username', 'password']} :headers, ## e.g. {'Accept' => 'application/vnd.example+json'} :namespace, ## e.g. 'ExampleAPI', or the class ExampleAPI itself :adapter ## subclass of HR::Adapter ] end |
.get_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 opts[:namespace] is
not set, returns self.
Otherwise, get_response_class uses get_response_data_type 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).
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/hyper_resource.rb', line 175 def self.get_response_class(response, namespace) if self.to_s == 'HyperResource' return self unless namespace end namespace ||= self.to_s type_name = self.get_response_data_type(response) return self unless type_name 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 |
.get_response_data_type(response) ⇒ Object
Inspects the given 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.
217 218 219 220 221 222 |
# File 'lib/hyper_resource.rb', line 217 def self.get_response_data_type(response) return nil unless response return nil unless content_type = response['content-type'] return nil unless m=content_type.match(/;\s* type=(?<type> [0-9A-Za-z:]+)/x) m[:type][0].upcase + m[:type][1..-1] end |
Instance Method Details
#[](i) ⇒ Object
Returns the ith object in the first collection of objects embedded
in this resource. Equivalent to self.objects[i].
232 |
# File 'lib/hyper_resource.rb', line 232 def [](i); self.objects.ith(i) end |
#_new_from_link(href) ⇒ Object
Returns a new HyperResource based on the given link href.
137 138 139 140 141 142 143 |
# File 'lib/hyper_resource.rb', line 137 def _new_from_link(href) self.class.new(:root => self.root, :auth => self.auth, :headers => self.headers, :namespace => self.namespace, :href => href) end |
#changed?(*args) ⇒ Boolean
132 133 134 |
# File 'lib/hyper_resource.rb', line 132 def changed?(*args) attributes.changed?(*args) end |
#first ⇒ Object
Returns the first object in the first collection of objects embedded
in this resource. Equivalent to self.objects.first.
228 |
# File 'lib/hyper_resource.rb', line 228 def first; self.objects.first end |
#get_response_class ⇒ Object
159 160 161 162 |
# File 'lib/hyper_resource.rb', line 159 def get_response_class self.namespace ||= self.class.to_s unless self.class.to_s=='HyperResource' self.class.get_response_class(self.response, self.namespace) end |
#get_response_data_type ⇒ Object
205 206 207 |
# File 'lib/hyper_resource.rb', line 205 def get_response_data_type self.class.get_response_data_type(self.response) end |
#incoming_filter(attr_hash) ⇒ Object
151 152 153 |
# File 'lib/hyper_resource.rb', line 151 def incoming_filter(attr_hash) attr_hash end |
#inspect ⇒ Object
:nodoc:
252 253 254 255 256 |
# File 'lib/hyper_resource.rb', line 252 def inspect # :nodoc: "#<#{self.class}:0x#{"%x" % self.object_id} @root=#{self.root.inspect} "+ "@href=#{self.href.inspect} @loaded=#{self.loaded} "+ "@namespace=#{self.namespace.inspect} ...>" end |
#outgoing_filter(attr_hash) ⇒ Object
155 156 157 |
# File 'lib/hyper_resource.rb', line 155 def outgoing_filter(attr_hash) attr_hash end |
#response_body ⇒ Object
response_body is deprecated in favor of response_object.
259 |
# File 'lib/hyper_resource.rb', line 259 def response_body; response_object end |
#to_response_class ⇒ Object
145 146 147 148 149 |
# File 'lib/hyper_resource.rb', line 145 def to_response_class response_class = self.get_response_class return self if self.class == response_class response_class.new(self) end |