kaminari 0.14.1 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/.document +1 -4
  3. data/.gitignore +1 -0
  4. data/.travis.yml +52 -5
  5. data/{CHANGELOG → CHANGELOG.rdoc} +129 -0
  6. data/Gemfile +1 -1
  7. data/README.rdoc +66 -25
  8. data/Rakefile +32 -9
  9. data/app/views/kaminari/_first_page.html.erb +1 -1
  10. data/app/views/kaminari/_first_page.html.haml +1 -1
  11. data/app/views/kaminari/_first_page.html.slim +1 -1
  12. data/app/views/kaminari/_gap.html.erb +1 -1
  13. data/app/views/kaminari/_gap.html.haml +1 -1
  14. data/app/views/kaminari/_gap.html.slim +1 -1
  15. data/app/views/kaminari/_last_page.html.erb +1 -1
  16. data/app/views/kaminari/_last_page.html.haml +1 -1
  17. data/app/views/kaminari/_last_page.html.slim +1 -1
  18. data/app/views/kaminari/_next_page.html.erb +1 -1
  19. data/app/views/kaminari/_next_page.html.haml +1 -1
  20. data/app/views/kaminari/_next_page.html.slim +1 -1
  21. data/app/views/kaminari/_prev_page.html.erb +1 -1
  22. data/app/views/kaminari/_prev_page.html.haml +1 -1
  23. data/app/views/kaminari/_prev_page.html.slim +1 -1
  24. data/gemfiles/active_record_30.gemfile +25 -4
  25. data/gemfiles/active_record_31.gemfile +23 -4
  26. data/gemfiles/active_record_32.gemfile +22 -4
  27. data/gemfiles/active_record_40.gemfile +26 -0
  28. data/gemfiles/active_record_41.gemfile +25 -0
  29. data/gemfiles/active_record_42.gemfile +25 -0
  30. data/gemfiles/active_record_edge.gemfile +30 -0
  31. data/gemfiles/data_mapper_12.gemfile +30 -10
  32. data/gemfiles/mongo_mapper.gemfile +20 -2
  33. data/gemfiles/mongoid_30.gemfile +18 -3
  34. data/gemfiles/mongoid_31.gemfile +21 -0
  35. data/gemfiles/mongoid_40.gemfile +19 -0
  36. data/gemfiles/mongoid_50.gemfile +23 -0
  37. data/gemfiles/sinatra_13.gemfile +36 -0
  38. data/gemfiles/sinatra_14.gemfile +33 -0
  39. data/kaminari.gemspec +13 -14
  40. data/lib/generators/kaminari/views_generator.rb +9 -8
  41. data/lib/kaminari/config.rb +2 -0
  42. data/lib/kaminari/helpers/action_view_extension.rb +9 -28
  43. data/lib/kaminari/helpers/paginator.rb +38 -18
  44. data/lib/kaminari/helpers/sinatra_helpers.rb +41 -3
  45. data/lib/kaminari/helpers/tags.rb +18 -5
  46. data/lib/kaminari/hooks.rb +31 -15
  47. data/lib/kaminari/models/active_record_extension.rb +8 -8
  48. data/lib/kaminari/models/active_record_model_extension.rb +8 -6
  49. data/lib/kaminari/models/active_record_relation_methods.rb +21 -10
  50. data/lib/kaminari/models/array_extension.rb +17 -11
  51. data/lib/kaminari/models/configuration_methods.rb +16 -2
  52. data/lib/kaminari/models/data_mapper_collection_methods.rb +4 -0
  53. data/lib/kaminari/models/data_mapper_extension.rb +5 -2
  54. data/lib/kaminari/models/mongoid_criteria_methods.rb +18 -1
  55. data/lib/kaminari/models/mongoid_extension.rb +8 -15
  56. data/lib/kaminari/models/page_scope_methods.rb +37 -5
  57. data/lib/kaminari/models/plucky_criteria_methods.rb +6 -1
  58. data/lib/kaminari/railtie.rb +1 -1
  59. data/lib/kaminari/sinatra.rb +2 -0
  60. data/lib/kaminari/version.rb +1 -1
  61. data/lib/kaminari.rb +5 -4
  62. data/spec/config/config_spec.rb +15 -0
  63. data/spec/fake_app/active_record/config.rb +1 -1
  64. data/spec/fake_app/active_record/models.rb +9 -1
  65. data/spec/fake_app/mongo_mapper/config.rb +1 -1
  66. data/spec/fake_app/mongoid/config.rb +7 -3
  67. data/spec/fake_app/mongoid/models.rb +16 -0
  68. data/spec/fake_app/rails_app.rb +1 -0
  69. data/spec/fake_app/views/alternative/kaminari/_first_page.html.erb +1 -0
  70. data/spec/fake_app/views/alternative/kaminari/_paginator.html.erb +3 -0
  71. data/spec/fake_app/views/kaminari/bootstrap/_page.html.erb +1 -0
  72. data/spec/fake_app/views/kaminari/bootstrap/_paginator.html.erb +7 -0
  73. data/spec/fake_gem.rb +18 -2
  74. data/spec/generators/views_generator_spec.rb +18 -0
  75. data/spec/helpers/action_view_extension_spec.rb +68 -12
  76. data/spec/helpers/helpers_spec.rb +9 -0
  77. data/spec/helpers/sinatra_helpers_spec.rb +53 -0
  78. data/spec/models/active_record/active_record_relation_methods_spec.rb +48 -1
  79. data/spec/models/active_record/inherited_spec.rb +9 -0
  80. data/spec/models/active_record/scopes_spec.rb +104 -5
  81. data/spec/models/array_spec.rb +55 -4
  82. data/spec/models/configuration_methods_spec.rb +125 -0
  83. data/spec/models/data_mapper/data_mapper_spec.rb +76 -26
  84. data/spec/models/mongo_mapper/mongo_mapper_spec.rb +12 -0
  85. data/spec/models/mongoid/mongoid_spec.rb +119 -1
  86. data/spec/spec_helper.rb +2 -0
  87. data/spec/spec_helper_for_sinatra.rb +2 -3
  88. data/spec/support/database_cleaner.rb +5 -2
  89. metadata +63 -87
  90. data/gemfiles/mongoid_24.gemfile +0 -7
  91. data/gemfiles/sinatra.gemfile +0 -10
  92. data/spec/models/active_record/default_per_page_spec.rb +0 -32
  93. data/spec/models/active_record/max_per_page_spec.rb +0 -32
@@ -12,6 +12,9 @@ module Kaminari
12
12
  include ::ActionView::Context
13
13
 
14
14
  def initialize(template, options) #:nodoc:
15
+ ActiveSupport::Deprecation.warn 'num_pages is deprecated and will be removed in Kaminari 1.0. Please use total_pages instead.' if options.has_key? :num_pages
16
+ options[:num_pages] ||= options[:total_pages]
17
+
15
18
  @window_options = {}.tap do |h|
16
19
  h[:window] = options.delete(:window) || options.delete(:inner_window) || Kaminari.config.window
17
20
  outer_window = options.delete(:outer_window) || Kaminari.config.outer_window
@@ -21,10 +24,11 @@ module Kaminari
21
24
  h[:right] = outer_window if h[:right] == 0
22
25
  end
23
26
  @template, @options = template, options
24
- @theme = @options[:theme] ? "#{@options[:theme]}/" : ''
25
- @options[:current_page] = PageProxy.new @window_options.merge(@options), @options[:current_page], nil
26
- #FIXME for compatibility. remove num_pages at some time in the future
27
- @options[:total_pages] ||= @options[:num_pages]
27
+ @theme = @options[:theme]
28
+ @views_prefix = @options[:views_prefix]
29
+ @window_options.merge! @options
30
+ @window_options[:current_page] = @options[:current_page] = PageProxy.new(@window_options, @options[:current_page], nil)
31
+
28
32
  @last = nil
29
33
  # initialize the output_buffer for Context
30
34
  @output_buffer = ActionView::OutputBuffer.new
@@ -45,8 +49,8 @@ module Kaminari
45
49
  def each_relevant_page
46
50
  return to_enum(:each_relevant_page) unless block_given?
47
51
 
48
- relevant_pages(@window_options.merge(@options)).each do |i|
49
- yield PageProxy.new(@window_options.merge(@options), i, @last)
52
+ relevant_pages(@window_options).each do |page|
53
+ yield PageProxy.new(@window_options, page, @last)
50
54
  end
51
55
  end
52
56
  alias each_page each_relevant_page
@@ -74,24 +78,40 @@ module Kaminari
74
78
 
75
79
  def to_s #:nodoc:
76
80
  subscriber = ActionView::LogSubscriber.log_subscribers.detect {|ls| ls.is_a? ActionView::LogSubscriber}
77
- return super @window_options.merge(@options).merge :paginator => self unless subscriber
78
81
 
79
- # dirty hack to suppress logging render_partial
80
- class << subscriber
81
- alias_method :render_partial_with_logging, :render_partial
82
- # do nothing
83
- def render_partial(event); end
84
- end
82
+ # There is a logging subscriber
83
+ # and we don't want it to log render_partial
84
+ # It is threadsafe, but might not repress logging
85
+ # consistently in a high-load environment
86
+ if subscriber
87
+ unless defined? subscriber.render_partial_with_logging
88
+ class << subscriber
89
+ alias_method :render_partial_with_logging, :render_partial
90
+ attr_accessor :render_without_logging
91
+ # ugly hack to make a renderer where
92
+ # we can turn logging on or off
93
+ def render_partial(event)
94
+ render_partial_with_logging(event) unless render_without_logging
95
+ end
96
+ end
97
+ end
85
98
 
86
- ret = super @window_options.merge(@options).merge :paginator => self
99
+ subscriber.render_without_logging = true
100
+ ret = super @window_options.merge :paginator => self
101
+ subscriber.render_without_logging = false
87
102
 
88
- class << subscriber
89
- alias_method :render_partial, :render_partial_with_logging
90
- undef :render_partial_with_logging
103
+ ret
104
+ else
105
+ super @window_options.merge :paginator => self
91
106
  end
92
- ret
93
107
  end
94
108
 
109
+ # delegates view helper methods to @template
110
+ def method_missing(name, *args, &block)
111
+ @template.respond_to?(name) ? @template.send(name, *args, &block) : super
112
+ end
113
+ private :method_missing
114
+
95
115
  # Wraps a "page number" and provides some utility methods
96
116
  class PageProxy
97
117
  include Comparable
@@ -1,5 +1,6 @@
1
1
  require 'active_support/core_ext/object'
2
2
  require 'active_support/core_ext/string'
3
+ require 'action_dispatch/http/mime_type'
3
4
 
4
5
  begin
5
6
 
@@ -10,6 +11,11 @@ module Kaminari::Helpers
10
11
  def registered(app)
11
12
  app.register Padrino::Helpers
12
13
  app.helpers HelperMethods
14
+ @app = app
15
+ end
16
+
17
+ def view_paths
18
+ @app.views
13
19
  end
14
20
 
15
21
  alias included registered
@@ -31,6 +37,7 @@ module Kaminari::Helpers
31
37
 
32
38
  def render(*args)
33
39
  base = ActionView::Base.new.tap do |a|
40
+ a.view_paths << SinatraHelpers.view_paths
34
41
  a.view_paths << File.expand_path('../../../../app/views', __FILE__)
35
42
  end
36
43
  base.render(*args)
@@ -87,6 +94,36 @@ module Kaminari::Helpers
87
94
  paginator.to_s
88
95
  end
89
96
 
97
+ # A simple "Twitter like" pagination link that creates a link to the previous page.
98
+ # Works on Sinatra.
99
+ #
100
+ # ==== Examples
101
+ # Basic usage:
102
+ #
103
+ # <%= link_to_previous_page @items, 'Previous Page' %>
104
+ #
105
+ # Ajax:
106
+ #
107
+ # <%= link_to_previous_page @items, 'Previous Page', :remote => true %>
108
+ #
109
+ # By default, it renders nothing if there are no more results on the previous page.
110
+ # You can customize this output by passing a parameter <tt>:placeholder</tt>.
111
+ #
112
+ # <%= link_to_previous_page @users, 'Previous Page', :placeholder => %{<span>At the Beginning</span>} %>
113
+ #
114
+ def link_to_previous_page(scope, name, options = {})
115
+ params = options.delete(:params) || (Rack::Utils.parse_query(env['QUERY_STRING']).symbolize_keys rescue {})
116
+ param_name = options.delete(:param_name) || Kaminari.config.param_name
117
+ placeholder = options.delete(:placeholder)
118
+
119
+ unless scope.first_page?
120
+ query = params.merge(param_name => scope.prev_page)
121
+ link_to name, env['PATH_INFO'] + (query.empty? ? '' : "?#{query.to_query}"), options.reverse_merge(:rel => 'previous')
122
+ else
123
+ placeholder.to_s.html_safe
124
+ end
125
+ end
126
+
90
127
  # A simple "Twitter like" pagination link that creates a link to the next page.
91
128
  # Works on Sinatra.
92
129
  #
@@ -108,11 +145,12 @@ module Kaminari::Helpers
108
145
  params = options.delete(:params) || (Rack::Utils.parse_query(env['QUERY_STRING']).symbolize_keys rescue {})
109
146
  param_name = options.delete(:param_name) || Kaminari.config.param_name
110
147
  placeholder = options.delete(:placeholder)
111
- query = params.merge(param_name => (scope.current_page + 1))
148
+
112
149
  unless scope.last_page?
150
+ query = params.merge(param_name => scope.next_page)
113
151
  link_to name, env['PATH_INFO'] + (query.empty? ? '' : "?#{query.to_query}"), options.reverse_merge(:rel => 'next')
114
152
  else
115
- placeholder
153
+ placeholder.to_s.html_safe
116
154
  end
117
155
  end
118
156
  end
@@ -125,7 +163,7 @@ end
125
163
 
126
164
  rescue LoadError
127
165
 
128
- $stderr.puts "[!]You shold install `padrino-helpers' gem if you want to use kaminari's pagination helpers with Sinatra."
166
+ $stderr.puts "[!]You should install `padrino-helpers' gem if you want to use kaminari's pagination helpers with Sinatra."
129
167
  $stderr.puts "[!]Kaminari::Helpers::SinatraHelper does nothing now..."
130
168
 
131
169
  module Kaminari::Helpers
@@ -15,17 +15,30 @@ module Kaminari
15
15
  class Tag
16
16
  def initialize(template, options = {}) #:nodoc:
17
17
  @template, @options = template, options.dup
18
- @param_name = @options.delete(:param_name)
19
- @theme = @options[:theme] ? "#{@options.delete(:theme)}/" : ''
20
- @params = @options[:params] ? template.params.merge(@options.delete :params) : template.params
18
+ @param_name = @options.delete(:param_name) || Kaminari.config.param_name
19
+ @theme = @options.delete(:theme)
20
+ @views_prefix = @options.delete(:views_prefix)
21
+ @params = template.params
22
+ # @params in Rails 5 no longer inherits from Hash
23
+ @params = @params.to_unsafe_h if @params.respond_to?(:to_unsafe_h)
24
+ @params = @params.except(:script_name).merge(@options.delete(:params) || {})
21
25
  end
22
26
 
23
27
  def to_s(locals = {}) #:nodoc:
24
- @template.render :partial => "kaminari/#{@theme}#{self.class.name.demodulize.underscore}", :locals => @options.merge(locals)
28
+ @template.render :partial => partial_path, :locals => @options.merge(locals), :formats => [:html]
25
29
  end
26
30
 
27
31
  def page_url_for(page)
28
- @template.url_for @params.merge(@param_name => (page <= 1 ? nil : page))
32
+ @template.url_for @params.merge(@param_name => (page <= 1 ? nil : page), :only_path => true)
33
+ end
34
+
35
+ def partial_path
36
+ [
37
+ @views_prefix,
38
+ "kaminari",
39
+ @theme,
40
+ self.class.name.demodulize.underscore
41
+ ].compact.join("/")
29
42
  end
30
43
  end
31
44
 
@@ -6,26 +6,42 @@ module Kaminari
6
6
  ::ActiveRecord::Base.send :include, Kaminari::ActiveRecordExtension
7
7
  end
8
8
 
9
- begin; require 'data_mapper'; rescue LoadError; end
10
- if defined? ::DataMapper
11
- require 'dm-aggregates'
12
- require 'kaminari/models/data_mapper_extension'
13
- ::DataMapper::Collection.send :include, Kaminari::DataMapperExtension::Collection
14
- ::DataMapper::Model.append_extensions Kaminari::DataMapperExtension::Model
15
- # ::DataMapper::Model.send :extend, Kaminari::DataMapperExtension::Model
9
+ # data_mapper
10
+ begin
11
+ require 'kaminari/data_mapper'
12
+ rescue LoadError
13
+ begin; require 'data_mapper'; rescue LoadError; end
14
+ if defined? ::DataMapper
15
+ require 'dm-aggregates'
16
+ require 'kaminari/models/data_mapper_extension'
17
+ ::DataMapper::Collection.send :include, Kaminari::DataMapperExtension::Collection
18
+ ::DataMapper::Model.append_extensions Kaminari::DataMapperExtension::Model
19
+ # ::DataMapper::Model.send :extend, Kaminari::DataMapperExtension::Model
20
+ end
16
21
  end
17
22
 
18
- begin; require 'mongoid'; rescue LoadError; end
19
- if defined? ::Mongoid
20
- require 'kaminari/models/mongoid_extension'
21
- ::Mongoid::Criteria.send :include, Kaminari::MongoidExtension::Criteria
22
- ::Mongoid::Document.send :include, Kaminari::MongoidExtension::Document
23
+ ## mongoid
24
+ begin
25
+ require 'kaminari/mongoid'
26
+ rescue LoadError
27
+ begin; require 'mongoid'; rescue LoadError; end
28
+ if defined? ::Mongoid
29
+ ActiveSupport::Deprecation.warn 'Kaminari Mongoid support has been extracted to a separate gem, and will be removed in the next 1.0 release. Please bundle kaminari-mongoid gem.'
30
+ require 'kaminari/models/mongoid_extension'
31
+ ::Mongoid::Document.send :include, Kaminari::MongoidExtension::Document
32
+ end
23
33
  end
24
34
 
35
+ ## mongo_mapper
25
36
  ActiveSupport.on_load(:mongo_mapper) do
26
- require 'kaminari/models/mongo_mapper_extension'
27
- ::MongoMapper::Document.send :include, Kaminari::MongoMapperExtension::Document
28
- ::Plucky::Query.send :include, Kaminari::PluckyCriteriaMethods
37
+ begin
38
+ require 'kaminari/mongo_mapper'
39
+ rescue LoadError
40
+ ActiveSupport::Deprecation.warn 'Kaminari MongoMapper support has been extracted to a separate gem, and will be removed in the next 1.0 release. Please bundle kaminari-mongo_mapper gem.'
41
+ require 'kaminari/models/mongo_mapper_extension'
42
+ ::MongoMapper::Document.send :include, Kaminari::MongoMapperExtension::Document
43
+ ::Plucky::Query.send :include, Kaminari::PluckyCriteriaMethods
44
+ end
29
45
  end
30
46
  require 'kaminari/models/array_extension'
31
47
 
@@ -3,19 +3,19 @@ require 'kaminari/models/active_record_model_extension'
3
3
  module Kaminari
4
4
  module ActiveRecordExtension
5
5
  extend ActiveSupport::Concern
6
- included do
6
+
7
+ module ClassMethods
7
8
  # Future subclasses will pick up the model extension
8
- class << self
9
- def inherited_with_kaminari(kls) #:nodoc:
10
- inherited_without_kaminari kls
11
- kls.send(:include, Kaminari::ActiveRecordModelExtension) if kls.superclass == ActiveRecord::Base
12
- end
13
- alias_method_chain :inherited, :kaminari
9
+ def inherited(kls) #:nodoc:
10
+ super
11
+ kls.send(:include, Kaminari::ActiveRecordModelExtension) if kls.superclass == ::ActiveRecord::Base
14
12
  end
13
+ end
15
14
 
15
+ included do
16
16
  # Existing subclasses pick up the model extension as well
17
17
  self.descendants.each do |kls|
18
- kls.send(:include, Kaminari::ActiveRecordModelExtension) if kls.superclass == ActiveRecord::Base
18
+ kls.send(:include, Kaminari::ActiveRecordModelExtension) if kls.superclass == ::ActiveRecord::Base
19
19
  end
20
20
  end
21
21
  end
@@ -9,12 +9,14 @@ module Kaminari
9
9
 
10
10
  # Fetch the values at the specified page number
11
11
  # Model.page(5)
12
- self.scope Kaminari.config.page_method_name, Proc.new {|num|
13
- limit(default_per_page).offset(default_per_page * ([num.to_i, 1].max - 1))
14
- } do
15
- include Kaminari::ActiveRecordRelationMethods
16
- include Kaminari::PageScopeMethods
17
- end
12
+ eval <<-RUBY
13
+ def self.#{Kaminari.config.page_method_name}(num = nil)
14
+ limit(default_per_page).offset(default_per_page * ((num = num.to_i - 1) < 0 ? 0 : num)).extending do
15
+ include Kaminari::ActiveRecordRelationMethods
16
+ include Kaminari::PageScopeMethods
17
+ end
18
+ end
19
+ RUBY
18
20
  end
19
21
  end
20
22
  end
@@ -3,12 +3,21 @@ module Kaminari
3
3
  # a workaround for AR 3.0.x that returns 0 for #count when page > 1
4
4
  # if +limit_value+ is specified, load all the records and count them
5
5
  if ActiveRecord::VERSION::STRING < '3.1'
6
- def count #:nodoc:
7
- limit_value ? length : super
6
+ def count(column_name = nil, options = {}) #:nodoc:
7
+ limit_value && !options[:distinct] ? length : super(column_name, options)
8
8
  end
9
9
  end
10
10
 
11
- def total_count #:nodoc:
11
+ def entry_name
12
+ model_name.human.downcase
13
+ end
14
+
15
+ def reset #:nodoc:
16
+ @total_count = nil
17
+ super
18
+ end
19
+
20
+ def total_count(column_name = :all, options = {}) #:nodoc:
12
21
  # #count overrides the #select which could include generated columns referenced in #order, so skip #order here, where it's irrelevant to the result anyway
13
22
  @total_count ||= begin
14
23
  c = except(:offset, :limit, :order)
@@ -16,14 +25,16 @@ module Kaminari
16
25
  # Remove includes only if they are irrelevant
17
26
  c = c.except(:includes) unless references_eager_loaded_tables?
18
27
 
19
- # a workaround to count the actual model instances on distinct query because count + distinct returns wrong value in some cases. see https://github.com/amatsuda/kaminari/pull/160
20
- uses_distinct_sql_statement = c.to_sql =~ /DISTINCT/i
21
- if uses_distinct_sql_statement
22
- c.length
28
+ # Rails 4.1 removes the `options` argument from AR::Relation#count
29
+ args = [column_name]
30
+ args << options if ActiveRecord::VERSION::STRING < '4.1.0'
31
+
32
+ # .group returns an OrderdHash that responds to #count
33
+ c = c.count(*args)
34
+ if c.is_a?(Hash) || c.is_a?(ActiveSupport::OrderedHash)
35
+ c.count
23
36
  else
24
- # .group returns an OrderdHash that responds to #count
25
- c = c.count
26
- c.respond_to?(:count) ? c.count : c
37
+ c.respond_to?(:count) ? c.count(*args) : c
27
38
  end
28
39
  end
29
40
  end
@@ -11,31 +11,37 @@ module Kaminari
11
11
  # * <tt>:offset</tt> - offset
12
12
  # * <tt>:total_count</tt> - total_count
13
13
  def initialize(original_array = [], options = {})
14
- @_original_array, @_limit_value, @_offset_value, @_total_count = original_array, (options[:limit] || default_per_page).to_i, options[:offset].to_i, options[:total_count]
14
+ @_original_array, @_limit_value, @_offset_value, @_total_count, @_padding = original_array, (options[:limit] || default_per_page).to_i, options[:offset].to_i, options[:total_count], options[:padding].to_i
15
15
 
16
16
  if options[:limit] && options[:offset]
17
- class << self
18
- include Kaminari::PageScopeMethods
19
- end
17
+ extend Kaminari::PageScopeMethods
20
18
  end
21
19
 
22
- if options[:total_count]
23
- super original_array
24
- else
25
- super(original_array[@_offset_value, @_limit_value] || [])
20
+ if @_total_count.present? && @_total_count <= original_array.count
21
+ original_array = original_array.first(@_total_count)[@_offset_value, @_limit_value]
26
22
  end
23
+
24
+ if @_total_count.nil?
25
+ original_array = original_array[@_offset_value, @_limit_value]
26
+ end
27
+
28
+ super(original_array || [])
29
+ end
30
+
31
+ def entry_name
32
+ "entry"
27
33
  end
28
34
 
29
35
  # items at the specified "page"
30
36
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
31
37
  def #{Kaminari.config.page_method_name}(num = 1)
32
- offset(limit_value * ([num.to_i, 1].max - 1))
38
+ offset(limit_value * ((num = num.to_i - 1) < 0 ? 0 : num))
33
39
  end
34
40
  RUBY
35
41
 
36
42
  # returns another chunk of the original array
37
43
  def limit(num)
38
- self.class.new @_original_array, :limit => num, :offset => @_offset_value, :total_count => @_total_count
44
+ self.class.new @_original_array, :limit => num, :offset => @_offset_value, :total_count => @_total_count, :padding => @_padding
39
45
  end
40
46
 
41
47
  # total item numbers of the original array
@@ -45,7 +51,7 @@ module Kaminari
45
51
 
46
52
  # returns another chunk of the original array
47
53
  def offset(num)
48
- self.class.new @_original_array, :limit => @_limit_value, :offset => num, :total_count => @_total_count
54
+ self.class.new @_original_array, :limit => @_limit_value, :offset => num, :total_count => @_total_count, :padding => @_padding
49
55
  end
50
56
  end
51
57
 
@@ -13,7 +13,7 @@ module Kaminari
13
13
  # This model's default +per_page+ value
14
14
  # returns +default_per_page+ value unless explicitly overridden via <tt>paginates_per</tt>
15
15
  def default_per_page
16
- @_default_per_page ||= Kaminari.config.default_per_page
16
+ (defined?(@_default_per_page) && @_default_per_page) || Kaminari.config.default_per_page
17
17
  end
18
18
 
19
19
  # Overrides the max +per_page+ value per model
@@ -27,7 +27,21 @@ module Kaminari
27
27
  # This model's max +per_page+ value
28
28
  # returns +max_per_page+ value unless explicitly overridden via <tt>max_paginates_per</tt>
29
29
  def max_per_page
30
- @_max_per_page || Kaminari.config.max_per_page
30
+ (defined?(@_max_per_page) && @_max_per_page) || Kaminari.config.max_per_page
31
+ end
32
+
33
+ # Overrides the max_pages value per model
34
+ # class Article < ActiveRecord::Base
35
+ # max_pages_per 100
36
+ # end
37
+ def max_pages_per(val)
38
+ @_max_pages = val
39
+ end
40
+
41
+ # This model's max_pages value
42
+ # returns max_pages value unless explicitly overridden via <tt>max_pages_per</tt>
43
+ def max_pages
44
+ (defined?(@_max_pages) && @_max_pages) || Kaminari.config.max_pages
31
45
  end
32
46
  end
33
47
  end
@@ -1,5 +1,9 @@
1
1
  module Kaminari
2
2
  module DataMapperCollectionMethods
3
+ def entry_name
4
+ model.model_name.human.downcase
5
+ end
6
+
3
7
  def limit_value #:nodoc:
4
8
  query.options[:limit] || 0
5
9
  end
@@ -5,8 +5,10 @@ module Kaminari
5
5
  module Paginatable
6
6
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
7
7
  def #{Kaminari.config.page_method_name}(num = 1)
8
+ model = self
9
+ model = self.model if self.is_a? DataMapper::Collection
8
10
  num = [num.to_i, 1].max - 1
9
- all(:limit => default_per_page, :offset => default_per_page * num).extend Paginating
11
+ all(:limit => model.default_per_page, :offset => model.default_per_page * num).extend Paginating
10
12
  end
11
13
  RUBY
12
14
  end
@@ -26,9 +28,10 @@ module Kaminari
26
28
  module Collection
27
29
  extend ActiveSupport::Concern
28
30
  included do
29
- include Kaminari::ConfigurationMethods::ClassMethods
30
31
  include Kaminari::DataMapperCollectionMethods
31
32
  include Paginatable
33
+
34
+ delegate :default_per_page, :max_per_page, :max_pages, :to => :model
32
35
  end
33
36
  end
34
37
 
@@ -1,5 +1,14 @@
1
1
  module Kaminari
2
2
  module MongoidCriteriaMethods
3
+ def initialize_copy(other) #:nodoc:
4
+ @total_count = nil
5
+ super
6
+ end
7
+
8
+ def entry_name
9
+ model_name.human.downcase
10
+ end
11
+
3
12
  def limit_value #:nodoc:
4
13
  options[:limit]
5
14
  end
@@ -9,7 +18,15 @@ module Kaminari
9
18
  end
10
19
 
11
20
  def total_count #:nodoc:
12
- embedded? ? unpage.count : count
21
+ @total_count ||= if embedded?
22
+ unpage.count
23
+ else
24
+ if options[:max_scan] && options[:max_scan] < count
25
+ options[:max_scan]
26
+ else
27
+ count
28
+ end
29
+ end
13
30
  end
14
31
 
15
32
  private
@@ -2,32 +2,25 @@ require 'kaminari/models/mongoid_criteria_methods'
2
2
 
3
3
  module Kaminari
4
4
  module MongoidExtension
5
- module Criteria
6
- extend ActiveSupport::Concern
7
-
8
- included do
9
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
10
- def #{Kaminari.config.page_method_name}(*args)
11
- super(*args).criteria.merge(self)
12
- end
13
- RUBY
14
- end
15
- end
16
-
17
5
  module Document
18
6
  extend ActiveSupport::Concern
19
7
  include Kaminari::ConfigurationMethods
20
8
 
21
9
  included do
22
- # Fetch the values at the specified page number
23
- # Model.page(5)
24
10
  scope Kaminari.config.page_method_name, Proc.new {|num|
25
- limit(default_per_page).offset(default_per_page * ([num.to_i, 1].max - 1))
11
+ limit(default_per_page).offset(default_per_page * ((num = num.to_i - 1) < 0 ? 0 : num))
26
12
  } do
27
13
  include Kaminari::MongoidCriteriaMethods
28
14
  include Kaminari::PageScopeMethods
29
15
  end
30
16
  end
17
+
18
+ module ClassMethods
19
+ def inherited(kls)
20
+ super
21
+ kls.send(:include, Kaminari::MongoidExtension::Document.dup)
22
+ end
23
+ end if Mongoid::VERSION < '5.0.0'
31
24
  end
32
25
  end
33
26
  end
@@ -13,22 +13,49 @@ module Kaminari
13
13
  end
14
14
 
15
15
  def padding(num)
16
+ @_padding = num
16
17
  offset(offset_value + num.to_i)
17
18
  end
18
19
 
19
20
  # Total number of pages
20
21
  def total_pages
21
- (total_count.to_f / limit_value).ceil
22
+ count_without_padding = total_count
23
+ count_without_padding -= @_padding if defined?(@_padding) && @_padding
24
+ count_without_padding = 0 if count_without_padding < 0
25
+
26
+ total_pages_count = (count_without_padding.to_f / limit_value).ceil
27
+ if max_pages.present? && max_pages < total_pages_count
28
+ max_pages
29
+ else
30
+ total_pages_count
31
+ end
32
+ end
33
+
34
+ def num_pages
35
+ ActiveSupport::Deprecation.warn 'num_pages is deprecated and will be removed in Kaminari 1.0. Please use total_pages instead.'
36
+ total_pages
22
37
  end
23
- #FIXME for compatibility. remove num_pages at some time in the future
24
- alias num_pages total_pages
25
38
 
26
39
  # Current page number
27
40
  def current_page
28
- (offset_value / limit_value) + 1
41
+ offset_without_padding = offset_value
42
+ offset_without_padding -= @_padding if defined?(@_padding) && @_padding
43
+ offset_without_padding = 0 if offset_without_padding < 0
44
+
45
+ (offset_without_padding / limit_value) + 1
29
46
  end
30
47
 
31
- # First page of the collection ?
48
+ # Next page number in the collection
49
+ def next_page
50
+ current_page + 1 unless last_page?
51
+ end
52
+
53
+ # Previous page number in the collection
54
+ def prev_page
55
+ current_page - 1 unless first_page?
56
+ end
57
+
58
+ # First page of the collection?
32
59
  def first_page?
33
60
  current_page == 1
34
61
  end
@@ -37,5 +64,10 @@ module Kaminari
37
64
  def last_page?
38
65
  current_page >= total_pages
39
66
  end
67
+
68
+ # Out of range of the collection?
69
+ def out_of_range?
70
+ current_page > total_pages
71
+ end
40
72
  end
41
73
  end
@@ -1,7 +1,12 @@
1
1
  module Kaminari
2
2
  module PluckyCriteriaMethods
3
3
  include Kaminari::PageScopeMethods
4
- include Kaminari::ConfigurationMethods::ClassMethods
4
+
5
+ delegate :default_per_page, :max_per_page, :max_pages, :to => :model
6
+
7
+ def entry_name
8
+ model.model_name.human.downcase
9
+ end
5
10
 
6
11
  def limit_value #:nodoc:
7
12
  options[:limit]
@@ -1,6 +1,6 @@
1
1
  module Kaminari
2
2
  class Railtie < ::Rails::Railtie #:nodoc:
3
- initializer 'kaminari' do |_app|
3
+ initializer 'kaminari' do
4
4
  Kaminari::Hooks.init
5
5
  end
6
6
  end
@@ -2,4 +2,6 @@ require 'sinatra/base'
2
2
  require 'kaminari'
3
3
  require 'kaminari/helpers/sinatra_helpers'
4
4
 
5
+ ActiveSupport::Deprecation.warn 'Kaminari Sinatra support has been extracted to a separate gem, and will be removed in the next 1.0 release. Please bundle kaminari-sinatra gem.'
6
+
5
7
  Kaminari::Hooks.init