paginate 2.0.0 → 3.0.0

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.
@@ -4,6 +4,9 @@ require "paginate/base"
4
4
  require "paginate/config"
5
5
  require "paginate/helper"
6
6
  require "paginate/renderer"
7
+ require "paginate/renderer/list"
8
+ require "paginate/renderer/more"
9
+ require "paginate/extension"
7
10
  require "paginate/active_record"
8
11
  require "paginate/action_controller"
9
12
 
@@ -16,4 +19,5 @@ end
16
19
  Paginate.configure do |config|
17
20
  config.param_name = :page
18
21
  config.size = 10
22
+ config.renderer = Paginate::Renderer::List
19
23
  end
@@ -1,5 +1,17 @@
1
1
  module ActiveRecord
2
2
  class Base
3
- scope :paginate, proc {|*args| Paginate::Base.new(*args).to_options }
3
+ class << self
4
+ def inherited_with_paginate(subclass)
5
+ inherited_without_paginate subclass
6
+ subclass.send(:include, Paginate::Extension) if subclass.superclass == ActiveRecord::Base
7
+ end
8
+
9
+ alias_method_chain :inherited, :paginate
10
+ end
11
+
12
+ # Extend existing models
13
+ self.descendants.each do |model|
14
+ model.send(:include, Paginate::Extension) if model.superclass == ActiveRecord::Base
15
+ end
4
16
  end
5
17
  end
@@ -1,12 +1,15 @@
1
1
  module Paginate
2
2
  class Base
3
3
  attr_accessor :options
4
+ attr_accessor :scope
5
+
6
+ def initialize(scope, options = {})
7
+ @scope = scope
4
8
 
5
- def initialize(options = {})
6
9
  if options.kind_of?(Hash)
7
10
  @options = options
8
11
  else
9
- @options = {:page => options.to_i}
12
+ @options = {page: options.to_i}
10
13
  end
11
14
 
12
15
  @options.reverse_merge!(Paginate::Config.to_hash)
@@ -21,7 +24,7 @@ module Paginate
21
24
  end
22
25
 
23
26
  def previous_page?
24
- options[:page] > 1
27
+ page > 1
25
28
  end
26
29
 
27
30
  def page
@@ -37,7 +40,13 @@ module Paginate
37
40
  end
38
41
 
39
42
  def to_options
40
- { :limit => limit, :offset => offset }
43
+ {limit: limit, offset: offset}
44
+ end
45
+
46
+ def to_scope
47
+ scope
48
+ .limit(limit)
49
+ .offset(offset)
41
50
  end
42
51
  end
43
52
  end
@@ -3,12 +3,14 @@ module Paginate
3
3
  class << self
4
4
  attr_accessor :size
5
5
  attr_accessor :param_name
6
+ attr_accessor :renderer
6
7
  end
7
8
 
8
9
  def self.to_hash
9
10
  {
10
- :size => size,
11
- :param_name => param_name
11
+ size: size,
12
+ param_name: param_name,
13
+ renderer: renderer
12
14
  }
13
15
  end
14
16
  end
@@ -0,0 +1,14 @@
1
+ module Paginate
2
+ module Extension
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ scope :paginate, proc {|*args|
7
+ Paginate::Base.new(
8
+ ActiveRecord::VERSION::MAJOR < 4 ? scoped : all,
9
+ *args
10
+ ).to_scope
11
+ }
12
+ end
13
+ end
14
+ end
@@ -12,6 +12,7 @@ module Paginate
12
12
  # * <tt>:id</tt>: the HTML id that will identify the pagination block.
13
13
  # * <tt>:size</tt>: the page size. When not specified will default to <tt>Paginate::Config.size</tt>.
14
14
  # * <tt>:param_name</tt>: the page param name. When not specified will default to <tt>Paginate::Config.param_name</tt>.
15
+ # * <tt>:renderer</tt>: A class that will be used to render the pagination. When not specified will default to <tt>Paginate::Renderer::List</tt>.
15
16
  #
16
17
  # <%= paginate @posts, proc {|page| posts_path(page) }
17
18
  # <%= paginate @posts, :url => proc {|page| posts_path(page) }
@@ -20,16 +21,28 @@ module Paginate
20
21
  #
21
22
  def paginate(collection, *args)
22
23
  options = args.extract_options!
23
- param_name = [options[:param_name], Paginate::Config.param_name, :page].compact.first
24
+
25
+ param_name = [
26
+ options[:param_name],
27
+ Paginate::Config.param_name,
28
+ :page
29
+ ].compact.first
30
+
31
+ renderer = [
32
+ options[:renderer],
33
+ Paginate::Config.renderer,
34
+ Paginate::Renderer::List
35
+ ].compact.first
36
+
24
37
  options.merge!({
25
- :collection => collection,
26
- :page => params[param_name],
27
- :param_name => param_name,
28
- :fullpath => request.respond_to?(:fullpath) ? request.fullpath : request.request_uri
38
+ collection: collection,
39
+ page: params[param_name],
40
+ param_name: param_name,
41
+ fullpath: request.fullpath
29
42
  })
30
- options.merge!(:url => args.first) if args.any?
31
43
 
32
- Paginate::Renderer.new(options).render
44
+ options.merge!(url: args.first) if args.any?
45
+ renderer.new(self, options).render
33
46
  end
34
47
 
35
48
  # Override the original render method, so we can strip the additional
@@ -49,49 +62,10 @@ module Paginate
49
62
  size = options.delete(:size) { Paginate::Config.size }
50
63
 
51
64
  return super(*[*args, options], &block) unless paginated
52
-
53
65
  collection = options.delete(:collection) { args.shift }
54
66
  collection = collection[0, size]
55
67
 
56
68
  super(collection, *[*args, options], &block)
57
69
  end
58
-
59
- # In order to iterate the correct items you have to skip the last collection's item.
60
- # We added this helper to automatically skip the last item only if there's a next page.
61
- #
62
- # <% iterate @items do |item| %>
63
- # <% end %>
64
- #
65
- # If you want to grab the iteration index as well just expect it as a block parameter.
66
- #
67
- # <% iterate @items do |item, i|
68
- # <% end %>
69
- #
70
- # If you set a custom size while fetching items from database, you need to inform it while iterating.
71
- #
72
- # @items = Item.paginate(:page => 1, :size => 5)
73
- #
74
- # Then in your view:
75
- #
76
- # <% iterate @items, :size => 5 do |item| %>
77
- # <% end %>
78
- #
79
- # You can receive the iteration counter by expecting two arguments.
80
- #
81
- # <% iterate @items do |item, i| do %>
82
- # <% end %>
83
- #
84
- def iterate(collection, options = {}, &block)
85
- options.reverse_merge!(:size => Paginate::Config.size)
86
- yield_index = block.arity == 2
87
-
88
- collection[0, options[:size]].each_with_index do |item, i|
89
- if yield_index
90
- yield item, i
91
- else
92
- yield item
93
- end
94
- end
95
- end
96
70
  end
97
71
  end
@@ -1,73 +1,57 @@
1
1
  module Paginate
2
- class Renderer
3
- attr_accessor :options
4
- attr_accessor :current_page
5
-
6
- def initialize(options)
7
- @current_page = [options[:page].to_i, 1].max
8
- options.reverse_merge!(Paginate::Config.to_hash)
9
- @options = options.merge(:page => current_page)
10
- end
11
-
12
- def processor
13
- @processor ||= Paginate::Base.new(options)
14
- end
15
-
16
- def url_for(page)
17
- url = options[:url] || options[:fullpath]
18
-
19
- if url.respond_to?(:call)
20
- url = url.call(page).to_s.dup
21
- else
22
- url = url.dup
23
-
24
- re = Regexp.new("([&?])#{Regexp.escape(options[:param_name].to_s)}=[^&]*")
25
- url.gsub!(re, "\\1")
26
- url.gsub!(/[\?&]$/, "")
27
- url.gsub!(/&+/, "&")
28
- url.gsub!(/\?&/, "?")
29
-
30
- url << (url =~ /\?/ ? "&" : "?")
31
- url << page.to_query(options[:param_name])
2
+ module Renderer
3
+ class Base
4
+ # Set the pagination options.
5
+ attr_reader :options
6
+
7
+ # Set the view context. You can use this object
8
+ # to call view and url helpers.
9
+ attr_reader :view_context
10
+
11
+ # Set the object with defines all pagination methods
12
+ # like `Paginate::Base#next_page?`.
13
+ attr_reader :processor
14
+
15
+ def initialize(view_context, options)
16
+ @view_context = view_context
17
+ @options = options.reverse_merge(Paginate::Config.to_hash)
18
+ @processor = Paginate::Base.new(nil, options)
32
19
  end
33
20
 
34
- url.gsub!(/&/, "&amp;")
35
- url
36
- end
37
-
38
- def render
39
- html = String.new
40
- previous_label = I18n.t("paginate.previous")
41
- previous_url = url_for(options[:page] - 1)
42
- next_label = I18n.t("paginate.next")
43
- next_url = url_for(options[:page] + 1)
44
- page_label = I18n.t("paginate.page", options)
45
-
46
- css = %w[ paginate ]
47
- css << "disabled" unless processor.previous_page? || processor.next_page?
48
-
49
- html << %[<ul class="#{css.join(" ")}">]
50
-
51
- # Previous page
52
- if processor.previous_page?
53
- html << %[<li class="previous-page"><a href="#{previous_url}" title="#{previous_label}">#{previous_label}</a></li>]
54
- else
55
- html << %[<li class="previous-page disabled"><span title="#{previous_label}">#{previous_label}</span></li>]
21
+ # Return the URL for previous page.
22
+ def previous_url
23
+ url_for(processor.page - 1)
56
24
  end
57
25
 
58
- # Current page
59
- html << %[<li class="page"><span>#{page_label}</span></li>]
60
-
61
- # Next page
62
- if processor.next_page?
63
- html << %[<li class="next-page"><a href="#{next_url}" title="#{next_label}">#{next_label}</a></li>]
64
- else
65
- html << %[<li class="next-page disabled"><span title="#{next_label}">#{next_label}</span></li>]
26
+ # Return the URL for next page.
27
+ def next_url
28
+ url_for(processor.page + 1)
66
29
  end
67
30
 
68
- html << %[</ul>]
69
-
70
- html.html_safe
31
+ # Compute the URL for a given page.
32
+ # It will keep track of all query string and replace the
33
+ # page parameter with the specified `page`.
34
+ def url_for(page)
35
+ url = options[:url] || options[:fullpath]
36
+
37
+ if url.respond_to?(:call)
38
+ url = url.call(page).to_s.dup
39
+ else
40
+ url = url.dup
41
+
42
+ re = Regexp.new("([&?])#{Regexp.escape(options[:param_name].to_s)}=[^&]*")
43
+ url.gsub!(re, "\\1")
44
+ url.gsub!(/[\?&]$/, "")
45
+ url.gsub!(/&+/, "&")
46
+ url.gsub!(/\?&/, "?")
47
+
48
+ url << (url =~ /\?/ ? "&" : "?")
49
+ url << page.to_query(options[:param_name])
50
+ end
51
+
52
+ url.gsub!(/&/, "&amp;")
53
+ url
54
+ end
71
55
  end
72
56
  end
73
57
  end
@@ -0,0 +1,47 @@
1
+ module Paginate
2
+ module Renderer
3
+ class List < Base
4
+ def previous_label
5
+ I18n.t("paginate.previous")
6
+ end
7
+
8
+ def next_label
9
+ I18n.t("paginate.next")
10
+ end
11
+
12
+ def page_label
13
+ I18n.t("paginate.page", page: processor.page)
14
+ end
15
+
16
+ def render
17
+ html = String.new
18
+
19
+ css = %w[ paginate ]
20
+ css << "disabled" unless processor.previous_page? || processor.next_page?
21
+
22
+ html << %[<ul class="#{css.join(" ")}">]
23
+
24
+ # Previous page
25
+ if processor.previous_page?
26
+ html << %[<li class="previous-page"><a href="#{previous_url}" title="#{previous_label}">#{previous_label}</a></li>]
27
+ else
28
+ html << %[<li class="previous-page disabled"><span title="#{previous_label}">#{previous_label}</span></li>]
29
+ end
30
+
31
+ # Current page
32
+ html << %[<li class="page"><span>#{page_label}</span></li>]
33
+
34
+ # Next page
35
+ if processor.next_page?
36
+ html << %[<li class="next-page"><a href="#{next_url}" title="#{next_label}">#{next_label}</a></li>]
37
+ else
38
+ html << %[<li class="next-page disabled"><span title="#{next_label}">#{next_label}</span></li>]
39
+ end
40
+
41
+ html << %[</ul>]
42
+
43
+ html.html_safe
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,19 @@
1
+ module Paginate
2
+ module Renderer
3
+ class More < Base
4
+ def more_label
5
+ I18n.t("paginate.more")
6
+ end
7
+
8
+ def render
9
+ return unless processor.next_page?
10
+
11
+ <<-HTML.html_safe
12
+ <p class="paginate">
13
+ <a class="more" href="#{next_url}" title="#{more_label}">#{more_label}</a>
14
+ </p>
15
+ HTML
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,6 +1,6 @@
1
1
  module Paginate
2
2
  module Version
3
- MAJOR = 2
3
+ MAJOR = 3
4
4
  MINOR = 0
5
5
  PATCH = 0
6
6
  STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
@@ -20,9 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.add_development_dependency "nokogiri"
21
21
  s.add_development_dependency "test_notifier"
22
22
  s.add_development_dependency "sqlite3-ruby"
23
- s.add_development_dependency "activesupport"
24
- s.add_development_dependency "activerecord"
25
- s.add_development_dependency "actionpack"
26
- s.add_development_dependency "rspec"
23
+ s.add_development_dependency "rails", "~> 4.0.0"
24
+ s.add_development_dependency "rspec", "~> 2.14.0.rc1"
27
25
  s.add_development_dependency "pry-meta"
28
26
  end
@@ -15,7 +15,7 @@ describe "ActionView support" do
15
15
  @view.lookup_context.prefixes << "application"
16
16
  @view.controller = @controller
17
17
  @view.extend(Paginate::Helper)
18
- @view.stub :request => @request
18
+ @view.stub request: @request
19
19
 
20
20
  @helper = Object.new
21
21
  @helper.extend(Paginate::Helper)
@@ -28,84 +28,6 @@ describe "ActionView support" do
28
28
  I18n.locale = :en
29
29
  end
30
30
 
31
- it "displays pagination list" do
32
- @request.fullpath = "/some/path?page=1"
33
- html = render(:default, [])
34
-
35
- expect(html.css("ul.paginate").count).to eql(1)
36
- expect(html.css("ul.paginate > li").count).to eql(3)
37
- end
38
-
39
- it "adds .disabled class when have no items" do
40
- @request.fullpath = "/some/path"
41
- html = render(:default, [])
42
-
43
- expect(html.css("ul.paginate.disabled").first).to be
44
- end
45
-
46
- it "displays next page link" do
47
- @request.fullpath = "/some/path?page=1"
48
- html = render(:default, Array.new(11))
49
- link = html.css("li.next-page > a").first
50
-
51
- expect(link).to be
52
- expect(link["href"]).to eql("/some/path?page=2")
53
- expect(link.text).to eql("Next page")
54
- end
55
-
56
- it "displays next page link using proc as url" do
57
- @request.fullpath = "/some/path?page=1"
58
- html = render(:block_as_url, Array.new(11))
59
- link = html.css("li.next-page > a").first
60
-
61
- expect(link).to be
62
- expect(link["href"]).to eql("/some/path/2")
63
- expect(link.text).to eql("Next page")
64
- end
65
-
66
- it "displays previous page link" do
67
- @params[:page] = 2
68
- @request.fullpath = "/some/path?page=2"
69
- html = render(:default, Array.new(11))
70
- link = html.css("li.previous-page > a").first
71
-
72
- expect(link).to be
73
- expect(link["href"]).to eql("/some/path?page=1")
74
- expect(link.text).to eql("Previous page")
75
- end
76
-
77
- it "disables element when have no next page" do
78
- @request.fullpath = "/some/path?page=1"
79
- html = render(:default, Array.new(10))
80
- link = html.css("li.next-page > a").first
81
- span = html.css("li.next-page.disabled > span").first
82
-
83
- expect(link).not_to be
84
- expect(span).to be
85
- expect(span.text).to eql("Next page")
86
- end
87
-
88
- it "disables element when have no previous page" do
89
- @request.fullpath = "/some/path?page=1"
90
- html = render(:default, Array.new(10))
91
- link = html.css("li.previous-page > a").first
92
- span = html.css("li.previous-page.disabled > span").first
93
-
94
- expect(link).not_to be
95
- expect(span).to be
96
- expect(span.text).to eql("Previous page")
97
- end
98
-
99
- it "displays current page" do
100
- @params[:page] = 10
101
- @request.fullpath = "/some/path?page=10"
102
- html = render(:default, [])
103
- span = html.css("li.page > span").first
104
-
105
- expect(span).to be
106
- expect(span.text).to eql("Page 10")
107
- end
108
-
109
31
  it "overrides render method" do
110
32
  items = [*1..11].map do |i|
111
33
  OpenStruct.new(:to_partial_path => "number", :value => i)
@@ -114,58 +36,11 @@ describe "ActionView support" do
114
36
  html = render(:render, items)
115
37
  end
116
38
 
117
- it "translates strings" do
118
- I18n.locale = :"pt-BR"
119
-
120
- @params[:page] = 10
121
- @request.fullpath = "/some/path?page=10"
122
- html = render(:default, Array.new(11))
123
-
124
- expect(html.css("li.page > span").text).to eql("Página 10")
125
- expect(html.css("li.next-page > a").text).to eql("Próxima página")
126
- expect(html.css("li.previous-page > a").text).to eql("Página anterior")
127
- end
128
-
129
- it "skips the last item while iterating" do
130
- values = []
131
- items = Array.new(11) {|i| "User#{i}" }
132
-
133
- @helper.iterate items do |item|
134
- values << item
135
- end
136
-
137
- expect(values).to eql(items[0, 10])
138
- end
139
-
140
- it "iterates all items when have less records than size" do
141
- values = []
142
- items = Array.new(8) {|i| "User#{i}" }
143
-
144
- @helper.iterate items do |item|
145
- values << item
146
- end
147
-
148
- expect(values).to eql(items[0, 8])
149
- end
150
-
151
- it "yields iteration counter" do
152
- values = []
153
- indices = []
154
- items = Array.new(11) {|i| "User#{i}" }
155
-
156
- @helper.iterate items do |item, i|
157
- values << item
158
- indices << i
159
- end
160
-
161
- expect(values).to eql(items[0, 10])
162
- expect(indices).to eql([*0...10])
163
- end
164
-
165
39
  private
166
40
  def render(view_name, items)
41
+ @controller.params = @params
167
42
  view_info = Struct.new(:to_partial_path).new("#{view_name}")
168
- Nokogiri @view.render(view_info, :items => items)
43
+ Nokogiri @view.render(view_info, items: items)
169
44
  end
170
45
 
171
46
  def load_view(name)