will_paginate 3.0.pre4 → 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.

Potentially problematic release.


This version of will_paginate might be problematic. Click here for more details.

Files changed (51) hide show
  1. data/README.md +61 -0
  2. data/Rakefile +19 -36
  3. data/lib/will_paginate.rb +16 -14
  4. data/lib/will_paginate/{finders/active_record.rb → active_record.rb} +66 -35
  5. data/lib/will_paginate/array.rb +5 -5
  6. data/lib/will_paginate/collection.rb +12 -36
  7. data/lib/will_paginate/core_ext.rb +0 -28
  8. data/lib/will_paginate/data_mapper.rb +91 -0
  9. data/lib/will_paginate/i18n.rb +22 -0
  10. data/lib/will_paginate/locale/en.yml +33 -0
  11. data/lib/will_paginate/page_number.rb +57 -0
  12. data/lib/will_paginate/per_page.rb +27 -0
  13. data/lib/will_paginate/railtie.rb +13 -4
  14. data/lib/will_paginate/sequel.rb +36 -0
  15. data/lib/will_paginate/version.rb +1 -1
  16. data/lib/will_paginate/view_helpers.rb +136 -22
  17. data/lib/will_paginate/view_helpers/action_view.rb +129 -117
  18. data/lib/will_paginate/view_helpers/link_renderer.rb +10 -11
  19. data/lib/will_paginate/view_helpers/link_renderer_base.rb +2 -8
  20. data/lib/will_paginate/view_helpers/merb.rb +20 -7
  21. data/lib/will_paginate/view_helpers/sinatra.rb +41 -0
  22. data/spec/ci.rb +29 -0
  23. data/spec/collection_spec.rb +7 -23
  24. data/spec/console +9 -1
  25. data/spec/console_fixtures.rb +1 -3
  26. data/spec/database.yml +10 -10
  27. data/spec/finders/active_record_spec.rb +82 -28
  28. data/spec/finders/activerecord_test_connector.rb +9 -1
  29. data/spec/finders/data_mapper_spec.rb +59 -48
  30. data/spec/finders/data_mapper_test_connector.rb +8 -1
  31. data/spec/finders/sequel_spec.rb +9 -3
  32. data/spec/fixtures/project.rb +2 -0
  33. data/spec/page_number_spec.rb +65 -0
  34. data/spec/per_page_spec.rb +41 -0
  35. data/spec/spec_helper.rb +5 -29
  36. data/spec/view_helpers/action_view_spec.rb +48 -32
  37. data/spec/view_helpers/base_spec.rb +59 -7
  38. data/spec/view_helpers/link_renderer_base_spec.rb +7 -12
  39. data/spec/view_helpers/view_example_group.rb +1 -0
  40. metadata +22 -23
  41. data/CHANGELOG.rdoc +0 -105
  42. data/README.rdoc +0 -111
  43. data/lib/will_paginate/deprecation.rb +0 -50
  44. data/lib/will_paginate/finders.rb +0 -9
  45. data/lib/will_paginate/finders/active_resource.rb +0 -51
  46. data/lib/will_paginate/finders/base.rb +0 -112
  47. data/lib/will_paginate/finders/data_mapper.rb +0 -30
  48. data/lib/will_paginate/finders/sequel.rb +0 -23
  49. data/lib/will_paginate/view_helpers/base.rb +0 -126
  50. data/spec/finders/active_resource_spec.rb +0 -52
  51. data/spec/finders_spec.rb +0 -76
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # will_paginate
2
+
3
+ will_paginate is a pagination library that integrates with Ruby on Rails, Sinatra, Merb, DataMapper and Sequel.
4
+
5
+ Installation:
6
+
7
+ ``` ruby
8
+ ## Gemfile for Rails 3, Sinatra, and Merb
9
+ gem 'will_paginate', '~> 3.0.pre4'
10
+ ```
11
+
12
+ See [installation instructions][install] on the wiki for more info.
13
+
14
+
15
+ ## Basic will_paginate use
16
+
17
+ ``` ruby
18
+ ## perform a paginated query:
19
+ @posts = Post.paginate(:page => params[:page])
20
+
21
+ # or, use an explicit "per page" limit:
22
+ Post.paginate(:page => params[:page], :per_page => 30)
23
+
24
+ ## render page links in the view:
25
+ <%= will_paginate @posts %>
26
+ ```
27
+
28
+ And that's it! You're done. You just need to add some CSS styles to [make those pagination links prettier][css].
29
+
30
+ You can customize the default "per_page" value:
31
+
32
+ ``` ruby
33
+ # for the Post model
34
+ class Post
35
+ self.per_page = 10
36
+ end
37
+
38
+ # set per_page globally
39
+ WillPaginate.per_page = 10
40
+ ```
41
+
42
+ New in Active Record 3:
43
+
44
+ ``` ruby
45
+ # paginate in Active Record now returns a Relation
46
+ Post.where(:published => true).paginate(:page => params[:page]).order('id DESC')
47
+
48
+ # the new, shorter page() method
49
+ Post.page(params[:page]).order('created_at DESC')
50
+ ```
51
+
52
+ See [the wiki][wiki] for more documentation. [Ask on the group][group] if you have usage questions. [Report bugs][issues] on GitHub.
53
+
54
+ Happy paginating.
55
+
56
+
57
+ [wiki]: https://github.com/mislav/will_paginate/wiki
58
+ [install]: https://github.com/mislav/will_paginate/wiki/Installation "will_paginate installation"
59
+ [group]: http://groups.google.com/group/will_paginate "will_paginate discussion and support group"
60
+ [issues]: https://github.com/mislav/will_paginate/issues
61
+ [css]: http://mislav.uniqpath.com/will_paginate/
data/Rakefile CHANGED
@@ -1,42 +1,25 @@
1
- require 'rake/rdoctask'
2
- require 'rspec/core/rake_task'
1
+ begin
2
+ require 'rspec/core/rake_task'
3
+ rescue LoadError
4
+ # no spec tasks
5
+ else
6
+ task :default => :spec
3
7
 
4
- task :default => :spec
5
-
6
- desc 'Run ALL OF the specs'
7
- RSpec::Core::RakeTask.new(:spec) do |t|
8
- # t.ruby_opts = '-w'
9
- end
10
-
11
- namespace :spec do
12
- desc "Run Rails specs"
13
- RSpec::Core::RakeTask.new(:rails) do |t|
14
- t.pattern = %w'spec/finders/active_record_spec.rb spec/view_helpers/action_view_spec.rb'
8
+ desc 'Run ALL OF the specs'
9
+ RSpec::Core::RakeTask.new(:spec) do |t|
10
+ # t.ruby_opts = '-w'
11
+ t.pattern = 'spec/finders/active_record_spec.rb' if ENV['DB'] and ENV['DB'] != 'sqlite3'
15
12
  end
16
- end
17
13
 
18
- desc 'Generate RDoc documentation for the will_paginate plugin.'
19
- Rake::RDocTask.new(:rdoc) do |rdoc|
20
- rdoc.rdoc_files.include('README.rdoc', 'LICENSE', 'CHANGELOG.rdoc').
21
- include('lib/**/*.rb').
22
- exclude('lib/will_paginate/finders/active_record/named_scope*').
23
- exclude('lib/will_paginate/finders/sequel.rb').
24
- exclude('lib/will_paginate/view_helpers/merb.rb').
25
- exclude('lib/will_paginate/deprecation.rb').
26
- exclude('lib/will_paginate/core_ext.rb').
27
- exclude('lib/will_paginate/version.rb')
28
-
29
- rdoc.main = "README.rdoc" # page to start on
30
- rdoc.title = "will_paginate documentation"
31
-
32
- rdoc.rdoc_dir = 'doc' # rdoc output folder
33
- rdoc.options << '--inline-source' << '--charset=UTF-8'
34
- rdoc.options << '--webcvs=http://github.com/mislav/will_paginate/tree/master/'
14
+ namespace :spec do
15
+ desc "Run Rails specs"
16
+ RSpec::Core::RakeTask.new(:rails) do |t|
17
+ t.pattern = %w'spec/finders/active_record_spec.rb spec/view_helpers/action_view_spec.rb'
18
+ end
19
+ end
35
20
  end
36
21
 
37
- task :website do
38
- Dir.chdir('website') do
39
- %x(haml index.haml index.html)
40
- %x(sass pagination.sass pagination.css)
41
- end
22
+ desc 'Run specs against both Rails 3.1 and Rails 3.0'
23
+ task :rails3 do |variable|
24
+ system 'bundle exec rake spec && BUNDLE_GEMFILE=Gemfile.rails3.0 bundle exec rake spec:rails'
42
25
  end
data/lib/will_paginate.rb CHANGED
@@ -1,23 +1,25 @@
1
- require 'will_paginate/deprecation'
2
-
3
- # = You *will* paginate!
4
- #
5
- # First read about WillPaginate::Finders::Base, then see
6
- # WillPaginate::ViewHelpers. The magical array you're handling in-between is
7
- # WillPaginate::Collection.
8
- #
9
- # Happy paginating!
1
+ # You will paginate!
10
2
  module WillPaginate
11
3
  end
12
4
 
13
- if defined?(::Rails::Railtie)
5
+ if defined?(Rails::Railtie)
14
6
  require 'will_paginate/railtie'
7
+ elsif defined?(Rails::Initializer)
8
+ raise "will_paginate 3.0 is not compatible with Rails 2.3 or older"
15
9
  end
16
10
 
17
- if defined?(::Merb::Plugins)
11
+ if defined?(Merb::AbstractController)
18
12
  require 'will_paginate/view_helpers/merb'
19
- # auto-load the right ORM adapter
20
- if adapter = { :datamapper => 'data_mapper', :activerecord => 'active_record', :sequel => 'sequel' }[Merb.orm]
21
- require "will_paginate/finders/#{adapter}"
13
+
14
+ Merb::BootLoader.before_app_loads do
15
+ adapters = { :datamapper => 'data_mapper', :activerecord => 'active_record', :sequel => 'sequel' }
16
+ # auto-load the right ORM adapter
17
+ if adapter = adapters[Merb.orm]
18
+ require "will_paginate/#{adapter}"
19
+ end
22
20
  end
23
21
  end
22
+
23
+ if defined?(Sinatra) and Sinatra.respond_to? :register
24
+ require 'will_paginate/view_helpers/sinatra'
25
+ end
@@ -1,7 +1,9 @@
1
- require 'will_paginate/finders/base'
1
+ require 'will_paginate/per_page'
2
+ require 'will_paginate/page_number'
3
+ require 'will_paginate/collection'
2
4
  require 'active_record'
3
5
 
4
- module WillPaginate::Finders
6
+ module WillPaginate
5
7
  # = Paginating finders for ActiveRecord models
6
8
  #
7
9
  # WillPaginate adds +paginate+, +per_page+ and other methods to
@@ -14,23 +16,6 @@ module WillPaginate::Finders
14
16
  # @posts = Post.paginate :all, :page => params[:page], :order => 'created_at DESC'
15
17
  #
16
18
  module ActiveRecord
17
- # In Rails, this is automatically called to mix-in pagination functionality to ActiveRecord.
18
- def self.enable!
19
- ::ActiveRecord::Base.extend Base
20
- ::ActiveRecord::Base.extend ActiveRecord::Pagination
21
- ::ActiveRecord::Base.extend ActiveRecord::BaseMethods
22
-
23
- klasses = [::ActiveRecord::Relation]
24
- if defined? ::ActiveRecord::Associations::CollectionProxy
25
- klasses << ::ActiveRecord::Associations::CollectionProxy
26
- else
27
- klasses << ::ActiveRecord::Associations::AssociationCollection
28
- end
29
-
30
- # support pagination on associations and scopes
31
- klasses.each { |klass| klass.send(:include, ActiveRecord::Pagination) }
32
- end
33
-
34
19
  # makes a Relation look like WillPaginate::Collection
35
20
  module RelationMethods
36
21
  attr_accessor :current_page
@@ -46,7 +31,7 @@ module WillPaginate::Finders
46
31
  def limit(num)
47
32
  rel = super
48
33
  if rel.current_page
49
- rel.offset((rel.current_page-1) * rel.limit_value)
34
+ rel.offset rel.current_page.to_offset(rel.limit_value).to_i
50
35
  else
51
36
  rel
52
37
  end
@@ -63,16 +48,27 @@ module WillPaginate::Finders
63
48
  if loaded? and size < limit_value and (current_page == 1 or size > 0)
64
49
  offset_value + size
65
50
  else
66
- excluded = [:order, :limit, :offset]
67
- excluded << :includes unless eager_loading?
68
- rel = self.except(*excluded)
69
- # TODO: hack. decide whether to keep
70
- rel = rel.apply_finder_options(@wp_count_options) if defined? @wp_count_options
71
- rel.count
51
+ @total_entries_queried = true
52
+ result = count
53
+ result = result.size if result.respond_to?(:size) and !result.is_a?(Integer)
54
+ result
72
55
  end
73
56
  end
74
57
  end
75
58
 
59
+ def count
60
+ if limit_value
61
+ excluded = [:order, :limit, :offset]
62
+ excluded << :includes unless eager_loading?
63
+ rel = self.except(*excluded)
64
+ # TODO: hack. decide whether to keep
65
+ rel = rel.apply_finder_options(@wp_count_options) if defined? @wp_count_options
66
+ rel.count
67
+ else
68
+ super
69
+ end
70
+ end
71
+
76
72
  # workaround for Active Record 3.0
77
73
  def size
78
74
  if !loaded? and limit_value
@@ -82,6 +78,15 @@ module WillPaginate::Finders
82
78
  end
83
79
  end
84
80
 
81
+ # overloaded to be pagination-aware
82
+ def empty?
83
+ if !loaded? and offset_value
84
+ count <= offset_value
85
+ else
86
+ super
87
+ end
88
+ end
89
+
85
90
  def total_pages
86
91
  (total_entries / limit_value.to_f).ceil
87
92
  end
@@ -89,7 +94,8 @@ module WillPaginate::Finders
89
94
  def clone
90
95
  other = super
91
96
  other.current_page = current_page unless other.current_page
92
- other.total_entries = nil
97
+ other.total_entries = nil if defined? @total_entries_queried
98
+ other.wp_count_options = @wp_count_options if defined? @wp_count_options
93
99
  other
94
100
  end
95
101
 
@@ -106,20 +112,26 @@ module WillPaginate::Finders
106
112
 
107
113
  module Pagination
108
114
  def paginate(options)
109
- pagenum, per_page, total = wp_parse_options(options)
110
- count_options = options[:count]
111
- options = options.except(:page, :per_page, :total_entries, :count)
112
- rel = limit(per_page).page(pagenum)
115
+ options = options.dup
116
+ pagenum = options.fetch(:page) { raise ArgumentError, ":page parameter required" }
117
+ per_page = options.delete(:per_page) || self.per_page
118
+ total = options.delete(:total_entries)
119
+
120
+ count_options = options.delete(:count)
121
+ options.delete(:page)
122
+
123
+ rel = limit(per_page.to_i).page(pagenum)
113
124
  rel = rel.apply_finder_options(options) if options.any?
114
125
  rel.wp_count_options = count_options if count_options
126
+ rel.total_entries = total.to_i unless total.blank?
115
127
  rel
116
128
  end
117
129
 
118
130
  def page(num)
119
- pagenum = num.nil? ? 1 : num.to_i
120
- raise ::WillPaginate::InvalidPage, num, pagenum if pagenum < 1
121
131
  rel = scoped.extending(RelationMethods)
122
- rel = rel.offset((pagenum-1) * (rel.limit_value || per_page))
132
+ pagenum = ::WillPaginate::PageNumber(num.nil? ? 1 : num)
133
+ per_page = rel.limit_value || self.per_page
134
+ rel = rel.offset(pagenum.to_offset(per_page).to_i)
123
135
  rel = rel.limit(per_page) unless rel.limit_value
124
136
  rel.current_page = pagenum
125
137
  rel
@@ -142,7 +154,11 @@ module WillPaginate::Finders
142
154
  # application.
143
155
  #
144
156
  def paginate_by_sql(sql, options)
145
- WillPaginate::Collection.create(*wp_parse_options(options)) do |pager|
157
+ pagenum = options.fetch(:page) { raise ArgumentError, ":page parameter required" }
158
+ per_page = options[:per_page] || self.per_page
159
+ total = options[:total_entries]
160
+
161
+ WillPaginate::Collection.create(pagenum, per_page, total) do |pager|
146
162
  query = sanitize_sql(sql.dup)
147
163
  original_query = query.dup
148
164
  # add limit, offset
@@ -163,5 +179,20 @@ module WillPaginate::Finders
163
179
  end
164
180
  end
165
181
  end
182
+
183
+ # mix everything into Active Record
184
+ ::ActiveRecord::Base.extend PerPage
185
+ ::ActiveRecord::Base.extend Pagination
186
+ ::ActiveRecord::Base.extend BaseMethods
187
+
188
+ klasses = [::ActiveRecord::Relation]
189
+ if defined? ::ActiveRecord::Associations::CollectionProxy
190
+ klasses << ::ActiveRecord::Associations::CollectionProxy
191
+ else
192
+ klasses << ::ActiveRecord::Associations::AssociationCollection
193
+ end
194
+
195
+ # support pagination on associations and scopes
196
+ klasses.each { |klass| klass.send(:include, Pagination) }
166
197
  end
167
198
  end
@@ -22,11 +22,11 @@ class Array
22
22
  # McAdam}[http://www.desimcadam.com/archives/8] and later proved to be the
23
23
  # most useful method of will_paginate library.
24
24
  def paginate(options = {})
25
- raise ArgumentError, "parameter hash expected (got #{options.inspect})" unless Hash === options
26
-
27
- WillPaginate::Collection.create options[:page] || 1,
28
- options[:per_page] || 30,
29
- options[:total_entries] || self.length do |pager|
25
+ page = options[:page] || 1
26
+ per_page = options[:per_page] || WillPaginate.per_page
27
+ total = options[:total_entries] || self.length
28
+
29
+ WillPaginate::Collection.create(page, per_page, total) do |pager|
30
30
  pager.replace self[pager.offset, pager.per_page].to_a
31
31
  end
32
32
  end
@@ -1,27 +1,7 @@
1
+ require 'will_paginate/per_page'
2
+ require 'will_paginate/page_number'
3
+
1
4
  module WillPaginate
2
- # = Invalid page number error
3
- # This is an ArgumentError raised in case a page was requested that is either
4
- # zero or negative number. You should decide how do deal with such errors in
5
- # the controller.
6
- #
7
- # If you're using Rails 2, then this error will automatically get handled like
8
- # 404 Not Found. The hook is in "will_paginate.rb":
9
- #
10
- # ActionController::Base.rescue_responses['WillPaginate::InvalidPage'] = :not_found
11
- #
12
- # If you don't like this, use your preffered method of rescuing exceptions in
13
- # public from your controllers to handle this differently. The +rescue_from+
14
- # method is a nice addition to Rails 2.
15
- #
16
- # This error is *not* raised when a page further than the last page is
17
- # requested. Use <tt>WillPaginate::Collection#out_of_bounds?</tt> method to
18
- # check for those cases and manually deal with them as you see fit.
19
- class InvalidPage < ArgumentError
20
- def initialize(page, page_num) #:nodoc:
21
- super "#{page.inspect} given as value, which translates to '#{page_num}' as page number"
22
- end
23
- end
24
-
25
5
  # = The key to pagination
26
6
  # Arrays returned from paginating finds are, in fact, instances of this little
27
7
  # class. You may think of WillPaginate::Collection as an ordinary array with
@@ -33,12 +13,10 @@ module WillPaginate
33
13
  #
34
14
  # If you are writing a library that provides a collection which you would like
35
15
  # to conform to this API, you don't have to copy these methods over; simply
36
- # make your plugin/gem dependant on the "will_paginate" gem:
16
+ # make your plugin/gem dependant on this library and do:
37
17
  #
38
- # gem 'will_paginate'
39
18
  # require 'will_paginate/collection'
40
- #
41
- # # now use WillPaginate::Collection directly or subclass it
19
+ # # WillPaginate::Collection is now available for use
42
20
  class Collection < Array
43
21
  attr_reader :current_page, :per_page, :total_entries, :total_pages
44
22
 
@@ -46,12 +24,9 @@ module WillPaginate
46
24
  # and the total number of entries. The last argument is optional because it
47
25
  # is best to do lazy counting; in other words, count *conditionally* after
48
26
  # populating the collection using the +replace+ method.
49
- def initialize(page, per_page, total = nil)
50
- @current_page = page.to_i
51
- raise InvalidPage.new(page, @current_page) if @current_page < 1
27
+ def initialize(page, per_page = WillPaginate.per_page, total = nil)
28
+ @current_page = WillPaginate::PageNumber(page)
52
29
  @per_page = per_page.to_i
53
- raise ArgumentError, "`per_page` setting cannot be less than 1 (#{@per_page} given)" if @per_page < 1
54
-
55
30
  self.total_entries = total if total
56
31
  end
57
32
 
@@ -82,7 +57,7 @@ module WillPaginate
82
57
  #
83
58
  # The Array#paginate API has since then changed, but this still serves as a
84
59
  # fine example of WillPaginate::Collection usage.
85
- def self.create(page, per_page, total = nil, &block)
60
+ def self.create(page, per_page, total = nil)
86
61
  pager = new(page, per_page, total)
87
62
  yield pager
88
63
  pager
@@ -98,9 +73,9 @@ module WillPaginate
98
73
  # Current offset of the paginated collection. If we're on the first page,
99
74
  # it is always 0. If we're on the 2nd page and there are 30 entries per page,
100
75
  # the offset is 30. This property is useful if you want to render ordinals
101
- # besides your records: simply start with offset + 1.
76
+ # side by side with records in the view: simply start with offset + 1.
102
77
  def offset
103
- (current_page - 1) * per_page
78
+ @current_page.to_offset(per_page).to_i
104
79
  end
105
80
 
106
81
  # current_page - 1 or nil if there is no previous page
@@ -112,7 +87,8 @@ module WillPaginate
112
87
  def next_page
113
88
  current_page < total_pages ? (current_page + 1) : nil
114
89
  end
115
-
90
+
91
+ # sets the <tt>total_entries</tt> property and calculates <tt>total_pages</tt>
116
92
  def total_entries=(number)
117
93
  @total_entries = number.to_i
118
94
  @total_pages = (@total_entries / per_page.to_f).ceil
@@ -1,5 +1,4 @@
1
1
  require 'set'
2
- require 'will_paginate/array'
3
2
 
4
3
  # copied from ActiveSupport so we don't depend on it
5
4
 
@@ -18,33 +17,6 @@ unless Hash.method_defined? :except
18
17
  end
19
18
  end
20
19
 
21
- unless Hash.method_defined? :slice
22
- Hash.class_eval do
23
- # Returns a new hash with only the given keys.
24
- def slice(*keys)
25
- allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
26
- reject { |key,| !allowed.include?(key) }
27
- end
28
-
29
- # Replaces the hash with only the given keys.
30
- def slice!(*keys)
31
- replace(slice(*keys))
32
- end
33
- end
34
- end
35
-
36
- unless String.method_defined? :constantize
37
- String.class_eval do
38
- def constantize
39
- unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ self
40
- raise NameError, "#{self.inspect} is not a valid constant name!"
41
- end
42
-
43
- Object.module_eval("::#{$1}", __FILE__, __LINE__)
44
- end
45
- end
46
- end
47
-
48
20
  unless String.method_defined? :underscore
49
21
  String.class_eval do
50
22
  def underscore