Class: HyperResource

Inherits:
Object
  • Object
show all
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/exceptions.rb,
lib/hyper_resource/modules/http.rb,
lib/hyper_resource/adapter/hal_json.rb

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.5'
VERSION_DATE =
'2013-10-11'

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Modules::HTTP

#create, #delete, #faraday_connection, #get, #post, #put, #update

Methods included from Modules::Utils

included

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).



69
70
71
72
73
74
75
76
77
78
79
80
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
# File 'lib/hyper_resource.rb', line 69

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.

Raises:

  • (NoMethodError)


152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/hyper_resource.rb', line 152

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[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_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).



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/hyper_resource.rb', line 210

def self._get_response_class(response, namespace) # :nodoc:
  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.



253
254
255
256
257
258
# File 'lib/hyper_resource.rb', line 253

def self._get_response_data_type(response) # :nodoc:
  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

Instance Method Details

#[](i) ⇒ Object

Returns the *i*th object in the first collection of objects embedded in this resource. Equivalent to self.objects[i].



147
# File 'lib/hyper_resource.rb', line 147

def [](i); self.objects.ith(i) end

#_get_response_classObject

:nodoc:



239
240
241
242
# File 'lib/hyper_resource.rb', line 239

def _get_response_class # :nodoc:
  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_typeObject

:nodoc:



260
261
262
# File 'lib/hyper_resource.rb', line 260

def _get_response_data_type # :nodoc:
  self.class._get_response_data_type(self.response)
end

Return a new HyperResource based on this object and a given href.



190
191
192
193
194
195
196
# File 'lib/hyper_resource.rb', line 190

def _new_from_link(href) # :nodoc:
  self.class.new(:root    => self.root,
                 :auth    => self.auth,
                 :headers => self.headers,
                 :namespace => self.namespace,
                 :href    => href)
end

#changed?(*args) ⇒ Boolean

Returns true if one or more of this object’s attributes has been reassigned.

Returns:

  • (Boolean)


114
115
116
# File 'lib/hyper_resource.rb', line 114

def changed?(*args)
  attributes.changed?(*args)
end

#firstObject

Returns the first object in the first collection of objects embedded in this resource. Equivalent to self.objects.first.



143
# File 'lib/hyper_resource.rb', line 143

def first; self.objects.first 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.



121
122
123
# File 'lib/hyper_resource.rb', line 121

def incoming_body_filter(attr_hash)
  attr_hash
end

#inspectObject

:nodoc:



174
175
176
177
178
# File 'lib/hyper_resource.rb', line 174

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_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.



128
129
130
# File 'lib/hyper_resource.rb', line 128

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.



136
137
138
# File 'lib/hyper_resource.rb', line 136

def outgoing_uri_filter(attr_hash)
  attr_hash
end

#response_bodyObject

response_body is deprecated in favor of response_object.



181
# File 'lib/hyper_resource.rb', line 181

def response_body; response_object end