From e04f65aeaa420600577c5f15e732f1cfcd2526fe Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 22 Apr 2011 02:57:12 +0900 Subject: [PATCH] refs #47, #68, #74 generic pagination support for Array object this enables you to paginate through any Arrayish object in this way: Kaminari.paginate_array(my_array_object).page(params[:page]).per(10) --- lib/kaminari/models/array_extension.rb | 42 ++++++++++ lib/kaminari/railtie.rb | 1 + spec/models/array_spec.rb | 105 +++++++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 lib/kaminari/models/array_extension.rb create mode 100644 spec/models/array_spec.rb diff --git a/lib/kaminari/models/array_extension.rb b/lib/kaminari/models/array_extension.rb new file mode 100644 index 0000000..812e364 --- /dev/null +++ b/lib/kaminari/models/array_extension.rb @@ -0,0 +1,42 @@ +module Kaminari + # Kind of Array that can paginate + class PaginatableArray < Array + include Kaminari::ConfigurationMethods::ClassMethods + + attr_internal_accessor :limit_value, :offset_value + + def initialize(original_array, limit_val = default_per_page, offset_val = 0) #:nodoc: + @_original_array, @_limit_value, @_offset_value = original_array, limit_val, offset_val + super (original_array[offset_val, limit_val] || []) + end + + # items at the specified "page" + def page(num = 1) + offset(limit_value * ([num.to_i, 1].max - 1)) + end + + # returns another chunk of the original array + def limit(num) + self.class.new @_original_array, num, offset_value + end + + # total item numbers of the original array + def total_count + @_original_array.count + end + + # returns another chunk of the original array + def offset(num) + arr = self.class.new @_original_array, limit_value, num + class << arr + include Kaminari::PageScopeMethods + end + arr + end + end + + # Wrap an Array object to make it paginatable + def self.paginate_array(array) + PaginatableArray.new array + end +end diff --git a/lib/kaminari/railtie.rb b/lib/kaminari/railtie.rb index 107e20f..8576c77 100644 --- a/lib/kaminari/railtie.rb +++ b/lib/kaminari/railtie.rb @@ -20,6 +20,7 @@ module Kaminari ::Mongoid::Document.send :include, Kaminari::MongoidExtension::Document ::Mongoid::Criteria.send :include, Kaminari::MongoidExtension::Criteria end + require File.join(File.dirname(__FILE__), 'models/array_extension') ActiveSupport.on_load(:action_view) do ::ActionView::Base.send :include, Kaminari::ActionViewExtension end diff --git a/spec/models/array_spec.rb b/spec/models/array_spec.rb new file mode 100644 index 0000000..eac9ff9 --- /dev/null +++ b/spec/models/array_spec.rb @@ -0,0 +1,105 @@ +require File.expand_path('../spec_helper', File.dirname(__FILE__)) + +describe Kaminari::PaginatableArray do + let(:array) { Kaminari::PaginatableArray.new((1..100).to_a) } + describe '#page' do + shared_examples_for 'the first page of array' do + it { should have(25).users } + its(:first) { should == 1 } + end + + shared_examples_for 'blank array page' do + it { should have(0).items } + end + + context 'page 1' do + subject { array.page 1 } + it_should_behave_like 'the first page of array' + end + + context 'page 2' do + subject { array.page 2 } + it { should have(25).users } + its(:first) { should == 26 } + end + + context 'page without an argument' do + subject { array.page } + it_should_behave_like 'the first page of array' + end + + context 'page < 1' do + subject { array.page 0 } + it_should_behave_like 'the first page of array' + end + + context 'page > max page' do + subject { array.page 5 } + it_should_behave_like 'blank array page' + end + end + + describe '#per' do + context 'page 1 per 5' do + subject { array.page(1).per(5) } + it { should have(5).users } + its(:first) { should == 1 } + end + end + + describe '#num_pages' do + context 'per 25 (default)' do + subject { array.page } + its(:num_pages) { should == 4 } + end + + context 'per 7' do + subject { array.page(2).per(7) } + its(:num_pages) { should == 15 } + end + + context 'per 65536' do + subject { array.page(50).per(65536) } + its(:num_pages) { should == 1 } + end + + context 'per 0 (using default)' do + subject { array.page(50).per(0) } + its(:num_pages) { should == 4 } + end + + context 'per -1 (using default)' do + subject { array.page(5).per(-1) } + its(:num_pages) { should == 4 } + end + + context 'per "String value that can not be converted into Number" (using default)' do + subject { array.page(5).per('aho') } + its(:num_pages) { should == 4 } + end + end + + describe '#current_page' do + context 'page 1' do + subject { array.page } + its(:current_page) { should == 1 } + end + + context 'page 2' do + subject { array.page(2).per 3 } + its(:current_page) { should == 2 } + end + end + + describe '#count' do + context 'page 1' do + subject { array.page } + its(:count) { should == 25 } + end + + context 'page 2' do + subject { array.page 2 } + its(:count) { should == 25 } + end + end +end