folio-pagination 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. data/.gitignore +17 -0
  2. data/.travis.yml +3 -0
  3. data/Gemfile +16 -0
  4. data/Guardfile +5 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +235 -0
  7. data/Rakefile +11 -0
  8. data/folio-pagination.gemspec +27 -0
  9. data/lib/folio/core_ext/enumerable.rb +51 -0
  10. data/lib/folio/invalid_page.rb +5 -0
  11. data/lib/folio/ordinal/page.rb +107 -0
  12. data/lib/folio/ordinal.rb +33 -0
  13. data/lib/folio/page.rb +86 -0
  14. data/lib/folio/per_page.rb +15 -0
  15. data/lib/folio/rails.rb +35 -0
  16. data/lib/folio/version.rb +3 -0
  17. data/lib/folio/will_paginate/active_record.rb +132 -0
  18. data/lib/folio/will_paginate/collection.rb +19 -0
  19. data/lib/folio/will_paginate/view_helpers/action_view.rb +10 -0
  20. data/lib/folio/will_paginate/view_helpers/link_renderer.rb +54 -0
  21. data/lib/folio/will_paginate/view_helpers/link_renderer_base.rb +44 -0
  22. data/lib/folio/will_paginate/view_helpers.rb +57 -0
  23. data/lib/folio-pagination.rb +3 -0
  24. data/lib/folio.rb +84 -0
  25. data/test/folio/core_ext/enumerable_test.rb +55 -0
  26. data/test/folio/ordinal/page_test.rb +173 -0
  27. data/test/folio/ordinal_test.rb +57 -0
  28. data/test/folio/page_test.rb +198 -0
  29. data/test/folio/per_page_test.rb +49 -0
  30. data/test/folio/rails_test.rb +15 -0
  31. data/test/folio/version_test.rb +8 -0
  32. data/test/folio/will_paginate/active_record_test.rb +118 -0
  33. data/test/folio/will_paginate/collection_test.rb +43 -0
  34. data/test/folio/will_paginate/view_helpers/link_renderer_base_test.rb +58 -0
  35. data/test/folio/will_paginate/view_helpers/link_renderer_test.rb +58 -0
  36. data/test/folio/will_paginate/view_helpers_test.rb +49 -0
  37. data/test/folio_test.rb +192 -0
  38. data/test/setup/active_record.rb +13 -0
  39. metadata +133 -0
@@ -0,0 +1,132 @@
1
+ begin
2
+ require 'will_paginate/active_record'
3
+ rescue LoadError
4
+ raise "folio-pagination's activerecord support requires will_paginate"
5
+ end
6
+
7
+ require 'folio/page'
8
+ require 'folio/ordinal'
9
+ require 'folio/ordinal/page'
10
+
11
+ module Folio
12
+ module WillPaginate
13
+ # enhances model_or_scope.page(n) method from WillPaginate to behave like a
14
+ # Folio::Ordinal::Page. replaces model_or_scope.paginate(...) method to
15
+ # behave like that from Folio while preserving basic mechanics of the
16
+ # version from WillPaginate.
17
+ #
18
+ # differences:
19
+ #
20
+ # * total_entries loading via count is *not* deferred as it was under
21
+ # WillPaginate.
22
+ #
23
+ # * paginate does *not* recognize any parameters beyond those described in
24
+ # for Folio's paginate (e.g. finder options, count options).
25
+ #
26
+ module ActiveRecord
27
+ module RelationMethods
28
+ include Folio::Page
29
+ include Folio::Ordinal::Page
30
+
31
+ # overrides Folio::Page's per_page similar to WillPaginate's version,
32
+ # but uses correct semantics for per_page(nil) (vs. per_page()).
33
+ def per_page(*args)
34
+ if args.size > 0
35
+ raise ArgumentError if args.size > 1
36
+ value ||= @klass.per_page
37
+ limit(value)
38
+ end
39
+ limit_value
40
+ end
41
+
42
+ # overrides WillPaginate's weird "ignore limit when counting" behavior.
43
+ # I can't fall back on super in the branch with a limit_value, since
44
+ # that would fall into WillPaginate's lap, but since there is a
45
+ # limit_value, safe enough to just instantiate and check length
46
+ def count
47
+ if limit_value
48
+ to_a.size
49
+ else
50
+ super
51
+ end
52
+ end
53
+ end
54
+
55
+ module Pagination
56
+ # turns the sequence of calls made by Folio::Ordinal#paginate into the
57
+ # construction of an appropriate relation
58
+ class PageProxy
59
+ def initialize(target)
60
+ @target = target
61
+ end
62
+
63
+ # needed to prevent Folio::Ordinal#configure_pagination from trying
64
+ # to decorate it
65
+ include Folio::Ordinal::Page
66
+
67
+ # called during Folio#configure_pagination, used to build up @rel
68
+ # from @target and the arguments
69
+ attr_writer :current_page
70
+
71
+ def per_page=(per_page)
72
+ @rel = @target.limit(per_page.to_i).page(@current_page)
73
+ @rel.limit_value
74
+ end
75
+
76
+ def total_entries=(total_entries)
77
+ @rel.total_entries = total_entries
78
+ end
79
+
80
+ # called during Folio::Ordinal#configure_pagination for bounds
81
+ # checking, before the proxy has been replaced by its result
82
+ def current_page
83
+ @rel.current_page
84
+ end
85
+
86
+ def out_of_bounds?
87
+ @rel.out_of_bounds?
88
+ end
89
+
90
+ # get the result of the construction back out during fill_page
91
+ def result
92
+ @rel
93
+ end
94
+ end
95
+
96
+ # set up the proxy to receive the calls
97
+ def build_page
98
+ PageProxy.new(self)
99
+ end
100
+
101
+ # pull the result out of the proxy
102
+ def fill_page(proxy)
103
+ proxy.result
104
+ end
105
+
106
+ # make sure the relation coming out of page(...) is folio-compatible
107
+ def page(num)
108
+ super.extending(RelationMethods)
109
+ end
110
+
111
+ # don't try and look at Class (ActiveRecord::Base.class, etc.) for
112
+ # defaults
113
+ def default_per_page
114
+ Folio.per_page
115
+ end
116
+
117
+ include ::Folio::Ordinal
118
+ end
119
+
120
+ # mix into Active Record. these are the same ones that WillPaginate mixes
121
+ # its version of Pagination into.
122
+ ::ActiveRecord::Base.extend Pagination
123
+ klasses = [::ActiveRecord::Relation]
124
+ if defined? ::ActiveRecord::Associations::CollectionProxy
125
+ klasses << ::ActiveRecord::Associations::CollectionProxy
126
+ else
127
+ klasses << ::ActiveRecord::Associations::AssociationCollection
128
+ end
129
+ klasses.each { |klass| klass.send(:include, Pagination) }
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,19 @@
1
+ require 'folio'
2
+ require 'folio/ordinal/page'
3
+ require 'will_paginate/collection'
4
+
5
+ # overrides WillPaginate::Collection.create to return an ordinal folio page
6
+ # instead of a WillPaginate::Collection; the rest of WillPaginate::Collection
7
+ # is unused when in folio-land.
8
+ module WillPaginate
9
+ class Collection
10
+ def self.create(current_page, per_page=nil, total_entries=nil)
11
+ page = ::Folio::Ordinal::Page.create
12
+ page.current_page = current_page
13
+ page.per_page = per_page
14
+ page.total_entries = total_entries
15
+ yield page if block_given?
16
+ page
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ begin
2
+ require 'will_paginate/view_helpers/action_view'
3
+ rescue LoadError
4
+ raise "folio-pagination's actionview support requires will_paginate"
5
+ end
6
+
7
+ require 'folio/will_paginate/view_helpers'
8
+
9
+ # no overrides specific to action view necessary. just including the general
10
+ # view_helper overrides as above is sufficient.
@@ -0,0 +1,54 @@
1
+ require 'will_paginate/view_helpers/link_renderer'
2
+
3
+ module Folio
4
+ module WillPaginate
5
+ module ViewHelpers
6
+ module LinkRenderer
7
+ def previous_page_with_folio
8
+ # the page identifier may not be ordinal; use the value as set on the
9
+ # collection, instead.
10
+ previous_or_next_page(@collection.previous_page, @options[:previous_label], 'previous_page')
11
+ end
12
+
13
+ def next_page_with_folio
14
+ # the page identifier may not be ordinal; use the value as set on the
15
+ # collection, instead.
16
+ previous_or_next_page(@collection.next_page, @options[:next_label], 'next_page')
17
+ end
18
+
19
+ def link_with_folio(text, target, attributes = {})
20
+ if target
21
+ # the non-folio version only does this for Fixnums, but we want to
22
+ # do it for any page value. fortunately, this method only ever
23
+ # receives Fixnums or nil, so we can do it now for any non-nil
24
+ # value, and the non-folio version will happily avoid a double
25
+ # application because even when the page was a fixnum, it won't be
26
+ # anymore.
27
+ attributes[:rel] = rel_value(target)
28
+ target = url(target)
29
+ end
30
+ link_without_folio(text, target, attributes)
31
+ end
32
+
33
+ def rel_value_with_folio(page)
34
+ # don't check against mathed out values, just check the values on the
35
+ # collection
36
+ rels = []
37
+ rels << 'prev' if page == @collection.previous_page
38
+ rels << 'next' if page == @collection.next_page
39
+ rels << 'start' if page == @collection.first_page
40
+ rels.empty? ? nil : rels.join(' ')
41
+ end
42
+
43
+ def self.included(klass)
44
+ [:previous_page, :next_page, :link, :rel_value].each do |method|
45
+ klass.send(:alias_method, :"#{method}_without_folio", method)
46
+ klass.send(:alias_method, method, :"#{method}_with_folio")
47
+ end
48
+ end
49
+
50
+ ::WillPaginate::ViewHelpers::LinkRenderer.send :include, self
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,44 @@
1
+ require 'will_paginate/view_helpers/link_renderer_base'
2
+
3
+ module Folio
4
+ module WillPaginate
5
+ module ViewHelpers
6
+ module LinkRendererBase
7
+ def prepare_with_folio(collection, options)
8
+ # only include page_links if we're in a collection with ordinal
9
+ # pages; otherwise stick to just prev/next.
10
+ options = options.merge(page_links: false) unless collection.ordinal_pages?
11
+ prepare_without_folio(collection, options)
12
+ end
13
+
14
+ def windowed_page_numbers_with_folio
15
+ page_numbers = windowed_page_numbers_without_folio
16
+ unless @collection.last_page
17
+ # the last page is not known, so add a trailing gap (it won't
18
+ # already be there, because the right range during the super call
19
+ # won't exist).
20
+ page_numbers << :gap
21
+ end
22
+ page_numbers
23
+ end
24
+
25
+ def total_pages_with_folio
26
+ # the collection may not have a known last page. if so, there must be
27
+ # a next page; count that as the last known page. it's ok to use
28
+ # these page identifiers as a page count because (after fixing
29
+ # LinkRenderer) it's only called when ordinal_pages is true.
30
+ @collection.last_page || @collection.next_page
31
+ end
32
+
33
+ def self.included(klass)
34
+ [:prepare, :windowed_page_numbers, :total_pages].each do |method|
35
+ klass.send(:alias_method, :"#{method}_without_folio", method)
36
+ klass.send(:alias_method, method, :"#{method}_with_folio")
37
+ end
38
+ end
39
+
40
+ ::WillPaginate::ViewHelpers::LinkRendererBase.send :include, self
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,57 @@
1
+ require 'folio'
2
+ require 'folio/will_paginate/view_helpers/link_renderer_base'
3
+ require 'folio/will_paginate/view_helpers/link_renderer'
4
+ require 'will_paginate/view_helpers'
5
+
6
+ module Folio
7
+ module WillPaginate
8
+ module ViewHelpers
9
+ # just copied from ::WillPaginate::ViewHelpers except line 14 (changed from
10
+ # "unless value > 1" to "if value == 1" to be friendly to unknown
11
+ # total_pages)
12
+ def will_paginate_with_folio(collection, options = {})
13
+ # early exit if there is nothing to render
14
+ return nil if collection.total_pages == 1
15
+
16
+ options = ::WillPaginate::ViewHelpers.pagination_options.merge(options)
17
+
18
+ options[:previous_label] ||= will_paginate_translate(:previous_label) { '&#8592; Previous' }
19
+ options[:next_label] ||= will_paginate_translate(:next_label) { 'Next &#8594;' }
20
+
21
+ # get the renderer instance
22
+ renderer = case options[:renderer]
23
+ when nil
24
+ raise ArgumentError, ":renderer not specified"
25
+ when String
26
+ klass = if options[:renderer].respond_to? :constantize then options[:renderer].constantize
27
+ else Object.const_get(options[:renderer]) # poor man's constantize
28
+ end
29
+ klass.new
30
+ when Class then options[:renderer].new
31
+ else options[:renderer]
32
+ end
33
+ # render HTML for pagination
34
+ renderer.prepare collection, options, self
35
+ output = renderer.to_html
36
+ output = output.html_safe if output.respond_to?(:html_safe)
37
+ output
38
+ end
39
+
40
+ def page_entries_info_with_folio(collection, options = {})
41
+ # skip outputting anything unless the collection has ordinal pages (to
42
+ # be able to get an offset) *and* a known total count.
43
+ return unless collection.total_entries && collection.ordinal_pages
44
+ page_entries_info_without_folio(collection, options)
45
+ end
46
+
47
+ def self.included(klass)
48
+ [:will_paginate, :page_entries_info].each do |method|
49
+ klass.send(:alias_method, :"#{method}_without_folio", method)
50
+ klass.send(:alias_method, method, :"#{method}_with_folio")
51
+ end
52
+ end
53
+
54
+ ::WillPaginate::ViewHelpers.send :include, self
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,3 @@
1
+ # convenience so that you can require by the gem name and get the same effect
2
+ # as requiring the canonical 'folio'.
3
+ require 'folio'
data/lib/folio.rb ADDED
@@ -0,0 +1,84 @@
1
+ require "folio/version"
2
+ require "folio/per_page"
3
+
4
+ # Mix into any class implementing the following two methods:
5
+ #
6
+ # +build_page+: Responsible for instantiating a Folio::Page and
7
+ # configuring its ordinal_pages?, first_page, and last_page attributes;
8
+ # those values being common to any page returned from the folio.
9
+ #
10
+ # +fill_page+: Receives a Folio::Page with the ordinal_pages?,
11
+ # first_page, last_page, current_page, per_page, and total_entries
12
+ # attributes configured, and populates the page with the corresponding
13
+ # items from the folio. Also sets appropriate values for the next_page
14
+ # and previous_page attributes on the page. If the value provided in the
15
+ # page's current_page cannot be interpreted as addressing a page in the
16
+ # folio, raises Folio::InvalidPage.
17
+ #
18
+ # In return, `Folio` provides a the paginate method and per_page
19
+ # attributes described below.
20
+ module Folio
21
+ # Returns a page worth of items from the folio in a Folio::Page.
22
+ # accepts the following parameters:
23
+ #
24
+ # +page+: a page identifier addressing which page of the folio to
25
+ # return. if not present, the first page will be returned. will raise
26
+ # Folio::InvalidPage if the provided value cannot be used to address a
27
+ # page.
28
+ #
29
+ # +per_page+: number of items to attempt to include in the page. if
30
+ # not present, defaults to the folio's per_page value. should only
31
+ # include fewer items if the end of the folio is reached.
32
+ #
33
+ # +total_entries+: pre-calculated value for the total number of items
34
+ # in the folio. may be nil, indicating the returned page should have
35
+ # total_entries nil.
36
+ #
37
+ # if the folio implements a count method and the total_entries
38
+ # parameter is not supplied, the page's total_entries will be set from
39
+ # the count method.
40
+ def paginate(options={})
41
+ page = self.build_page
42
+ page = self.configure_pagination(page, options)
43
+ page = self.fill_page(page)
44
+ page
45
+ end
46
+
47
+ def configure_pagination(page, options)
48
+ current_page = options.fetch(:page) { nil }
49
+ current_page = page.first_page if current_page.nil?
50
+ page.current_page = current_page
51
+ page.per_page = options.fetch(:per_page) { self.per_page }
52
+ page.total_entries = options.fetch(:total_entries) { self.respond_to?(:count) ? self.count : nil }
53
+ page
54
+ end
55
+
56
+ def default_per_page
57
+ self.class.per_page
58
+ end
59
+
60
+ include ::Folio::PerPage
61
+
62
+ # this funny pattern is so that if a module (e.g. Folio::Ordinal)
63
+ # includes this module, it won't get the per_page attribute, but will
64
+ # still be able to bestow that attribute on any class that includes
65
+ # *it*.
66
+ module PerPageIncluder
67
+ def included(klass)
68
+ if klass.is_a?(Class)
69
+ klass.extend ::Folio::PerPage
70
+ else
71
+ klass.extend ::Folio::PerPageIncluder
72
+ end
73
+ end
74
+ end
75
+
76
+ extend PerPageIncluder
77
+ extend PerPage
78
+ per_page(30)
79
+ end
80
+
81
+ # load the other commonly used portions of the gem
82
+ require "folio/page"
83
+ require "folio/ordinal"
84
+ require "folio/ordinal/page"
@@ -0,0 +1,55 @@
1
+ require 'minitest/autorun'
2
+ require 'folio/core_ext/enumerable'
3
+
4
+ describe Array do
5
+ it "should be an ordinal folio" do
6
+ assert_respond_to [], :build_page
7
+ [].build_page.first_page.must_equal 1
8
+ end
9
+
10
+ describe "per_page" do
11
+ it "should have per_page attribute as expected on instances" do
12
+ assert_respond_to [], :per_page
13
+ assert_respond_to [], :per_page=
14
+ end
15
+
16
+ it "should not have per_page attribute on classes" do
17
+ Array.wont_respond_to :per_page
18
+ Array.wont_respond_to :per_page=
19
+ end
20
+
21
+ it "should default to Folio.per_page" do
22
+ was = Folio.per_page
23
+ Folio.per_page = 100
24
+ [].per_page.must_equal 100
25
+ Folio.per_page = was
26
+ end
27
+ end
28
+
29
+ describe "paginate" do
30
+ before do
31
+ @ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
32
+ end
33
+
34
+ it "should return a page" do
35
+ page = @ary.paginate
36
+ assert_respond_to page, :current_page
37
+ end
38
+
39
+ it "should return appropriate slice" do
40
+ @ary.paginate(page: 2, per_page: 4).must_equal [5, 6, 7, 8]
41
+ end
42
+
43
+ it "should return partial slice at end" do
44
+ @ary.paginate(page: 3, per_page: 4).must_equal [9, 10]
45
+ end
46
+
47
+ it "should raise InvalidPage after end even if size unknown" do
48
+ lambda{ @ary.paginate(page: 3, per_page: 5, total_entries: nil) }.must_raise Folio::InvalidPage
49
+ end
50
+
51
+ it "should return empty first page if empty" do
52
+ [].paginate.must_equal []
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,173 @@
1
+ require 'minitest/autorun'
2
+ require 'folio/ordinal'
3
+
4
+ describe Folio::Ordinal::Page do
5
+ before do
6
+ @page = Folio::Ordinal::Page.create
7
+ @page.current_page = 1
8
+ @page.per_page = 10
9
+ @page.total_entries = 30
10
+ end
11
+
12
+ it "should have ordinal_pages=true" do
13
+ @page.ordinal_pages.must_equal true
14
+ @page.ordinal_pages?.must_equal true
15
+ end
16
+
17
+ it "should have first_page=1" do
18
+ @page.first_page.must_equal 1
19
+ end
20
+
21
+ it "should force current_page to an integer" do
22
+ @page.current_page = "3"
23
+ @page.current_page.must_equal 3
24
+ end
25
+
26
+ describe "when total pages known" do
27
+ it "should have last_page=total_pages" do
28
+ @page.last_page.must_equal @page.total_pages
29
+
30
+ @page.total_entries = 0
31
+ @page.last_page.must_equal @page.total_pages
32
+
33
+ @page.total_entries = nil
34
+ @page.last_page.must_equal @page.total_pages
35
+ end
36
+
37
+ it "should have next_page=current_page+1 when not at end" do
38
+ @page.current_page = 2
39
+ @page.next_page.must_equal 3
40
+ end
41
+
42
+ it "should still have next_page=current_page+1 when not at end, despite set value" do
43
+ @page.current_page = 2
44
+ @page.next_page = nil
45
+ @page.next_page.must_equal 3
46
+ end
47
+
48
+ it "should have next_page=nil when at end" do
49
+ @page.current_page = 3
50
+ @page.next_page.must_be_nil
51
+ end
52
+
53
+ it "should still have next_page=nil when at end, despite set value" do
54
+ @page.current_page = 3
55
+ @page.next_page = 4
56
+ @page.next_page.must_be_nil
57
+ end
58
+ end
59
+
60
+ describe "when total pages not known" do
61
+ before do
62
+ @page.total_entries = nil
63
+ end
64
+
65
+ it "should have last_page=nil if next_page is known or assumed" do
66
+ # @page.next_page unset
67
+ @page.last_page.must_be_nil
68
+
69
+ # @page.next_page explicitly non-nil
70
+ @page.next_page = 2
71
+ @page.last_page.must_be_nil
72
+ end
73
+
74
+ it "should have last_page=current_page if next_page is explicitly nil" do
75
+ @page.next_page = nil
76
+ @page.last_page.must_equal @page.current_page
77
+ end
78
+
79
+ it "should have next_page=current_page+1 when not explicitly set" do
80
+ @page.current_page = 2
81
+ @page.next_page.must_equal 3
82
+ end
83
+
84
+ it "should force non-nil set next_page to an integer" do
85
+ @page.next_page = "4"
86
+ @page.next_page.must_equal 4
87
+ end
88
+
89
+ it "should not force nil set next_page to an integer" do
90
+ @page.next_page = nil
91
+ @page.next_page.must_be_nil
92
+ end
93
+
94
+ it "should have next_page=set value when explicitly set" do
95
+ @page.next_page = nil
96
+ @page.current_page = 2
97
+ @page.next_page.must_be_nil
98
+ end
99
+ end
100
+
101
+ it "should have previous_page=nil when at beginning" do
102
+ @page.current_page = 1
103
+ @page.previous_page.must_be_nil
104
+ end
105
+
106
+ it "should have previous_page=current_page-1 when not at beginning" do
107
+ @page.current_page = 3
108
+ @page.previous_page.must_equal 2
109
+ end
110
+
111
+ describe "out_of_bounds?" do
112
+ it "should be false if in first_page..last_page range" do
113
+ @page.current_page = 1
114
+ @page.out_of_bounds?.must_equal false
115
+
116
+ @page.current_page = 3
117
+ @page.out_of_bounds?.must_equal false
118
+ end
119
+
120
+ it "should be true if negative page" do
121
+ @page.current_page = -1
122
+ @page.out_of_bounds?.must_equal true
123
+ end
124
+
125
+ it "should be true if zero page" do
126
+ @page.current_page = 0
127
+ @page.out_of_bounds?.must_equal true
128
+ end
129
+
130
+ it "should be true after known last_page" do
131
+ @page.current_page = 4
132
+ @page.out_of_bounds?.must_equal true
133
+ end
134
+
135
+ it "should not care about large numbers when total_pages not known" do
136
+ @page.total_entries = nil
137
+ @page.current_page = 50
138
+ @page.out_of_bounds?.must_equal false
139
+ end
140
+ end
141
+
142
+ describe "decorate" do
143
+ before do
144
+ @page = Folio::Ordinal::Page.decorate([])
145
+ end
146
+
147
+ it "should add page methods to the object" do
148
+ assert_respond_to @page, :current_page
149
+ end
150
+
151
+ it "should add ordinal page methods to the object" do
152
+ @page.first_page.must_equal 1
153
+ end
154
+
155
+ it "should preserve other methods on the object" do
156
+ assert_respond_to @page, :each
157
+ end
158
+ end
159
+
160
+ describe "create" do
161
+ before do
162
+ @page = Folio::Ordinal::Page.create
163
+ end
164
+
165
+ it "should be an Array at heart" do
166
+ @page.must_be :is_a?, Array
167
+ end
168
+
169
+ it "should be decorated as an ordinal page" do
170
+ @page.first_page.must_equal 1
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,57 @@
1
+ require 'minitest/autorun'
2
+ require 'folio/ordinal'
3
+
4
+ describe Folio::Ordinal do
5
+ before do
6
+ klass = Class.new do
7
+ def build_page
8
+ Folio::Page.create
9
+ end
10
+
11
+ def fill_page(page)
12
+ page
13
+ end
14
+
15
+ include Folio::Ordinal
16
+ end
17
+ @folio = klass.new
18
+ end
19
+
20
+ describe "paginate" do
21
+ it "should decorate the result of build_page" do
22
+ @page = @folio.paginate
23
+ @page.is_a?(Folio::Ordinal::Page).must_equal true
24
+ end
25
+
26
+ describe "bounds checking" do
27
+ before do
28
+ @folio.per_page = 10
29
+ end
30
+
31
+ it "should raise on non-integer page" do
32
+ lambda{ @folio.paginate(page: "non-integer") }.must_raise Folio::InvalidPage
33
+ end
34
+
35
+ it "should raise on negative page" do
36
+ lambda{ @folio.paginate(page: -1) }.must_raise Folio::InvalidPage
37
+ end
38
+
39
+ it "should raise on page of 0" do
40
+ lambda{ @folio.paginate(page: 0) }.must_raise Folio::InvalidPage
41
+ end
42
+
43
+ it "should raise on page greater than known last_page" do
44
+ lambda{ @folio.paginate(page: 4, total_entries: 30) }.must_raise Folio::InvalidPage
45
+ end
46
+
47
+ it "should not raise on page number between first_page and known last_page" do
48
+ @folio.paginate(page: 1, total_entries: 30)
49
+ @folio.paginate(page: 3, total_entries: 30)
50
+ end
51
+
52
+ it "should not raise on large page if last_page unknown" do
53
+ @folio.paginate(page: 100)
54
+ end
55
+ end
56
+ end
57
+ end