lib/zendesk_api/collection.rb in zendesk_api-0.2.6 vs lib/zendesk_api/collection.rb in zendesk_api-0.3.0

- old
+ new

@@ -25,36 +25,25 @@ # Additional options are: verb (default: GET), path (default: resource param), page, per_page. # @param [Client] client The {Client} to use. # @param [String] resource The resource being collected. # @param [Hash] options Any additional options to be passed in. def initialize(client, resource, options = {}) - @client, @resource = client, resource.resource_name + @client, @resource_class, @resource = client, resource, resource.resource_name @options = Hashie::Mash.new(options) - @verb = @options.delete(:verb) - @collection_path = @options.delete(:collection_path) + set_association_from_options + join_special_params - association_options = { :path => @options.delete(:path) } - association_options[:path] ||= @collection_path.join("/") if @collection_path - @association = @options.delete(:association) || Association.new(association_options.merge(:class => resource)) - - # some params use comma-joined strings instead of query-based arrays for multiple values - @options.each do |k, v| - if SPECIALLY_JOINED_PARAMS.include?(k.to_sym) && v.is_a?(Array) - @options[k] = v.join(',') - end - end - - @collection_path ||= [@resource] - @resource_class = resource - @fetchable = true + @verb = @options.delete(:verb) @includes = Array(@options.delete(:include)) # Used for Attachments, TicketComment if @resource_class.is_a?(Class) && @resource_class.superclass == ZendeskAPI::Data @resources = [] @fetchable = false + else + @fetchable = true end end # Passes arguments and the proper path to the resource class method. # @param [Hash] attributes Attributes to pass to Create#create @@ -156,43 +145,20 @@ end # Executes actual GET from API and loads resources into proper class. # @param [Boolean] reload Whether to disregard cache def fetch(reload = false) - return @resources if @resources && (!@fetchable || !reload) - - if association && association.options.parent && association.options.parent.new_record? + if @resources && (!@fetchable || !reload) + return @resources + elsif association && association.options.parent && association.options.parent.new_record? return @resources = [] end - if @query - path = @query - @query = nil - else - path = self.path - end + @response = get_response(@query || self.path) + handle_response(@response.body.dup) - @response = @client.connection.send(@verb || "get", path) do |req| - opts = @options.delete_if {|k, v| v.nil?} - - req.params.merge!(:include => @includes.join(",")) if @includes.any? - - if %w{put post}.include?(@verb.to_s) - req.body = opts - else - req.params.merge!(opts) - end - end - - body = @response.body.dup - - results = body.delete(@resource_class.model_key) || body.delete("results") - @resources = results.map {|res| @resource_class.new(@client, res)} - - set_page_and_count(body) - set_includes(@resources, @includes, body) - + @query = nil @resources end rescue_client_error :fetch, :with => lambda { Array.new } @@ -236,12 +202,11 @@ # * Otherwise, returns an empty array. def next if @options["page"] clear_cache @options["page"] += 1 - elsif @next_page - @query = @next_page + elsif @query = @next_page fetch(true) else clear_cache @resources = [] end @@ -253,12 +218,11 @@ # * Otherwise, returns an empty array. def prev if @options["page"] && @options["page"] > 1 clear_cache @options["page"] -= 1 - elsif @prev_page - @query = @prev_page + elsif @query = @prev_page fetch(true) else clear_cache @resources = [] end @@ -275,20 +239,16 @@ # @private def to_ary; nil; end # Sends methods to underlying array of resources. def method_missing(name, *args, &block) - methods = @resource_class.singleton_methods(false).map(&:to_sym) - - if methods.include?(name) - @resource_class.send(name, @client, *args, &block) + if resource_methods.include?(name) + collection_method(name, *args, &block) elsif Array.new.respond_to?(name) - to_a.send(name, *args, &block) + array_method(name, *args, &block) else - opts = args.last.is_a?(Hash) ? args.last : {} - opts.merge!(:collection_path => @collection_path.dup.push(name)) - self.class.new(@client, @resource_class, @options.merge(opts)) + next_collection(name, *args, &block) end end # @private def to_s @@ -313,8 +273,73 @@ if @next_page =~ /page=(\d+)/ @options["page"] = $1.to_i - 1 elsif @prev_page =~ /page=(\d+)/ @options["page"] = $1.to_i + 1 end + end + + ## Initialize + + def join_special_params + # some params use comma-joined strings instead of query-based arrays for multiple values + @options.each do |k, v| + if SPECIALLY_JOINED_PARAMS.include?(k.to_sym) && v.is_a?(Array) + @options[k] = v.join(',') + end + end + end + + def set_association_from_options + @collection_path = @options.delete(:collection_path) + + association_options = { :path => @options.delete(:path) } + association_options[:path] ||= @collection_path.join("/") if @collection_path + @association = @options.delete(:association) || Association.new(association_options.merge(:class => @resource_class)) + + @collection_path ||= [@resource] + end + + ## Fetch + + def get_response(path) + @response = @client.connection.send(@verb || "get", path) do |req| + opts = @options.delete_if {|_, v| v.nil?} + + req.params.merge!(:include => @includes.join(",")) if @includes.any? + + if %w{put post}.include?(@verb.to_s) + req.body = opts + else + req.params.merge!(opts) + end + end + end + + def handle_response(body) + results = body.delete(@resource_class.model_key) || body.delete("results") + @resources = results.map {|res| @resource_class.new(@client, res)} + + set_page_and_count(body) + set_includes(@resources, @includes, body) + end + + ## Method missing + + def array_method(name, *args, &block) + to_a.send(name, *args, &block) + end + + def next_collection(name, *args, &block) + opts = args.last.is_a?(Hash) ? args.last : {} + opts.merge!(:collection_path => @collection_path.dup.push(name)) + self.class.new(@client, @resource_class, @options.merge(opts)) + end + + def collection_method(name, *args, &block) + @resource_class.send(name, @client, *args, &block) + end + + def resource_methods + @resource_methods ||= @resource_class.singleton_methods(false).map(&:to_sym) end end end