paginate 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)