class HyperResource

HyperResource is the main resource base class. Normally it will be used through subclassing, though it may also be used directly.

Constants

DEFAULT_HEADERS
VERSION
VERSION_DATE

Public Class Methods

get_data_type_from_response(response) click to toggle source

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.

# 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) click to toggle source
# 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
new(opts={}) click to toggle source

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

# 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
response_class(response, namespace) click to toggle source

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

# 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

Private Class Methods

_hr_deprecate(message) click to toggle source

Show a deprecation message.

# File lib/hyper_resource.rb, line 290
def self._hr_deprecate(message) # @private
  STDERR.puts "#{message} (called from #{caller[2]})"
end

Public Instance Methods

[](i) click to toggle source

Returns the *i*th object in the first collection of objects embedded in this resource. Returns nil on failure.

# File lib/hyper_resource.rb, line 126
def [](i)
  get unless loaded
  self.objects.first[1][i]
end
_hr_response_class() click to toggle source
# 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) click to toggle source

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

# File lib/hyper_resource.rb, line 92
def changed?(*args)
  attributes.changed?(*args)
end
deserialized_response() click to toggle source
# 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) click to toggle source

Iterates over the objects in the first collection of embedded objects in this resource.

# 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() click to toggle source

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

# 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) click to toggle source

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.

# File lib/hyper_resource.rb, line 102
def incoming_body_filter(attr_hash)
  attr_hash
end
inspect() click to toggle source
# 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
method_missing(method, *args) click to toggle source

method_missing will load this resource if not yet loaded, then attempt to delegate to attributes, then objects, then links. Override with care.

# 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
outgoing_body_filter(attr_hash) click to toggle source

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.

# File lib/hyper_resource.rb, line 109
def outgoing_body_filter(attr_hash)
  attr_hash
end
outgoing_uri_filter(attr_hash) click to toggle source

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.

# File lib/hyper_resource.rb, line 117
def outgoing_uri_filter(attr_hash)
  attr_hash
end
response_body() click to toggle source

response_body, response_object, and deserialized_response

are deprecated in favor of +body+.  (Sorry. Naming things is hard.)
# 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() click to toggle source
# 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

Private Instance Methods

_hr_deprecate(*args) click to toggle source
# File lib/hyper_resource.rb, line 294
def _hr_deprecate(*args) # @private
  self.class._hr_deprecate(*args)
end
init_from_resource(resource) click to toggle source

Use the given resource's data to initialize this one.

# File lib/hyper_resource.rb, line 281
def init_from_resource(resource)
  (self.class._hr_attributes - [:attributes, :links, :objects]).each do |attr|
    self.send("#{attr}=".to_sym, resource.send(attr))
  end
  self.adapter.apply(self.body, self)
end
to_response_class() click to toggle source

Return this object, “cast” into its proper response class.

# File lib/hyper_resource.rb, line 274
def to_response_class
  response_class = self._hr_response_class
  return self if self.class == response_class
  response_class.new(self)
end