module PageUp class Fragment NullResult = 'NullResult' def initialize fragment, page, per_page, total = nil @page = page @per_page = per_page @size = total || (fragment.size + offset) @fragment = [].fill(NullResult, 0, offset) + fragment end attr_reader :size def [] range until covers? range next_page = page_for(range) result = @callback.call next_page, @per_page @per_page.times do |index| value = result[index] @fragment[index + offset(next_page)] = value end end @fragment[range].compact end def to_a self[0..@size].to_a end def use &block @callback = block end private def page_for range first_null = range.find { |index| @fragment.fetch(index,NullResult) == NullResult } || range.end + 1 (first_null / @per_page) + 1 end def offset page = @page (page - 1) * @per_page end def covers? range !range.any? { |index| @fragment.fetch(index,NullResult) == NullResult } end end end