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