kaminari 0.15.1 → 0.16.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 (46) hide show
  1. data/.travis.yml +17 -4
  2. data/CHANGELOG.rdoc +25 -0
  3. data/README.rdoc +23 -6
  4. data/Rakefile +2 -2
  5. data/gemfiles/active_record_30.gemfile +7 -3
  6. data/gemfiles/active_record_31.gemfile +7 -3
  7. data/gemfiles/active_record_32.gemfile +7 -3
  8. data/gemfiles/active_record_40.gemfile +9 -5
  9. data/gemfiles/active_record_41.gemfile +24 -0
  10. data/gemfiles/active_record_edge.gemfile +7 -3
  11. data/gemfiles/data_mapper_12.gemfile +7 -3
  12. data/gemfiles/mongo_mapper.gemfile +7 -2
  13. data/gemfiles/mongoid_24.gemfile +2 -2
  14. data/gemfiles/mongoid_30.gemfile +2 -1
  15. data/gemfiles/mongoid_31.gemfile +1 -1
  16. data/gemfiles/mongoid_40.gemfile +14 -0
  17. data/gemfiles/sinatra_13.gemfile +7 -4
  18. data/gemfiles/sinatra_14.gemfile +14 -6
  19. data/lib/generators/kaminari/views_generator.rb +3 -3
  20. data/lib/kaminari/helpers/action_view_extension.rb +5 -25
  21. data/lib/kaminari/helpers/paginator.rb +10 -3
  22. data/lib/kaminari/helpers/sinatra_helpers.rb +33 -2
  23. data/lib/kaminari/helpers/tags.rb +12 -2
  24. data/lib/kaminari/hooks.rb +0 -1
  25. data/lib/kaminari/models/active_record_extension.rb +2 -2
  26. data/lib/kaminari/models/active_record_relation_methods.rb +4 -0
  27. data/lib/kaminari/models/array_extension.rb +8 -4
  28. data/lib/kaminari/models/data_mapper_collection_methods.rb +4 -0
  29. data/lib/kaminari/models/mongoid_criteria_methods.rb +13 -1
  30. data/lib/kaminari/models/mongoid_extension.rb +0 -12
  31. data/lib/kaminari/models/plucky_criteria_methods.rb +4 -0
  32. data/lib/kaminari/version.rb +1 -1
  33. data/spec/fake_app/active_record/config.rb +1 -1
  34. data/spec/fake_app/mongoid/config.rb +3 -1
  35. data/spec/fake_app/mongoid/models.rb +4 -0
  36. data/spec/fake_app/views/alternative/kaminari/_first_page.html.erb +1 -0
  37. data/spec/fake_app/views/alternative/kaminari/_paginator.html.erb +3 -0
  38. data/spec/generators/views_generator_spec.rb +18 -0
  39. data/spec/helpers/action_view_extension_spec.rb +17 -10
  40. data/spec/helpers/helpers_spec.rb +9 -0
  41. data/spec/helpers/sinatra_helpers_spec.rb +53 -0
  42. data/spec/models/array_spec.rb +23 -4
  43. data/spec/models/mongoid/mongoid_spec.rb +72 -1
  44. data/spec/spec_helper.rb +1 -0
  45. metadata +62 -32
  46. checksums.yaml +0 -7
@@ -1,11 +1,15 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'activerecord', '~> 3.2.0', :require => 'active_record'
4
- gem 'railties', '~> 3.2.3'
5
- gem 'rspec-rails', '>= 2.0'
6
4
  gem 'sinatra', '~> 1.4.0'
7
- gem 'tilt', '~> 1.3.0'
8
- gem 'padrino-helpers', '~> 0.11.3'
5
+ gem 'rspec', '~> 2.14.1'
6
+
7
+ if RUBY_VERSION <= "1.8.7"
8
+ gem 'padrino-helpers', '~> 0.11.0'
9
+ else
10
+ gem 'padrino-helpers', '~> 0.12.0'
11
+ end
12
+
9
13
  gem 'rack-test', '>= 0'
10
14
  gem 'sinatra-contrib', '~> 1.4.0'
11
15
 
@@ -15,8 +19,12 @@ gem 'nokogiri', '< 1.6'
15
19
  gem 'capybara', '< 2.1'
16
20
  gem 'rubyzip', '< 1'
17
21
 
18
- platforms :ruby, :rbx do
19
- gem 'sqlite3'
22
+ platforms :ruby do
23
+ if RUBY_VERSION > "2.1.0"
24
+ gem 'sqlite3'
25
+ else
26
+ gem 'sqlite3', '1.3.8'
27
+ end
20
28
  end
21
29
  platforms :jruby do
22
30
  gem 'activerecord-jdbcsqlite3-adapter', '>= 1.3.0'
@@ -96,10 +96,10 @@ BANNER
96
96
  module GitHubApiHelper
97
97
  def get_files_in_master
98
98
  master_tree_sha = open('https://api.github.com/repos/amatsuda/kaminari_themes/git/refs/heads/master') do |json|
99
- ActiveSupport::JSON.decode(json)['object']['sha']
99
+ ActiveSupport::JSON.decode(json.read)['object']['sha']
100
100
  end
101
101
  open('https://api.github.com/repos/amatsuda/kaminari_themes/git/trees/' + master_tree_sha + '?recursive=1') do |json|
102
- blobs = ActiveSupport::JSON.decode(json)['tree'].find_all {|i| i['type'] == 'blob' }
102
+ blobs = ActiveSupport::JSON.decode(json.read)['tree'].find_all {|i| i['type'] == 'blob' }
103
103
  blobs.map do |blob|
104
104
  [blob['path'], blob['sha']]
105
105
  end
@@ -109,7 +109,7 @@ BANNER
109
109
 
110
110
  def get_content_for(path)
111
111
  open('https://api.github.com/repos/amatsuda/kaminari_themes/contents/' + path) do |json|
112
- Base64.decode64(ActiveSupport::JSON.decode(json)['content'])
112
+ Base64.decode64(ActiveSupport::JSON.decode(json.read)['content'])
113
113
  end
114
114
  end
115
115
  module_function :get_content_for
@@ -39,7 +39,7 @@ module Kaminari
39
39
  def link_to_previous_page(scope, name, options = {}, &block)
40
40
  params = options.delete(:params) || {}
41
41
  param_name = options.delete(:param_name) || Kaminari.config.param_name
42
- link_to_unless scope.first_page?, name, params.merge(param_name => (scope.current_page - 1)), options.reverse_merge(:rel => 'previous') do
42
+ link_to_unless scope.first_page?, name, params.merge(param_name => scope.prev_page), options.reverse_merge(:rel => 'previous') do
43
43
  block.call if block
44
44
  end
45
45
  end
@@ -64,7 +64,7 @@ module Kaminari
64
64
  def link_to_next_page(scope, name, options = {}, &block)
65
65
  params = options.delete(:params) || {}
66
66
  param_name = options.delete(:param_name) || Kaminari.config.param_name
67
- link_to_unless scope.last_page?, name, params.merge(param_name => (scope.current_page + 1)), options.reverse_merge(:rel => 'next') do
67
+ link_to_unless scope.last_page?, name, params.merge(param_name => scope.next_page), options.reverse_merge(:rel => 'next') do
68
68
  block.call if block
69
69
  end
70
70
  end
@@ -86,17 +86,7 @@ module Kaminari
86
86
  # <%= page_entries_info @posts, :entry_name => 'item' %>
87
87
  # #-> Displaying items 6 - 10 of 26 in total
88
88
  def page_entries_info(collection, options = {})
89
- entry_name = if options[:entry_name]
90
- options[:entry_name]
91
- elsif collection.is_a?(::Kaminari::PaginatableArray)
92
- 'entry'
93
- else
94
- if collection.respond_to? :model # DataMapper
95
- collection.model.model_name.human.downcase
96
- else # AR
97
- collection.model_name.human.downcase
98
- end
99
- end
89
+ entry_name = options[:entry_name] || collection.entry_name
100
90
  entry_name = entry_name.pluralize unless collection.total_count == 1
101
91
 
102
92
  if collection.total_pages < 2
@@ -131,18 +121,8 @@ module Kaminari
131
121
  param_name = options.delete(:param_name) || Kaminari.config.param_name
132
122
 
133
123
  output = ""
134
-
135
- if !scope.first_page? && !scope.last_page?
136
- # If not first and not last, then output both links.
137
- output << '<link rel="next" href="' + url_for(params.merge(param_name => (scope.current_page + 1), :only_path => true)) + '"/>'
138
- output << '<link rel="prev" href="' + url_for(params.merge(param_name => (scope.current_page - 1), :only_path => true)) + '"/>'
139
- elsif scope.first_page?
140
- # If first page, add next link unless last page.
141
- output << '<link rel="next" href="' + url_for(params.merge(param_name => (scope.current_page + 1), :only_path => true)) + '"/>' unless scope.last_page?
142
- else
143
- # If last page, add prev link unless first page.
144
- output << '<link rel="prev" href="' + url_for(params.merge(param_name => (scope.current_page - 1), :only_path => true)) + '"/>' unless scope.first_page?
145
- end
124
+ output << '<link rel="next" href="' + url_for(params.merge(param_name => scope.next_page, :only_path => true)) + '"/>' if scope.next_page
125
+ output << '<link rel="prev" href="' + url_for(params.merge(param_name => scope.prev_page, :only_path => true)) + '"/>' if scope.prev_page
146
126
 
147
127
  output.html_safe
148
128
  end
@@ -25,7 +25,8 @@ module Kaminari
25
25
  h[:right] = outer_window if h[:right] == 0
26
26
  end
27
27
  @template, @options = template, options
28
- @theme = @options[:theme] ? "#{@options[:theme]}/" : ''
28
+ @theme = @options.delete(:theme)
29
+ @views_prefix = @options[:views_prefix]
29
30
  @window_options.merge! @options
30
31
  @window_options[:current_page] = @options[:current_page] = PageProxy.new(@window_options, @options[:current_page], nil)
31
32
 
@@ -49,8 +50,8 @@ module Kaminari
49
50
  def each_relevant_page
50
51
  return to_enum(:each_relevant_page) unless block_given?
51
52
 
52
- relevant_pages(@window_options).each do |i|
53
- yield PageProxy.new(@window_options, i, @last)
53
+ relevant_pages(@window_options).each do |page|
54
+ yield PageProxy.new(@window_options, page, @last)
54
55
  end
55
56
  end
56
57
  alias each_page each_relevant_page
@@ -106,6 +107,12 @@ module Kaminari
106
107
  end
107
108
  end
108
109
 
110
+ # delegates view helper methods to @template
111
+ def method_missing(name, *args, &block)
112
+ @template.respond_to?(name) ? @template.send(name, *args, &block) : super
113
+ end
114
+ private :method_missing
115
+
109
116
  # Wraps a "page number" and provides some utility methods
110
117
  class PageProxy
111
118
  include Comparable
@@ -93,6 +93,36 @@ module Kaminari::Helpers
93
93
  paginator.to_s
94
94
  end
95
95
 
96
+ # A simple "Twitter like" pagination link that creates a link to the previous page.
97
+ # Works on Sinatra.
98
+ #
99
+ # ==== Examples
100
+ # Basic usage:
101
+ #
102
+ # <%= link_to_previous_page @items, 'Previous Page' %>
103
+ #
104
+ # Ajax:
105
+ #
106
+ # <%= link_to_previous_page @items, 'Previous Page', :remote => true %>
107
+ #
108
+ # By default, it renders nothing if there are no more results on the previous page.
109
+ # You can customize this output by passing a parameter <tt>:placeholder</tt>.
110
+ #
111
+ # <%= link_to_previous_page @users, 'Previous Page', :placeholder => %{<span>At the Beginning</span>} %>
112
+ #
113
+ def link_to_previous_page(scope, name, options = {})
114
+ params = options.delete(:params) || (Rack::Utils.parse_query(env['QUERY_STRING']).symbolize_keys rescue {})
115
+ param_name = options.delete(:param_name) || Kaminari.config.param_name
116
+ placeholder = options.delete(:placeholder)
117
+
118
+ unless scope.first_page?
119
+ query = params.merge(param_name => scope.prev_page)
120
+ link_to name, env['PATH_INFO'] + (query.empty? ? '' : "?#{query.to_query}"), options.reverse_merge(:rel => 'previous')
121
+ else
122
+ placeholder.to_s.html_safe
123
+ end
124
+ end
125
+
96
126
  # A simple "Twitter like" pagination link that creates a link to the next page.
97
127
  # Works on Sinatra.
98
128
  #
@@ -114,11 +144,12 @@ module Kaminari::Helpers
114
144
  params = options.delete(:params) || (Rack::Utils.parse_query(env['QUERY_STRING']).symbolize_keys rescue {})
115
145
  param_name = options.delete(:param_name) || Kaminari.config.param_name
116
146
  placeholder = options.delete(:placeholder)
117
- query = params.merge(param_name => (scope.current_page + 1))
147
+
118
148
  unless scope.last_page?
149
+ query = params.merge(param_name => scope.next_page)
119
150
  link_to name, env['PATH_INFO'] + (query.empty? ? '' : "?#{query.to_query}"), options.reverse_merge(:rel => 'next')
120
151
  else
121
- placeholder
152
+ placeholder.to_s.html_safe
122
153
  end
123
154
  end
124
155
  end
@@ -16,17 +16,27 @@ module Kaminari
16
16
  def initialize(template, options = {}) #:nodoc:
17
17
  @template, @options = template, options.dup
18
18
  @param_name = @options.delete(:param_name) || Kaminari.config.param_name
19
- @theme = @options[:theme] ? "#{@options.delete(:theme)}/" : ''
19
+ @theme = @options.delete(:theme)
20
+ @views_prefix = @options[:views_prefix]
20
21
  @params = @options[:params] ? template.params.merge(@options.delete :params) : template.params
21
22
  end
22
23
 
23
24
  def to_s(locals = {}) #:nodoc:
24
- @template.render :partial => "kaminari/#{@theme}#{self.class.name.demodulize.underscore}", :locals => @options.merge(locals), :formats => [:html]
25
+ @template.render :partial => partial_path, :locals => @options.merge(locals), :formats => [:html]
25
26
  end
26
27
 
27
28
  def page_url_for(page)
28
29
  @template.url_for @params.merge(@param_name => (page <= 1 ? nil : page), :only_path => true)
29
30
  end
31
+
32
+ def partial_path
33
+ [
34
+ @views_prefix,
35
+ "kaminari",
36
+ @theme,
37
+ self.class.name.demodulize.underscore
38
+ ].compact.join("/")
39
+ end
30
40
  end
31
41
 
32
42
  # Tag that contains a link
@@ -18,7 +18,6 @@ module Kaminari
18
18
  begin; require 'mongoid'; rescue LoadError; end
19
19
  if defined? ::Mongoid
20
20
  require 'kaminari/models/mongoid_extension'
21
- ::Mongoid::Criteria.send :include, Kaminari::MongoidExtension::Criteria
22
21
  ::Mongoid::Document.send :include, Kaminari::MongoidExtension::Document
23
22
  end
24
23
 
@@ -8,14 +8,14 @@ module Kaminari
8
8
  class << self
9
9
  def inherited_with_kaminari(kls) #:nodoc:
10
10
  inherited_without_kaminari kls
11
- kls.send(:include, Kaminari::ActiveRecordModelExtension) if kls.superclass == ActiveRecord::Base
11
+ kls.send(:include, Kaminari::ActiveRecordModelExtension) if kls.superclass == ::ActiveRecord::Base
12
12
  end
13
13
  alias_method_chain :inherited, :kaminari
14
14
  end
15
15
 
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
@@ -8,6 +8,10 @@ module Kaminari
8
8
  end
9
9
  end
10
10
 
11
+ def entry_name
12
+ model_name.human.downcase
13
+ end
14
+
11
15
  def total_count(column_name = :all, options = {}) #:nodoc:
12
16
  # #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
17
  @total_count ||= begin
@@ -17,11 +17,15 @@ module Kaminari
17
17
  extend Kaminari::PageScopeMethods
18
18
  end
19
19
 
20
- if options[:total_count]
21
- super original_array
22
- else
23
- super(original_array[@_offset_value, @_limit_value] || [])
20
+ if @_total_count
21
+ original_array = original_array.first(@_total_count)
24
22
  end
23
+
24
+ super(original_array[@_offset_value, @_limit_value] || [])
25
+ end
26
+
27
+ def entry_name
28
+ "entry"
25
29
  end
26
30
 
27
31
  # items at the specified "page"
@@ -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
@@ -1,5 +1,9 @@
1
1
  module Kaminari
2
2
  module MongoidCriteriaMethods
3
+ def entry_name
4
+ model_name.human.downcase
5
+ end
6
+
3
7
  def limit_value #:nodoc:
4
8
  options[:limit]
5
9
  end
@@ -9,7 +13,15 @@ module Kaminari
9
13
  end
10
14
 
11
15
  def total_count #:nodoc:
12
- embedded? ? unpage.length : length
16
+ @total_count ||= if embedded?
17
+ unpage.count
18
+ else
19
+ if options[:max_scan] && options[:max_scan] < count
20
+ options[:max_scan]
21
+ else
22
+ count
23
+ end
24
+ end
13
25
  end
14
26
 
15
27
  private
@@ -2,18 +2,6 @@ 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
@@ -4,6 +4,10 @@ module Kaminari
4
4
 
5
5
  delegate :default_per_page, :max_per_page, :max_pages, :to => :model
6
6
 
7
+ def entry_name
8
+ model.model_name.human.downcase
9
+ end
10
+
7
11
  def limit_value #:nodoc:
8
12
  options[:limit]
9
13
  end
@@ -1,3 +1,3 @@
1
1
  module Kaminari
2
- VERSION = '0.15.1'
2
+ VERSION = '0.16.0'
3
3
  end
@@ -1,3 +1,3 @@
1
1
  # database
2
2
  ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ':memory:'}}
3
- ActiveRecord::Base.establish_connection('test')
3
+ ActiveRecord::Base.establish_connection :test
@@ -3,12 +3,14 @@
3
3
  # Psych does not yet support YAML 1.1 merge keys.
4
4
  # Merge keys is often used in mongoid.yml
5
5
  # See: http://redmine.ruby-lang.org/issues/show/4300
6
+ require 'mongoid/version'
7
+
6
8
  if RUBY_VERSION >= '1.9.2'
7
9
  YAML::ENGINE.yamler = 'syck'
8
10
  end
9
11
 
10
12
  Mongoid.configure do |config|
11
- if Mongoid::VERSION =~ /^3/
13
+ if Mongoid::VERSION > '3.0.0'
12
14
  config.sessions = {:default => {:hosts => ['localhost:27017'], :database => 'kaminari_test'}}
13
15
  else
14
16
  config.master = Mongo::Connection.new.db('kaminari_test')
@@ -1,5 +1,9 @@
1
1
  class User
2
2
  include ::Mongoid::Document
3
+ if Mongoid::VERSION > '4.0.0'
4
+ include Mongoid::Attributes::Dynamic
5
+ end
6
+
3
7
  field :name, :type => String
4
8
  field :age, :type => Integer
5
9
  end
@@ -0,0 +1 @@
1
+ <b><%= current_page %></b>
@@ -0,0 +1,3 @@
1
+ <%= paginator.render do -%>
2
+ <%= first_page_tag %>
3
+ <% end -%>
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ if defined?(Rails)
4
+ require 'rails/generators'
5
+ require 'generators/kaminari/views_generator'
6
+
7
+ describe Kaminari::Generators::GitHubApiHelper, :generator_spec => true do
8
+ describe '.get_files_in_master' do
9
+ subject { Kaminari::Generators::GitHubApiHelper.get_files_in_master }
10
+ it { should include(["README", "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"]) }
11
+ end
12
+
13
+ describe '.get_content_for' do
14
+ subject { Kaminari::Generators::GitHubApiHelper.get_content_for("README") }
15
+ it { should == "" }
16
+ end
17
+ end
18
+ end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe 'Kaminari::ActionViewExtension' do
3
+ describe 'Kaminari::ActionViewExtension', :if => defined?(Rails)do
4
4
  describe '#paginate' do
5
5
  before do
6
6
  50.times {|i| User.create! :name => "user#{i}"}
@@ -15,6 +15,12 @@ describe 'Kaminari::ActionViewExtension' do
15
15
  lambda { helper.escape_javascript(helper.paginate @users, :params => {:controller => 'users', :action => 'index'}) }.should_not raise_error
16
16
  end
17
17
  end
18
+
19
+ context 'accepts :view_prefix option' do
20
+ before { helper.controller.append_view_path "spec/fake_app/views" }
21
+ subject { helper.paginate @users, :views_prefix => "alternative/", :params => {:controller => 'users', :action => 'index'} }
22
+ it { should eq(" <b>1</b>\n") }
23
+ end
18
24
  end
19
25
 
20
26
  describe '#link_to_previous_page' do
@@ -248,7 +254,7 @@ describe 'Kaminari::ActionViewExtension' do
248
254
 
249
255
  describe '#rel_next_prev_link_tags' do
250
256
  before do
251
- 75.times {|i| User.create! :name => "user#{i}"}
257
+ 80.times {|i| User.create! :name => "user#{i}"}
252
258
  end
253
259
 
254
260
  context 'the first page' do
@@ -257,31 +263,32 @@ describe 'Kaminari::ActionViewExtension' do
257
263
  end
258
264
 
259
265
  subject { helper.rel_next_prev_link_tags @users, :params => {:controller => 'users', :action => 'index'} }
260
- it { should be_a String }
261
- it { should match(/rel="next"/) }
262
266
  it { should_not match(/rel="prev"/) }
267
+ it { should match(/rel="next"/) }
268
+ it { should match(/\?page=2/) }
263
269
  end
264
270
 
265
271
  context 'the middle page' do
266
272
  before do
267
- @users = User.page(2).per(25)
273
+ @users = User.page(3).per(25)
268
274
  end
269
275
 
270
276
  subject { helper.rel_next_prev_link_tags @users, :params => {:controller => 'users', :action => 'index'} }
271
- it { should be_a String }
272
- it { should match(/rel="next"/) }
273
277
  it { should match(/rel="prev"/) }
278
+ it { should match(/\?page=2/) }
279
+ it { should match(/rel="next"/) }
280
+ it { should match(/\?page=4/) }
274
281
  end
275
282
 
276
283
  context 'the last page' do
277
284
  before do
278
- @users = User.page(3).per(25)
285
+ @users = User.page(4).per(25)
279
286
  end
280
287
 
281
288
  subject { helper.rel_next_prev_link_tags @users, :params => {:controller => 'users', :action => 'index'} }
282
- it { should be_a String }
283
- it { should_not match(/rel="next"/) }
284
289
  it { should match(/rel="prev"/) }
290
+ it { should match(/\?page=3"/) }
291
+ it { should_not match(/rel="next"/) }
285
292
  end
286
293
  end
287
294
  end