simply_paginate 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # SimplyPaginate
2
- [![Build Status](https://travis-ci.org/guiman/simply_paginate.png)](https://travis-ci.org/guiman/simply_paginate)
2
+ [![Build Status](https://travis-ci.org/guiman/simply_paginate.png)](https://travis-ci.org/guiman/simply_paginate) [![Code Climate](https://codeclimate.com/github/guiman/simply_paginate.png)](https://codeclimate.com/github/guiman/simply_paginate)
3
3
 
4
4
  Simply paginate will do just that, give me a collection and you will be able to use a pagination logic (no extra html boilerplate or dependecies).
5
5
 
@@ -19,60 +19,79 @@ Or install it yourself as:
19
19
 
20
20
  ## Motivation
21
21
  When dealing with pagination most known gems come bundled with lots of extra functionality I usually don't need (like html boilerplate), this is my attempt to create just the pagination logic, as simple as that.
22
+ So if you need pagiation but don't want to reinvent the wheel and keep your collections Pagination Agnostic, this is the gem you need. The only
23
+ requirement is the adoption of the popular ruby Enumerable interface.
22
24
 
23
25
  ## Usage
24
26
 
25
27
  ```ruby
26
28
  require 'simply_paginate'
27
29
 
28
- collection = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
30
+ include SimplyPaginate
29
31
 
30
- paginator = SimplyPaginate::Paginator.new(collection)
32
+ collection = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
31
33
 
32
- # create pages with max of 3 elements
33
- SimplyPaginate::Paginator.per_page 3
34
+ pages = Paginator.new(collection, 3)
34
35
 
35
36
  # retrieve a certain page
36
- paginator[0]
37
+ pages[1]
37
38
 
38
39
  #move through the pages freely
39
- paginator[0].next
40
- paginator[0].previous
40
+ pages[1].next
41
+ pages[1].previous
41
42
 
42
43
  #you might want the first element on the 3rd page
43
- paginator[0].next.next.next.previous.elements[0]
44
+ pages[1].next.next.next.previous.elements[0]
44
45
 
45
46
  #or maybe all of them
46
- paginator[0].next.next.next.previous.elements
47
- ```
47
+ pages[0].next.next.next.previous.elements
48
48
 
49
- There is also the possibility to use a DataMapper::Collection as the collection to be paginated (right out of the box, not extensions needed):
50
-
51
- ```ruby
52
- # I will guess you have a model called Post
53
- # By default Paginator.per_page is 10
49
+ #you can also iterate the ruby way
50
+ pages.each do |page|
51
+ puts page.elements
52
+ end
54
53
 
55
- paginator = SimplyPaginate::Paginator.new(Post.all)
54
+ #or in a more old fashion way
55
+ pages.start
56
56
 
57
- paginator[0].elements # this will return a DataMapper::Collection with the first 10 elements
57
+ while pages.next? do
58
+ puts pages.current.elements
59
+
60
+ pages.next!
61
+ end
58
62
  ```
59
63
 
60
- ## Currently working on:
64
+ ## Changes on this branch
65
+ Well this branch introduced a better design about the relationship between pages and page, and also
66
+ an improvement on the API.
61
67
 
62
- * Adding support for common ORMs like: ActiveRecord, Sequel and DataMapper.
63
- * Testing...
68
+ Now a Page can be used without the need of having a Paginator, and also a Paginator could be transversed
69
+ without need to access pages directly.
64
70
 
65
- ## Alternative branch
66
- This branch contains a different implementation on the paging algorithm. This one creates pages on the fly and calculating offsets,
67
- so when you call ```previous``` or ```next``` or ```[]```page object representing is created on that moment, thus saving memory.
71
+ ```ruby
72
+ require 'simply_paginate'
68
73
 
69
- Another modification is that the ```per_page``` value has moved up to the class, and there is no need on calling ```paginate``` anymore,
70
- also the ```pages``` has been dropped.
74
+ include SimplyPaginate
71
75
 
72
- ## Release 0.0.2 features:
73
- * Dropping the each_slice in order to use a more memory efficient index algorithm for paging.
74
- * Adding more tests to the page object.
76
+ collection = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
75
77
 
78
+ # Give me the first page of the collection with a size of 3
79
+ first_page = Page.new(1, collection, 3)
80
+
81
+ first_page.elements
82
+ #=> [1, 2, 3]
83
+ first_page.next.elements
84
+ #=> [4, 5, 6]
85
+ ```
86
+ ##0.0.4 - Changelog:
87
+
88
+ * Redesign on relation between paginator and pages. You can use them togheter or separately.
89
+ * Improved API for Paginator, now including:
90
+ * each iteration
91
+ * next!, next?, current and start methods for manual iteration
92
+ * first and last accessors
93
+ * Test improvement
94
+
76
95
  ## Contributing
77
96
 
78
97
  1. Fork it
@@ -0,0 +1,7 @@
1
+ # A sample Gemfile
2
+ source "https://rubygems.org"
3
+
4
+ gem 'simply_paginate', github: 'guiman/simply_paginate'
5
+ gem 'data_mapper'
6
+ gem 'dm-sqlite-adapter'
7
+
@@ -0,0 +1,19 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+
4
+ DataMapper.setup :default, 'sqlite::memory:'
5
+
6
+ class Person
7
+ include DataMapper::Resource
8
+
9
+ property :id, Serial
10
+ property :age, String
11
+ end
12
+
13
+ DataMapper.auto_migrate!
14
+
15
+ 100.times { Person.create age: rand(1..90) }
16
+
17
+ paginator = SimplyPaginate::Paginator.new(Person.all)
18
+
19
+ paginator[0].elements.all(:age.gt => 10)
@@ -1,33 +1,35 @@
1
1
  module SimplyPaginate
2
2
  class Page
3
- attr_reader :first, :last
3
+ attr_reader :index, :collection, :size
4
4
 
5
- def initialize(first, last, paginator, previous_page = nil, next_page = nil)
6
- @first = first
7
- @last = last
8
- @paginator = paginator
5
+ def initialize(page, collection, size = Paginator.per_page)
6
+ @index = page
7
+ @collection = collection
8
+ @size = size
9
+
10
+ @move_page = lambda do |number|
11
+ new_index = @index + number
12
+ Page.new(new_index, @collection, @size) unless (new_index == 0) || (new_index > (@collection.count.to_f / @size.to_f).ceil)
13
+ end
9
14
  end
10
15
 
11
16
  def next
12
- first = @last + 1
13
- last = first + Paginator.per_page - 1
14
-
15
- (first >= @paginator.collection.count) ? nil : @paginator.current = Page.new(first, last, @paginator)
17
+ @move_page.call(1)
16
18
  end
17
19
 
18
20
  def previous
19
- first = @first - Paginator.per_page
20
- last = @first - 1
21
-
22
- (first < 0) ? nil : @paginator.current = Page.new(first, last, @paginator)
21
+ @move_page.call(-1)
23
22
  end
24
23
 
25
- def current?
26
- !@paginator.current.nil? && @paginator.current.first == @first && @paginator.current.last == @last
24
+ def elements
25
+ first = (@index - 1) * @size
26
+ last = first + size - 1
27
+
28
+ collection[first..last]
27
29
  end
28
30
 
29
- def elements
30
- @paginator.collection[@first..@last]
31
+ def ==(other)
32
+ (index == other.index) && (elements == other.elements) if other.respond_to?(:index) && other.respond_to?(:elements)
31
33
  end
32
34
  end
33
35
  end
@@ -1,7 +1,8 @@
1
1
  module SimplyPaginate
2
+ FIRST_PAGE_INDEX = 1
3
+
2
4
  class Paginator
3
5
  attr_reader :collection
4
- attr_accessor :current
5
6
 
6
7
  def self.per_page=(amount_per_page)
7
8
  raise NotInRangeError.new("Amount per page should be greater than 0") unless amount_per_page > 0
@@ -13,20 +14,56 @@ module SimplyPaginate
13
14
  @@per_page
14
15
  end
15
16
 
16
- def initialize(collection)
17
+ def initialize(collection, per_page = self.class.per_page)
17
18
  @collection = collection
18
- @current = nil
19
+ @per_page = per_page
19
20
  end
20
21
 
21
- def [](pos)
22
- first = pos * @@per_page
23
- last = first + @@per_page - 1
22
+ ## Basic Operations
24
23
 
25
- ((first < 0) || (first >= self.collection.count)) ? nil : Page.new(first, last, self)
24
+ def first
25
+ self[FIRST_PAGE_INDEX]
26
+ end
27
+
28
+ def last
29
+ self[total_pages]
26
30
  end
27
31
 
28
32
  def total_pages
29
- (@collection.count.to_f / @@per_page.to_f).ceil
33
+ (@collection.count.to_f / @per_page.to_f).ceil
34
+ end
35
+
36
+ def [](pos)
37
+ Page.new(pos, @collection) unless pos == 0 || pos > total_pages
38
+ end
39
+
40
+ ## Iteration
41
+
42
+ def next!
43
+ raise NoMethodError.new("You need to start before iterating") unless @current
44
+ @current = @current.next
45
+ end
46
+
47
+ def next?
48
+ @current != nil
49
+ end
50
+
51
+ def start
52
+ @current = first
53
+ end
54
+
55
+ def current
56
+ @current
57
+ end
58
+
59
+ def each
60
+ start
61
+
62
+ while next? do
63
+ yield current
64
+
65
+ next!
66
+ end
30
67
  end
31
68
 
32
69
  Paginator.per_page = 10
@@ -1,3 +1,3 @@
1
1
  module SimplyPaginate
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
data/spec/page_spec.rb CHANGED
@@ -1,74 +1,39 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe SimplyPaginate::Page do
4
- before do
5
- SimplyPaginate::Paginator.per_page = 5
3
+ include SimplyPaginate
6
4
 
7
- @paginator = SimplyPaginate::Paginator.new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
8
- @first_page = SimplyPaginate::Page.new(0, 4, @paginator)
9
- @last_page = SimplyPaginate::Page.new(5, 9, @paginator)
5
+ describe Page do
6
+ include Helpers
10
7
 
11
- class SimplyPaginate::Page
12
- def paginator
13
- @paginator
14
- end
15
- end
16
- end
17
-
18
- it "must always have an instance of paginator" do
19
- @first_page.paginator.wont_be_nil
20
- @last_page.paginator.wont_be_nil
8
+ let(:first_page) { build_page 1 }
21
9
 
22
- @first_page.next.paginator.wont_be_nil
23
- @first_page.next.previous.paginator.wont_be_nil
24
- end
10
+ let(:second_page) { build_page 2 }
25
11
 
26
- it "must be able to get the elements" do
27
- @first_page.elements.must_equal [1, 2, 3, 4, 5]
28
- @last_page.elements.must_equal [6, 7, 8, 9, 10]
12
+ let(:last_page) { build_page 4 }
29
13
 
30
- @first_page.next.elements.must_equal [6, 7, 8, 9, 10]
31
- @last_page.previous.elements.must_equal [1, 2, 3, 4, 5]
14
+ it "must represent a specific page on a collection" do
15
+ first_page.elements.must_equal [1, 2, 3]
16
+ first_page.index.must_equal SimplyPaginate::FIRST_PAGE_INDEX
32
17
  end
33
18
 
34
- describe "when having next and previous pages" do
35
- before do
36
- SimplyPaginate::Paginator.per_page = 2
37
- end
38
-
39
- it "must be able to go back and foward" do
40
- @paginator[1].next.elements.must_equal @paginator[2].elements
41
- @paginator[1].previous.elements.must_equal @paginator[0].elements
42
- end
19
+ it "must be able to retrieve it's elements" do
20
+ first_page.elements.must_equal [1, 2, 3]
43
21
  end
44
22
 
45
- describe "when having previous and no next" do
46
- it "must be able to go back " do
47
- @last_page.next.must_be_nil
48
- @last_page.previous.elements.must_equal @first_page.elements
49
- end
23
+ it "must be able to compare with other page" do
24
+ first_page.must_equal first_page
25
+ first_page.wont_equal second_page
26
+ first_page.wont_equal Page.new(1, page_array_collection, 5)
27
+ first_page.must_equal Page.new(1, [1, 2, 3], 3)
50
28
  end
51
29
 
52
- describe "when having next and no previous" do
53
- it "must be able to go back " do
54
- @first_page.next.elements.must_equal @last_page.elements
55
- @first_page.previous.must_be_nil
56
- end
30
+ it "must be able to move forward" do
31
+ first_page.next.must_equal second_page
32
+ last_page.next.must_be_nil
57
33
  end
58
34
 
59
- describe "when moving to previous or next" do
60
- it "must be setted as current when landed after next" do
61
- @paginator[0].next
62
- @paginator[0].current?.must_equal false
63
- @paginator[1].current?.must_equal true
64
- end
65
-
66
- it "must be setted as current when landed after previous" do
67
- @paginator[1].previous
68
- @paginator[1].current?.must_equal false
69
- @paginator[0].current?.must_equal true
70
- end
71
-
35
+ it "must be able to move backwards" do
36
+ first_page.previous.must_be_nil
37
+ second_page.previous.must_equal first_page
72
38
  end
73
-
74
39
  end
@@ -1,50 +1,77 @@
1
1
  require 'spec_helper'
2
2
 
3
+ Paginator.per_page = 3
3
4
 
4
- describe SimplyPaginate::Paginator do
5
- before do
6
- SimplyPaginate::Paginator.per_page = 3
7
- @paginator = SimplyPaginate::Paginator.new [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
8
- end
5
+ describe Paginator do
6
+ include Helpers
7
+
8
+ let(:pages) { Paginator.new page_array_collection }
9
+
10
+ let(:first_page) { build_page 1 }
11
+
12
+ let(:last_page) { build_page 4 }
9
13
 
10
- describe 'before paginating' do
11
- it 'must be able to paginate' do
12
- @paginator.total_pages.must_equal 4
14
+ it "must be able to iterate using each" do
15
+ count = 0
16
+ results = []
17
+
18
+ pages.each do |page|
19
+ page.wont_be_nil
20
+ results << page.elements
21
+
22
+ count += 1
13
23
  end
24
+
25
+ count.must_equal 4
26
+ results.must_equal [[1,2,3], [4,5,6], [7,8,9], [10]]
14
27
  end
15
28
 
16
- describe 'after paginating' do
17
- before do
18
- SimplyPaginate::Paginator.per_page = 5
29
+ it "must be able to tell how many pages there are" do
30
+ pages.total_pages.must_equal 4
31
+ end
19
32
 
20
- @first_page = SimplyPaginate::Page.new(0, 4, @paginator)
21
- @last_page = SimplyPaginate::Page.new(5, 9, @paginator)
33
+ it "must be able to retrieve a certain page" do
34
+ pages[0].must_be_nil
35
+ pages[1].wont_be_nil
36
+ pages[1].must_equal first_page
37
+ pages[4].must_equal last_page
38
+ pages[5].must_be_nil
39
+ end
22
40
 
23
- @pages = [@first_page, @last_page]
24
- end
41
+ it "must be able to retrieve the first page" do
42
+ pages.first.must_equal first_page
43
+ end
25
44
 
26
- it 'must be able to paginate' do
27
- @paginator.total_pages.must_equal 2
28
- end
45
+ it "must be able to retrieve the last page" do
46
+ pages.last.must_equal pages[4]
47
+ end
29
48
 
30
- it 'must be able to retrieve a certain page' do
31
- @paginator[0].elements.must_equal @first_page.elements
32
- @paginator[0].previous.must_be_nil
33
- @paginator[0].next.wont_be_nil
49
+ describe "when iterating using 'start', 'next!' and 'next?'" do
50
+ it "must need to start before moving to the next " do
51
+ lambda { pages.next! }.must_raise NoMethodError
34
52
  end
35
53
 
36
- it 'must be able to retrieve all pages' do
37
- @paginator.total_pages.must_equal 2
54
+ it "must move to the next page using 'next!'" do
55
+ iteration_pages = pages
56
+ iteration_pages.start
57
+ iteration_pages.next!
58
+ iteration_pages.current.must_equal build_page(2)
59
+ end
38
60
 
39
- #test first element
40
- @paginator[0].elements.must_equal @first_page.elements
41
- @paginator[0].previous.must_be_nil
42
- @paginator[0].next.wont_be_nil
61
+ it "must retrieve the current page using 'current'" do
62
+ iteration_pages = pages
63
+ iteration_pages.current.must_be_nil
64
+ iteration_pages.start
65
+ iteration_pages.current.must_equal first_page
66
+ end
43
67
 
44
- #test second element
45
- @paginator[1].elements.must_equal @last_page.elements
46
- @paginator[1].previous.wont_be_nil
47
- @paginator[1].next.must_be_nil
68
+ it "must retrieve if we can get a next value using 'next?'" do
69
+ iteration_pages = pages
70
+ iteration_pages.next?.must_equal false
71
+ iteration_pages.start
72
+ iteration_pages.next?.must_equal true
73
+ 4.times { iteration_pages.next! }
74
+ iteration_pages.next?.must_equal false
48
75
  end
49
76
  end
50
77
  end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,13 @@
1
1
  require 'bundler'
2
2
  require 'minitest/autorun'
3
3
  Bundler.require
4
+
5
+ module Helpers
6
+ def page_array_collection
7
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
8
+ end
9
+
10
+ def build_page(number)
11
+ lambda { Page.new number, page_array_collection, 3 }.call
12
+ end
13
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simply_paginate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-25 00:00:00.000000000 Z
12
+ date: 2013-05-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -72,6 +72,8 @@ files:
72
72
  - LICENSE.txt
73
73
  - README.md
74
74
  - Rakefile
75
+ - examples/data_mapper_example/Gemfile
76
+ - examples/data_mapper_example/test.rb
75
77
  - lib/simply_paginate.rb
76
78
  - lib/simply_paginate/not_in_range_error.rb
77
79
  - lib/simply_paginate/page.rb