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
+