lib/flexirest/lazy_association_loader.rb
require 'active_support/hash_with_indifferent_access'
module Flexirest
class LazyAssociationLoader
include Enumerable
def initialize(name, value, request, options = {})
@name = name
class_to_map = request.method[:options][:lazy][name] rescue nil
@request = class_to_map.nil? ? request : Flexirest::Request.new(class_to_map._mapped_method(:find), class_to_map.new, options)
@object = nil
@options = options
if value.is_a? Array
@subloaders = value.map {|url| LazyAssociationLoader.new(name, url, request, options)}
elsif value.is_a?(Hash) && (value.has_key?("url") || value.has_key?(:url))
@url = (value["url"] || value[:url])
elsif value.is_a?(Hash) && (value.has_key?("href") || value.has_key?(:href)) # HAL
@url = (value["href"] || value[:href])
@_hal_attributes = HashWithIndifferentAccess.new(value)
elsif value.is_a?(Hash)
mapped = {}
value.each do |k,v|
mapped[k.to_sym] = LazyAssociationLoader.new(name, v, request, options)
end
@subloaders = mapped
# Need to also ensure that the hash/wrapped object is returned when the property is accessed
elsif value.is_a? String
@url = value
else
raise InvalidLazyAssociationContentException.new("Invalid content for #{@name}, expected Array, String or Hash containing 'url' key")
end
end
def _hal_attributes(key)
@_hal_attributes[key]
end
def size
if @subloaders
@subloaders.size
else
ensure_lazy_loaded
@object.size
end
end
def each
if @subloaders
if @subloaders.is_a? Array
@subloaders.each do |loader|
yield loader
end
elsif @subloaders.is_a? Hash
@subloaders.each do |key, value|
yield key, value
end
end
else
ensure_lazy_loaded
if @object.is_a? Flexirest::Base
@object.each do |key, value|
yield key, value
end
else
@object.each do |obj|
yield obj
end
end
end
end
def keys
@subloaders.keys
end
def method_missing(name, *args)
if @subloaders.is_a? Hash
return @subloaders[name.to_sym]
end
ensure_lazy_loaded
if @object
@object.send(name, *args)
end
end
private
def ensure_lazy_loaded
if @object.nil?
method = MultiJson.load(MultiJson.dump(@request.method),:symbolize_keys => true)
method[:method] = :get
method[:options][:url] = @url
method[:options][:overridden_name] = @options[:overridden_name]
request = Flexirest::Request.new(method, @request.object)
request.url = request.forced_url = @url
@object = request.call
if @object.respond_to?(:_parent=)
@object._parent = @options[:parent]
@object._parent_attribute_name = @options[:parent_attribute_name]
end
end
end
end
class InvalidLazyAssociationContentException < Exception ; end
end