lib/finix/pagination.rb in finix-0.15 vs lib/finix/pagination.rb in finix-0.16

- old
+ new

@@ -1,80 +1,169 @@ require 'cgi' +require 'ostruct' require_relative 'hal_resource' +require_relative 'indifferent_hash' module Finix class Pagination - include Enumerable + include ::Enumerable include HalResource attr_accessor :resource_class + attr_reader :attributes + attr_reader :hyperlinks - def initialize(href, opts={}) - @hyperlinks = {} - @attributes = {} + def initialize(*args) + opts = args.slice!(0) || {} + href = opts.delete(:href) + @hyperlinks = Finix::Utils.eval_class(self, IndifferentHash).new @hyperlinks[:self] = href + @attributes = {} @resource_class = nil + extract_opts opts end + def init!(*args) + opts = args.slice(0) || {} + extract_opts opts + self + end + def each return enum_for :each unless block_given? - current + fetch_first loop do items.each { |item| yield item } fetch :next end end - def current - refresh unless items - items + def count(*args) + refresh # always refresh to get last items + return super *args if block_given? + self.send :method_missing, :count, args end - def fetch(scope) # :next, :last, :first, :prev, :self - scope = scope.to_s.to_sym + def fetch(scope = nil) # :next, :last, :first, :prev, :self + opts = {} + if scope.is_a? Hash + opts = Finix::Utils.indifferent_read_access scope + scope = nil + end + + scope = :self if scope.nil? + scope = scope.to_s.to_sym unless scope.nil? if @hyperlinks[scope] - load_from @hyperlinks[scope] + load_from @hyperlinks[scope], opts return self.items end raise StopIteration end + alias retrieve fetch + def refresh - fetch :self + fetch + self end def create(attrs={}) - attrs = attrs.attributes if attrs.is_a?(Finix::Resource) + attrs = attrs.attributes if attrs.is_a?(Resource) attrs = Finix::Utils.indifferent_read_access attrs + href = @hyperlinks[:self] @resource_class = Finix.from_hypermedia_registry href, attrs - @resource_class.new(attrs, href).save + + attrs[:href] = href + @resource_class.new(attrs).save end private - def load_from(url, params = {}) - params ||= {} + def fetch_first + @attributes['page']['offset'] = 0 unless @attributes['page']['offset'].nil? + fetch(@hyperlinks[:first] ? :first : nil) + end - response = Finix.get url, params - body = Finix::Utils.indifferent_read_access response.body + def extract_opts(opts={}) + opts = Finix::Utils.indifferent_read_access opts + limit = opts.delete('limit') + offset = opts.delete('offset') + @attributes['page'] = @attributes['page'] || {} + @attributes['page']['limit'] = limit unless limit.nil? + @attributes['page']['offset'] = offset unless offset.nil? + @attributes.merge! opts unless opts.empty? - links = body.delete('_links') - links.each { |key, link| @hyperlinks[key.to_sym] = link[:href] } + if not limit.nil? or not offset.nil? # reset @hyperlinks + @hyperlinks.reject! {|k, v| k.to_s != 'self'} + parsed_url = URI.parse(@hyperlinks[:self]) + parsed_url.query = nil + @hyperlinks[:self] = parsed_url.to_s + end + end - @attributes = {} # clear attributes - if body.has_key? '_embedded' - resource_name, resources = body.delete('_embedded').first - @resource_class = Finix.from_hypermedia_registry resource_name - @attributes['items'] = resources.map do |attrs| - cls = Finix.from_hypermedia_registry resource_name, attrs - cls.construct_from_response attrs - end - @attributes['page'] = body.delete('page') + def load_from(url, opts = {}) + parsed_url = URI.parse(url) + + params = {} + params.merge! @attributes['page'] if @attributes.has_key? 'page' + params.merge! parse_query(parsed_url.query) + parsed_url.query = nil # remove query + + # params page + opts ||= {} + page = opts.delete('page') + unless page.nil? + page = Finix::Utils.indifferent_read_access page + params.merge! page unless page.nil? end + + params.merge! opts unless opts.empty? + params.delete('count') # remove count from previous query + + response = Finix.get parsed_url.to_s, params + load_page_from_response! response + # body = Finix::Utils.indifferent_read_access response.body + # + # @hyperlinks = Finix::Utils.eval_class(self, IndifferentHash).new + # links = body.delete('_links') + # links.each { |key, link| @hyperlinks[key.to_sym] = link[:href] } + # + # @attributes = {'items' => [], 'page' => body.delete('page')} # clear attributes + # if body.has_key? '_embedded' + # resource_name, resources = body.delete('_embedded').first + # @resource_class = Finix.from_hypermedia_registry resource_name + # @attributes['items'] = resources.map do |attrs| + # cls = Finix.from_hypermedia_registry resource_name, attrs + # cls.construct_from_response attrs + # end + # end end + # Stolen from Mongrel, with some small modifications: + # Parses a query string by breaking it up at the '&' + # and ';' characters. You can also use this to parse + # cookies by changing the characters used in the second + # parameter (which defaults to '&;'). + def parse_query(qs, d = nil) + params = {} + (qs || '').split(d ? /[#{d}] */n : /[&;] */n).each do |p| + k, v = p.split('=', 2).map { |x| CGI::unescape(x) } + if (cur = params[k]) + if cur.class == Array + params[k] << v + else + params[k] = [cur, v] + end + else + params[k] = v + end + end + + params + end end -end \ No newline at end of file +end +