taylorbarstow-simple_pagination 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 0
4
+ :minor: 1
@@ -0,0 +1,3 @@
1
+ %w(page page_collection).each do |f|
2
+ require File.join(File.dirname(__FILE__), 'simple_pagination', f)
3
+ end
@@ -0,0 +1,59 @@
1
+ module SimplePagination
2
+ class Page
3
+ def initialize(number, collection)
4
+ @number, @collection = number, collection
5
+ end
6
+
7
+ ##
8
+ # The zero-based offset of the first record in this page
9
+ def offset
10
+ (@number-1) * @collection.page_size + 1
11
+ end
12
+
13
+ ##
14
+ # The one-based page number for this page
15
+ def number
16
+ @number
17
+ end
18
+
19
+ ##
20
+ # The Page object after this page (or +nil+ if +self.last?+)
21
+ def next
22
+ @collection[number + 1]
23
+ end
24
+
25
+ ##
26
+ # The Page object before this page (or +nil+ if +self.first?+)
27
+ def prev
28
+ @collection[number - 1]
29
+ end
30
+
31
+ ##
32
+ # Test if this is the first page in the collection
33
+ def first?
34
+ number == 1
35
+ end
36
+
37
+ ##
38
+ # Test if this is the last page in the collection
39
+ def last?
40
+ number == @collection.length
41
+ end
42
+
43
+ ##
44
+ # Test if this is the current page.
45
+ def current?
46
+ self === @collection.current
47
+ end
48
+
49
+ ##
50
+ # Generate a "window" of pages around (and including) this page. +n+
51
+ # is the number of pages to show (defaults to 10). For example, if this is
52
+ # page 8 and you ask for window(10) you will get an array of Page objects
53
+ # representing the following pages: 4, 5, 6, 7, 8, 9, 10, 11, 12, 13
54
+ def window(n=10)
55
+ start = [1, [number-(n/2)+1, @collection.length-n+1].min].max
56
+ (start..start+n-1).collect {|i| @collection[i]}.compact
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,68 @@
1
+ module SimplePagination
2
+ class PageCollection
3
+ ##
4
+ # Create a new PageCollection object. The following options are available.
5
+ # [:current_offset] The zero-based offset of the first record in the current page of results
6
+ # [:current_page] The one-based offset of the current page of results
7
+ # [:total] The total number of results across all pages
8
+ # [:page_size] The page size
9
+ #
10
+ # You can choose between :current_offset and :current_page based on your
11
+ # needs. Same goes for :total_records and :total_pages. :page_size
12
+ # is required.
13
+ #
14
+ # A typical use of this class would be to define a <tt>pages</tt> method on your
15
+ # result set class which returns an instance of PageCollection. (So you can
16
+ # do, e.g., <tt>my_result_set.pages.current</tt> and so on.)
17
+ def initialize(options={})
18
+ check_options(options)
19
+ @pages, @page_size = {}, options[:page_size]
20
+ @length = options[:total_pages] || options[:total_records] / @page_size
21
+ @current_page = options[:current_page] || (options[:current_offset]/@page_size)+1
22
+ end
23
+
24
+ ##
25
+ # A Page object representing the page at a given page number (one-based).
26
+ def [](i)
27
+ @pages[i] ||= Page.new(i, self) unless out_of_bounds?(i)
28
+ end
29
+
30
+ ##
31
+ # A Page object representing the current page in the collection.
32
+ def current
33
+ self[@current_page]
34
+ end
35
+
36
+ ##
37
+ # A Page object representing the first page in the collection.
38
+ def first
39
+ self[1]
40
+ end
41
+
42
+ ##
43
+ # A Page object representing the last page in the collection.
44
+ def last
45
+ self[length]
46
+ end
47
+
48
+ ##
49
+ # The number of pages in the collection.
50
+ attr_reader :length
51
+
52
+ ##
53
+ # The number of records shown on each page in the collection.
54
+ attr_reader :page_size
55
+
56
+ private
57
+
58
+ def check_options(options)
59
+ raise ArgumentError, "requires :current_offset or :current_page" unless options[:current_offset] || options[:current_page]
60
+ raise ArgumentError, "requires :page_size" unless options[:page_size]
61
+ raise ArgumentError, "requires :total" unless options[:total_pages] or options[:total_records]
62
+ end
63
+
64
+ def out_of_bounds?(i)
65
+ i > length || i < 1
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,99 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper.rb')
2
+
3
+ class PageCollectionTest < Test::Unit::TestCase
4
+ include SimplePagination
5
+
6
+ context "creating a new instance" do
7
+ should "require :current_offset or :current_page" do
8
+ args = {:page_size => 10, :total_records => 100}
9
+ assert_raise(ArgumentError) {PageCollection.new(args)}
10
+ assert_nothing_raised {PageCollection.new(args.merge(:current_offset => 0))}
11
+ assert_nothing_raised {PageCollection.new(args.merge(:current_page => 1))}
12
+ end
13
+
14
+ should "require :total_records or :total_pages" do
15
+ args = {:page_size => 10, :current_page => 1}
16
+ assert_raise(ArgumentError) {PageCollection.new(args)}
17
+ assert_nothing_raised {PageCollection.new(args.merge(:total_pages => 10))}
18
+ assert_nothing_raised {PageCollection.new(args.merge(:total_records => 10))}
19
+ end
20
+
21
+ should "require :page_size" do
22
+ args = {:total_records => 100, :current_offset => 0}
23
+ assert_raise(ArgumentError) {PageCollection.new(args)}
24
+ assert_nothing_raised {PageCollection.new(args.merge(:page_size => 10))}
25
+ end
26
+ end
27
+
28
+ context "accessors" do
29
+ setup do
30
+ @collection = PageCollection.new(:total_pages => 10, :page_size => 10, :current_offset => 0)
31
+ end
32
+
33
+ should "provide page_size accessor" do
34
+ assert_equal 10, @collection.page_size
35
+ end
36
+
37
+ should "provide length accessor" do
38
+ assert_equal 10, @collection.length
39
+ end
40
+
41
+ should "calculate length when given :total_records" do
42
+ c = PageCollection.new(:total_records => 113, :page_size => 3, :current_offset => 0)
43
+ assert_equal 37, c.length
44
+ end
45
+ end
46
+
47
+ context "accessing a specific page" do
48
+ setup do
49
+ @collection = PageCollection.new(:total_pages => 10, :page_size => 10, :current_page=>1)
50
+ end
51
+
52
+ should "create and return a new Page instance" do
53
+ p = Page.new(1, @collection)
54
+ Page.expects(:new).with(1, @collection).returns(p)
55
+ assert_same p, @collection[1]
56
+ end
57
+
58
+ should "return the same Page across multiple invocations" do
59
+ assert_same @collection[3], @collection[3]
60
+ assert_not_same @collection[3], @collection[4]
61
+ end
62
+
63
+ context "when the page is out of bounds" do
64
+ should "return nil" do
65
+ assert_equal nil, @collection[100]
66
+ assert_equal nil, @collection[0]
67
+ assert_equal nil, @collection[-1]
68
+ end
69
+ end
70
+ end
71
+
72
+ context "accessing named pages" do
73
+ setup do
74
+ @collection = PageCollection.new(:total_pages => 10, :page_size => 10, :current_page=>1)
75
+ end
76
+
77
+ should "access current page" do
78
+ (1..3).each do |i|
79
+ c = PageCollection.new(:total_pages => 10, :page_size => 10, :current_page=>i)
80
+ c.expects(:[]).with(i)
81
+ c.current
82
+ end
83
+ end
84
+
85
+ should "access first page" do
86
+ @collection.expects(:[]).with(1)
87
+ @collection.first
88
+ end
89
+
90
+ should "access last page" do
91
+ @collection.expects(:[]).with(10)
92
+ @collection.last
93
+
94
+ c = PageCollection.new(:total_records => 113, :page_size => 3, :current_page => 1)
95
+ c.expects(:[]).with(37)
96
+ c.last
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,108 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper.rb')
2
+
3
+ class PageTest < Test::Unit::TestCase
4
+ include SimplePagination
5
+
6
+ def assert_page_window(expected, actual)
7
+ actual.each {|page| assert_instance_of Page, page}
8
+ assert_equal expected, actual.collect {|page| page.number}
9
+ end
10
+
11
+ context "accessors" do
12
+ setup do
13
+ @collection = PageCollection.new(:current_page => 1, :total_pages => 10, :page_size => 10)
14
+ @page = Page.new(5, @collection)
15
+ end
16
+
17
+ should "provide accessor for page number" do
18
+ assert_equal 5, @page.number
19
+ end
20
+
21
+ should "provide accessor for first record offset" do
22
+ assert_equal 41, @page.offset
23
+ end
24
+ end
25
+
26
+ context "next/previous page" do
27
+ setup do
28
+ @collection = PageCollection.new(:current_page => 1, :total_pages => 10, :page_size => 10)
29
+ end
30
+
31
+ should "provide previous page using PageCollection#[]" do
32
+ @collection.expects(:[]).with(2)
33
+ Page.new(3, @collection).prev
34
+
35
+ @collection.expects(:[]).with(4)
36
+ Page.new(5, @collection).prev
37
+ end
38
+
39
+ should "provide next page using PageCollection#[]" do
40
+ @collection.expects(:[]).with(2)
41
+ Page.new(1, @collection).next
42
+
43
+ @collection.expects(:[]).with(4)
44
+ Page.new(3, @collection).next
45
+ end
46
+ end
47
+
48
+ context "named page tests" do
49
+ setup do
50
+ @collection = PageCollection.new(:current_page => 1, :total_pages => 10, :page_size => 10)
51
+ end
52
+
53
+ should "identify last page" do
54
+ assert @collection[10].last?
55
+ end
56
+
57
+ should "not identify non last page as last" do
58
+ (1..9).each {|i| assert !@collection[i].last?}
59
+ end
60
+
61
+ should "identify first page" do
62
+ assert @collection[1].first?
63
+ end
64
+
65
+ should "not identify non first page as first" do
66
+ (2..10).each {|i| assert !@collection[i].first?}
67
+ end
68
+
69
+ should "identify current page" do
70
+ assert @collection[1].current?
71
+ end
72
+
73
+ should "not identify non current page as current" do
74
+ (2..10).each {|i| assert !@collection[i].current?}
75
+ end
76
+ end
77
+
78
+ context "generating a page window" do
79
+ setup do
80
+ @collection = PageCollection.new(:current_page => 1, :page_size => 10, :total_pages => 50)
81
+ end
82
+
83
+ should "generate page window of the requested size" do
84
+ assert_equal 10, @collection[10].window(10).length
85
+ assert_equal 5, @collection[10].window(5).length
86
+ end
87
+
88
+ should "generate page window when near beginning" do
89
+ (1..5).each do |i|
90
+ assert_page_window (1..10).to_a, @collection[i].window(10)
91
+ end
92
+ end
93
+
94
+ should "generate page window when in middle" do
95
+ assert_page_window (20..29).to_a, @collection[24].window(10)
96
+ end
97
+
98
+ should "generate page window when near end" do
99
+ (46..50).each do |i|
100
+ assert_page_window (41..50).to_a, @collection[i].window(10)
101
+ end
102
+ end
103
+
104
+ should "generate page window when requesting window larger than # of pages" do
105
+ assert_page_window (1..50).to_a, @collection[1].window(100)
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'simple_pagination')
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: taylorbarstow-simple_pagination
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Taylor Barstow
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-11 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A simple, standalone pagination gem for non-ActiveRecord data.
17
+ email: taylorbarstow@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - VERSION.yml
26
+ - lib/simple_pagination
27
+ - lib/simple_pagination/page.rb
28
+ - lib/simple_pagination/page_collection.rb
29
+ - lib/simple_pagination.rb
30
+ - test/simple_pagination
31
+ - test/simple_pagination/page_collection_test.rb
32
+ - test/simple_pagination/page_test.rb
33
+ - test/test_helper.rb
34
+ has_rdoc: true
35
+ homepage: http://github.com/taylorbarstow/simple_pagination
36
+ post_install_message:
37
+ rdoc_options:
38
+ - --inline-source
39
+ - --charset=UTF-8
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ requirements: []
55
+
56
+ rubyforge_project:
57
+ rubygems_version: 1.2.0
58
+ signing_key:
59
+ specification_version: 2
60
+ summary: A simple, standalone pagination gem non-ActiveRecord data.
61
+ test_files: []
62
+