api-pagination 4.7.2 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fcd1a8e55bce363ef14c8fca2ff4a06ea1cf325e61fe2eba564d6bcbcb0cbb43
4
- data.tar.gz: 66a8a77cc4e1fa163ce3e644c2828388778efaab24783967c2c9e7986a83ac30
3
+ metadata.gz: ba0df72041cd862671500fd9efe94c7fe8e35975877e0e9bbcd1c0b77860e4a4
4
+ data.tar.gz: debcf49e29dcda50d93cd31a2e9efec2332541dbe38f6bdaa488b450e5bb7d09
5
5
  SHA512:
6
- metadata.gz: 475209b5986a009d9bc52cded5269fec22998e6d94c419635772950ee17ea7a1b0a01818b6791f009fe9da545022522f2ba0303a5fae93d81a364f3bc740cb1e
7
- data.tar.gz: 355d8e7786bf49318941d48ea57ff6fd81fd6cf9b97d9e185fb1302eb20dc4144100f3fce675809d73bffc0341b0f100e37fb3f12a2e6c51ea9b98e4d9db5a03
6
+ metadata.gz: 4661d9bfa18456e1c6fcfb837ef4c3acbc9e35dd983299201340dc077056e3f5632c39a8f718b285d66b4e3985aec23da68a56c8c278f0fc850f27626352bb0b
7
+ data.tar.gz: 688fae38d680fb9f1b133a627172d687c7fa6f56186039a88a5bfe238e396c5310359266580644d7719b981d6f3589ac884f6b6d88688c497c8516cbffd122cd
@@ -10,6 +10,8 @@ module ApiPagination
10
10
 
11
11
  attr_accessor :base_url
12
12
 
13
+ attr_accessor :response_formats
14
+
13
15
  def configure(&block)
14
16
  yield self
15
17
  end
@@ -20,6 +22,7 @@ module ApiPagination
20
22
  @page_header = nil
21
23
  @include_total = true
22
24
  @base_url = nil
25
+ @response_formats = [:json, :xml]
23
26
  end
24
27
 
25
28
  ['page', 'per_page'].each do |param_name|
@@ -50,11 +53,17 @@ module ApiPagination
50
53
  end
51
54
 
52
55
  def paginator
53
- @paginator || set_paginator
56
+ if instance_variable_defined? :@paginator
57
+ @paginator
58
+ else
59
+ set_paginator
60
+ end
54
61
  end
55
62
 
56
63
  def paginator=(paginator)
57
64
  case paginator.to_sym
65
+ when :pagy
66
+ use_pagy
58
67
  when :kaminari
59
68
  use_kaminari
60
69
  when :will_paginate
@@ -67,11 +76,12 @@ module ApiPagination
67
76
  private
68
77
 
69
78
  def set_paginator
70
- if defined?(Kaminari) && defined?(WillPaginate::CollectionMethods)
79
+ conditions = [defined?(Pagy), defined?(Kaminari), defined?(WillPaginate::CollectionMethods)]
80
+ if conditions.compact.size > 1
71
81
  Kernel.warn <<-WARNING
72
- Warning: api-pagination relies on either Kaminari or WillPaginate, but both are
73
- currently active. If possible, you should remove one or the other. If you can't,
74
- you _must_ configure api-pagination on your own. For example:
82
+ Warning: api-pagination relies on Pagy, Kaminari, or WillPaginate, but more than
83
+ one are currently active. If possible, you should remove one or the other. If
84
+ you can't, you _must_ configure api-pagination on your own. For example:
75
85
 
76
86
  ApiPagination.configure do |config|
77
87
  config.paginator = :kaminari
@@ -86,13 +96,19 @@ Kaminari.configure do |config|
86
96
  end
87
97
 
88
98
  WARNING
99
+ elsif defined?(Pagy)
100
+ use_pagy
89
101
  elsif defined?(Kaminari)
90
- return use_kaminari
102
+ use_kaminari
91
103
  elsif defined?(WillPaginate::CollectionMethods)
92
- return use_will_paginate
104
+ use_will_paginate
93
105
  end
94
106
  end
95
107
 
108
+ def use_pagy
109
+ @paginator = :pagy
110
+ end
111
+
96
112
  def use_kaminari
97
113
  require 'kaminari/models/array_extension'
98
114
  @paginator = :kaminari
@@ -1,17 +1,26 @@
1
1
  begin; require 'grape'; rescue LoadError; end
2
2
  if defined?(Grape::API)
3
3
  require 'grape/pagination'
4
- Grape::API.send(:include, Grape::Pagination)
4
+
5
+ klass = if Grape::VERSION >= '1.2.0' || defined?(Grape::API::Instance)
6
+ Grape::API::Instance
7
+ else
8
+ Grape::API
9
+ end
10
+
11
+ klass.send(:include, Grape::Pagination)
5
12
  end
6
13
 
14
+ begin; require 'pagy'; rescue LoadError; end
7
15
  begin; require 'kaminari'; rescue LoadError; end
8
16
  begin; require 'will_paginate'; rescue LoadError; end
9
17
 
10
- unless defined?(Kaminari) || defined?(WillPaginate::CollectionMethods)
18
+ unless defined?(Pagy) || defined?(Kaminari) || defined?(WillPaginate::CollectionMethods)
11
19
  Kernel.warn <<-WARNING.gsub(/^\s{4}/, '')
12
- Warning: api-pagination relies on either Kaminari or WillPaginate. Please
13
- install either dependency by adding one of the following to your Gemfile:
20
+ Warning: api-pagination relies on either Pagy, Kaminari, or WillPaginate.
21
+ Please install a paginator by adding one of the following to your Gemfile:
14
22
 
23
+ gem 'pagy'
15
24
  gem 'kaminari'
16
25
  gem 'will_paginate'
17
26
  WARNING
@@ -1,8 +1,8 @@
1
1
  module ApiPagination
2
2
  class Version
3
- MAJOR = 4
4
- MINOR = 7
5
- PATCH = 2
3
+ MAJOR = 5
4
+ MINOR = 0
5
+ PATCH = 0
6
6
 
7
7
  def self.to_s
8
8
  [MAJOR, MINOR, PATCH].join('.')
@@ -9,6 +9,8 @@ module ApiPagination
9
9
  options[:per_page] = options[:per_page].to_i
10
10
 
11
11
  case ApiPagination.config.paginator
12
+ when :pagy
13
+ paginate_with_pagy(collection, options)
12
14
  when :kaminari
13
15
  paginate_with_kaminari(collection, options, options[:paginate_array_options] || {})
14
16
  when :will_paginate
@@ -18,7 +20,9 @@ module ApiPagination
18
20
  end
19
21
  end
20
22
 
21
- def pages_from(collection)
23
+ def pages_from(collection, options = {})
24
+ return pagy_pages_from(collection) if ApiPagination.config.paginator == :pagy && collection.is_a?(Pagy)
25
+
22
26
  {}.tap do |pages|
23
27
  unless collection.first_page?
24
28
  pages[:first] = 1
@@ -26,7 +30,7 @@ module ApiPagination
26
30
  end
27
31
 
28
32
  unless collection.last_page? || (ApiPagination.config.paginator == :kaminari && collection.out_of_range?)
29
- pages[:last] = collection.total_pages
33
+ pages[:last] = collection.total_pages if ApiPagination.config.include_total
30
34
  pages[:next] = collection.current_page + 1
31
35
  end
32
36
  end
@@ -34,6 +38,7 @@ module ApiPagination
34
38
 
35
39
  def total_from(collection)
36
40
  case ApiPagination.config.paginator
41
+ when :pagy then collection.count.to_s
37
42
  when :kaminari then collection.total_count.to_s
38
43
  when :will_paginate then collection.total_entries.to_s
39
44
  end
@@ -41,6 +46,47 @@ module ApiPagination
41
46
 
42
47
  private
43
48
 
49
+ def paginate_with_pagy(collection, options)
50
+ if Pagy::DEFAULT[:max_per_page] && options[:per_page] > Pagy::DEFAULT[:max_per_page]
51
+ options[:per_page] = Pagy::DEFAULT[:max_per_page]
52
+ elsif options[:per_page] <= 0
53
+ options[:per_page] = Pagy::DEFAULT[:items]
54
+ end
55
+
56
+ pagy = pagy_from(collection, options)
57
+ collection = if collection.respond_to?(:offset) && collection.respond_to?(:limit)
58
+ collection.offset(pagy.offset).limit(pagy.items)
59
+ else
60
+ collection[pagy.offset, pagy.items]
61
+ end
62
+
63
+ return [collection, pagy]
64
+ end
65
+
66
+ def pagy_from(collection, options)
67
+ if options[:count]
68
+ count = options[:count]
69
+ else
70
+ count = collection.is_a?(Array) ? collection.count : collection.count(:all)
71
+ end
72
+
73
+ Pagy.new(count: count, items: options[:per_page], page: options[:page])
74
+ end
75
+
76
+ def pagy_pages_from(pagy)
77
+ {}.tap do |pages|
78
+ unless pagy.page == 1
79
+ pages[:first] = 1
80
+ pages[:prev] = pagy.prev
81
+ end
82
+
83
+ unless pagy.page == pagy.pages
84
+ pages[:last] = pagy.pages if ApiPagination.config.include_total
85
+ pages[:next] = pagy.next
86
+ end
87
+ end
88
+ end
89
+
44
90
  def paginate_with_kaminari(collection, options, paginate_array_options = {})
45
91
  if Kaminari.config.max_per_page && options[:per_page] > Kaminari.config.max_per_page
46
92
  options[:per_page] = Kaminari.config.max_per_page
@@ -48,8 +94,10 @@ module ApiPagination
48
94
  options[:per_page] = get_default_per_page_for_kaminari(collection)
49
95
  end
50
96
 
51
- collection = Kaminari.paginate_array(collection, paginate_array_options) if collection.is_a?(Array)
52
- collection.page(options[:page]).per(options[:per_page])
97
+ collection = Kaminari.paginate_array(collection, **paginate_array_options) if collection.is_a?(Array)
98
+ collection = collection.page(options[:page]).per(options[:per_page])
99
+ collection.without_count if !collection.is_a?(Array) && !ApiPagination.config.include_total
100
+ [collection, nil]
53
101
  end
54
102
 
55
103
  def paginate_with_will_paginate(collection, options)
@@ -57,35 +105,36 @@ module ApiPagination
57
105
  options[:per_page] = default_per_page_for_will_paginate(collection)
58
106
  end
59
107
 
60
- if defined?(Sequel::Dataset) && collection.kind_of?(Sequel::Dataset)
108
+ collection = if defined?(Sequel::Dataset) && collection.kind_of?(Sequel::Dataset)
61
109
  collection.paginate(options[:page], options[:per_page])
62
110
  else
63
111
  supported_options = [:page, :per_page, :total_entries]
64
112
  options = options.dup.keep_if { |k,v| supported_options.include?(k.to_sym) }
65
113
  collection.paginate(options)
66
114
  end
115
+
116
+ [collection, nil]
67
117
  end
68
118
 
69
119
  def get_default_per_page_for_kaminari(collection)
70
120
  default = Kaminari.config.default_per_page
71
- detect_model(collection).default_per_page || default
72
- rescue
73
- default
121
+ extract_per_page_from_model(collection, :default_per_page) || default
74
122
  end
75
123
 
76
124
  def default_per_page_for_will_paginate(collection)
77
125
  default = WillPaginate.per_page
78
- detect_model(collection).per_page || default
79
- rescue
80
- default
126
+ extract_per_page_from_model(collection, :per_page) || default
81
127
  end
82
128
 
83
- def detect_model(collection)
84
- if collection.respond_to?(:table_name)
85
- collection.table_name.classify.constantize
129
+ def extract_per_page_from_model(collection, accessor)
130
+ klass = if collection.respond_to?(:klass)
131
+ collection.klass
86
132
  else
87
133
  collection.first.class
88
134
  end
135
+
136
+ return unless klass.respond_to?(accessor)
137
+ klass.send(accessor)
89
138
  end
90
139
  end
91
140
  end
@@ -9,11 +9,11 @@ module Grape
9
9
  :page => ApiPagination.config.page_param(params),
10
10
  :per_page => [per_page, route_setting(:max_per_page)].compact.min
11
11
  }
12
- collection = ApiPagination.paginate(collection, options)
12
+ collection, pagy = ApiPagination.paginate(collection, options)
13
13
 
14
14
  links = (header['Link'] || "").split(',').map(&:strip)
15
15
  url = request.url.sub(/\?.*$/, '')
16
- pages = ApiPagination.pages_from(collection)
16
+ pages = ApiPagination.pages_from(pagy || collection, options)
17
17
 
18
18
  pages.each do |k, v|
19
19
  old_params = Rack::Utils.parse_nested_query(request.query_string)
@@ -27,7 +27,7 @@ module Grape
27
27
  include_total = ApiPagination.config.include_total
28
28
 
29
29
  header 'Link', links.join(', ') unless links.empty?
30
- header total_header, ApiPagination.total_from(collection).to_s if include_total
30
+ header total_header, ApiPagination.total_from(pagy || collection).to_s if include_total
31
31
  header per_page_header, options[:per_page].to_s
32
32
  header page_header, options[:page].to_s unless page_header.nil?
33
33
 
@@ -46,7 +46,7 @@ module Grape
46
46
  params do
47
47
  optional :page, :type => Integer, :default => 1,
48
48
  :desc => 'Page of results to fetch.'
49
- optional :per_page, :type => Integer,
49
+ optional :per_page, :type => Integer, :default => options[:per_page],
50
50
  :desc => 'Number of results to return per page.',
51
51
  :values => per_page_values
52
52
  end
@@ -8,11 +8,12 @@ module Rails
8
8
 
9
9
  return _paginate_collection(collection, options) if collection
10
10
 
11
- collection = options[:json] || options[:xml]
11
+ response_format = _discover_format(options)
12
+
13
+ collection = options[response_format]
12
14
  collection = _paginate_collection(collection, options)
13
15
 
14
- options[:json] = collection if options[:json]
15
- options[:xml] = collection if options[:xml]
16
+ options[response_format] = collection if options[response_format]
16
17
 
17
18
  render options
18
19
  end
@@ -23,15 +24,21 @@ module Rails
23
24
 
24
25
  private
25
26
 
27
+ def _discover_format(options)
28
+ for response_format in ApiPagination.config.response_formats
29
+ return response_format if options.key?(response_format)
30
+ end
31
+ end
32
+
26
33
  def _paginate_collection(collection, options={})
27
34
  options[:page] = ApiPagination.config.page_param(params)
28
35
  options[:per_page] ||= ApiPagination.config.per_page_param(params)
29
36
 
30
- collection = ApiPagination.paginate(collection, options)
37
+ collection, pagy = ApiPagination.paginate(collection, options)
31
38
 
32
39
  links = (headers['Link'] || '').split(',').map(&:strip)
33
40
  url = base_url + request.path_info
34
- pages = ApiPagination.pages_from(collection)
41
+ pages = ApiPagination.pages_from(pagy || collection, options)
35
42
 
36
43
  pages.each do |k, v|
37
44
  new_params = request.query_parameters.merge(:page => v)
@@ -46,7 +53,7 @@ module Rails
46
53
  headers['Link'] = links.join(', ') unless links.empty?
47
54
  headers[per_page_header] = options[:per_page].to_s
48
55
  headers[page_header] = options[:page].to_s unless page_header.nil?
49
- headers[total_header] = total_count(collection, options).to_s if include_total
56
+ headers[total_header] = total_count(pagy || collection, options).to_s if include_total
50
57
 
51
58
  return collection
52
59
  end
@@ -62,6 +69,5 @@ module Rails
62
69
  def base_url
63
70
  ApiPagination.config.base_url || request.base_url
64
71
  end
65
-
66
72
  end
67
73
  end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+ require 'support/active_record/foo'
3
+ require 'nulldb_rspec'
4
+
5
+ ActiveRecord::Base.establish_connection(
6
+ adapter: :nulldb,
7
+ schema: 'spec/support/active_record/schema.rb'
8
+ )
9
+
10
+ NullDB.configure { |ndb| def ndb.project_root; Dir.pwd; end; }
11
+
12
+ shared_examples 'produces_correct_sql' do
13
+ it 'produces correct sql for first page' do
14
+ allow(collection).to receive(:count).and_return(collection_size)
15
+ paginated_sql, _ = ApiPagination.paginate(collection, per_page: per_page)
16
+ expect(paginated_sql.to_sql).to eql(Foo.limit(per_page).offset(0).to_sql)
17
+ end
18
+ end
19
+
20
+ describe 'ActiveRecord Support' do
21
+ let(:collection) { Foo.all }
22
+ let(:collection_size) { 50 }
23
+ let(:per_page) { 5 }
24
+
25
+ if ApiPagination.config.paginator == :will_paginate
26
+ require 'will_paginate/active_record'
27
+ end
28
+
29
+ context "pagination with #{ApiPagination.config.paginator}" do
30
+ include_examples 'produces_correct_sql'
31
+ end
32
+
33
+
34
+ if ApiPagination.config.paginator != :pagy
35
+ context 'reflections' do
36
+ it 'invokes the correct methods to determine type' do
37
+ expect(collection).to receive(:klass).at_least(:once)
38
+ .and_call_original
39
+ ApiPagination.paginate(collection)
40
+ end
41
+
42
+ it 'does not fail if table name is not snake cased class name' do
43
+ allow(collection).to receive(:table_name).and_return(SecureRandom.uuid)
44
+ expect { ApiPagination.paginate(collection) }.to_not raise_error
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+
@@ -2,63 +2,73 @@ require 'spec_helper'
2
2
 
3
3
  describe ApiPagination do
4
4
  let(:collection) {(1..100).to_a}
5
+ let(:active_record_relation) {double("ActiveRecord_Relation").as_null_object}
5
6
  let(:paginate_array_options) {{ total_count: 1000 }}
6
7
 
7
8
  describe "#paginate" do
8
- context 'Using kaminari' do
9
- before do
10
- ApiPagination.config.paginator = :kaminari
11
- end
9
+ if ENV['PAGINATOR'].to_sym == :kaminari
10
+ context 'Using kaminari' do
11
+ describe '.paginate' do
12
+ it 'should accept paginate_array_options option' do
13
+ expect(Kaminari).to receive(:paginate_array)
14
+ .with(collection, **paginate_array_options)
15
+ .and_call_original
12
16
 
13
- after do
14
- ApiPagination.config.paginator = ENV['PAGINATOR'].to_sym
15
- end
17
+ ApiPagination.paginate(
18
+ collection,
19
+ {
20
+ per_page: 30,
21
+ paginate_array_options: paginate_array_options
22
+ }
23
+ )
24
+ end
16
25
 
17
- it 'should accept paginate_array_options option' do
18
- expect(Kaminari).to receive(:paginate_array)
19
- .with(collection, paginate_array_options)
20
- .and_call_original
26
+ context 'configured not to include the total' do
27
+ before { ApiPagination.config.include_total = false }
21
28
 
22
- ApiPagination.paginate(
23
- collection,
24
- {
25
- per_page: 30,
26
- paginate_array_options: paginate_array_options
27
- }
28
- )
29
- end
29
+ context 'and paginating an array' do
30
+ it 'should not call without_count on the collection' do
31
+ expect(collection).to_not receive :without_count
32
+ ApiPagination.paginate(collection)
33
+ end
34
+ end
35
+ context 'and paginating an active record relation' do
36
+ it 'should call without_count on the relation' do
37
+ expect(active_record_relation).to receive :without_count
38
+ ApiPagination.paginate(active_record_relation)
39
+ end
40
+ end
41
+
42
+ after { ApiPagination.config.include_total = true }
43
+ end
44
+ end
30
45
 
31
- describe '.pages_from' do
32
- subject {described_class.pages_from collection}
46
+ describe '.pages_from' do
47
+ subject { described_class.pages_from(collection) }
33
48
 
34
- context 'on empty collection' do
35
- let(:collection) {ApiPagination.paginate [], page: 1}
49
+ context 'on empty collection' do
50
+ let(:collection) { ApiPagination.paginate([], page: 1).first }
36
51
 
37
- it {is_expected.to be_empty}
52
+ it { is_expected.to be_empty }
53
+ end
38
54
  end
39
55
  end
40
56
  end
41
57
 
42
- context 'Using will_paginate' do
43
- before do
44
- ApiPagination.config.paginator = :will_paginate
45
- end
46
-
47
- after do
48
- ApiPagination.config.paginator = ENV['PAGINATOR'].to_sym
49
- end
50
-
51
- context 'passing in total_entries in options' do
52
- it 'should set total_entries using the passed in value' do
53
- paginated_collection = ApiPagination.paginate(collection, total_entries: 3000)
54
- expect(paginated_collection.total_entries).to eq(3000)
58
+ if ENV['PAGINATOR'].to_sym == :will_paginate
59
+ context 'Using will_paginate' do
60
+ context 'passing in total_entries in options' do
61
+ it 'should set total_entries using the passed in value' do
62
+ paginated_collection = ApiPagination.paginate(collection, total_entries: 3000).first
63
+ expect(paginated_collection.total_entries).to eq(3000)
64
+ end
55
65
  end
56
- end
57
66
 
58
- context 'passing in collection only' do
59
- it 'should set total_entries using the size of the collection ' do
60
- paginated_collection = ApiPagination.paginate(collection)
61
- expect(paginated_collection.total_entries).to eq(100)
67
+ context 'passing in collection only' do
68
+ it 'should set total_entries using the size of the collection ' do
69
+ paginated_collection = ApiPagination.paginate(collection).first
70
+ expect(paginated_collection.total_entries).to eq(100)
71
+ end
62
72
  end
63
73
  end
64
74
  end
data/spec/grape_spec.rb CHANGED
@@ -5,8 +5,11 @@ require 'support/shared_examples/middle_page'
5
5
  require 'support/shared_examples/last_page'
6
6
 
7
7
  describe NumbersAPI do
8
+ it { is_expected.to be_kind_of(Grape::Pagination) }
9
+
8
10
  describe 'GET #index' do
9
- let(:links) { last_response.headers['Link'].split(', ') }
11
+ let(:link) { last_response.headers['Link'] }
12
+ let(:links) { link.split(', ') }
10
13
  let(:total) { last_response.headers['Total'].to_i }
11
14
  let(:per_page) { last_response.headers['Per-Page'].to_i }
12
15
 
@@ -139,6 +142,12 @@ describe NumbersAPI do
139
142
  expect(last_response.header['Total']).to be_nil
140
143
  end
141
144
 
145
+ it 'should not include a link with rel "last"' do
146
+ get '/numbers', count: 100
147
+
148
+ expect(link).to_not include('rel="last"')
149
+ end
150
+
142
151
  after { ApiPagination.config.include_total = true }
143
152
  end
144
153
 
data/spec/rails_spec.rb CHANGED
@@ -8,7 +8,8 @@ describe NumbersController, :type => :controller do
8
8
  before { request.host = 'example.org' }
9
9
 
10
10
  describe 'GET #index' do
11
- let(:links) { response.headers['Link'].split(', ') }
11
+ let(:link) { response.headers['Link'] }
12
+ let(:links) { link.split(', ') }
12
13
  let(:total) { response.headers['Total'].to_i }
13
14
  let(:per_page) { response.headers['Per-Page'].to_i }
14
15
 
@@ -134,6 +135,12 @@ describe NumbersController, :type => :controller do
134
135
  expect(response.header['Total']).to be_nil
135
136
  end
136
137
 
138
+ it 'should not include a link with rel "last"' do
139
+ get :index, params: { count: 100 }
140
+
141
+ expect(link).to_not include('rel="last"')
142
+ end
143
+
137
144
  after { ApiPagination.config.include_total = true }
138
145
  end
139
146
 
@@ -214,8 +221,11 @@ describe NumbersController, :type => :controller do
214
221
  end
215
222
  end
216
223
 
217
- context 'paginate array options' do
218
- shared_examples 'properly set Total header' do
224
+ if ApiPagination.config.paginator.to_sym == :kaminari
225
+ context 'paginate array options' do
226
+ let(:paginate_array_total_count) { 300 }
227
+ let(:total_header) { 300 }
228
+ let(:count) { 50 }
219
229
  let(:params) do
220
230
  {
221
231
  paginate_array_total_count: paginate_array_total_count,
@@ -223,80 +233,75 @@ describe NumbersController, :type => :controller do
223
233
  }
224
234
  end
225
235
 
226
- specify do
236
+ it 'has a properly set Total header' do
227
237
  get :index_with_paginate_array_options, params: params
228
238
 
229
239
  expect(response.header['Total']).to be_kind_of(String)
230
240
  expect(response.header['Total'].to_i).to eq total_header
231
241
  end
232
242
  end
243
+ end
233
244
 
234
- context 'kaminari' do
235
- around do |example|
236
- paginator = ApiPagination.config.paginator
237
- ApiPagination.config.paginator = :kaminari
238
- example.run
239
- ApiPagination.config.paginator = paginator
240
- end
245
+ if [:will_paginate, :kaminari].include?(ApiPagination.config.paginator.to_sym)
246
+ context 'default per page in model' do
247
+ before do
248
+ class Fixnum
249
+ @default_per_page = 6
250
+ @per_page = 6
241
251
 
242
- it_should_behave_like 'properly set Total header' do
243
- let(:paginate_array_total_count) { 300 }
244
- let(:total_header) { 300 }
245
- let(:count) { 50 }
252
+ class << self
253
+ attr_accessor :default_per_page, :per_page
254
+ end
255
+ end
246
256
  end
247
- end
248
257
 
249
- context 'will_paginate' do
250
- around do |example|
251
- paginator = ApiPagination.config.paginator
252
- ApiPagination.config.paginator = :will_paginate
253
- example.run
254
- ApiPagination.config.paginator = paginator
258
+ after do
259
+ class Fixnum
260
+ @default_per_page = 25
261
+ @per_page = 25
262
+ end
255
263
  end
256
264
 
257
- it_should_behave_like 'properly set Total header' do
258
- let(:paginate_array_total_count) { 300 }
259
- let(:total_header) { 50 }
260
- let(:count) { 50 }
265
+ after :all do
266
+ class Fixnum
267
+ class << self
268
+ undef_method :default_per_page, :per_page
269
+ end
270
+ end
261
271
  end
262
- end
263
- end
264
272
 
265
- context 'default per page in model' do
266
- before do
267
- class Fixnum
268
- @default_per_page = 6
269
- @per_page = 6
273
+ it 'should use default per page from model' do
274
+ get :index_with_no_per_page, params: {count: 100}
270
275
 
271
- class << self
272
- attr_accessor :default_per_page, :per_page
273
- end
276
+ expect(response.header['Per-Page']).to eq('6')
274
277
  end
275
- end
276
278
 
277
- after do
278
- class Fixnum
279
- @default_per_page = 25
280
- @per_page = 25
281
- end
282
- end
279
+ it 'should not fail if the model yields nil for per page' do
280
+ class Fixnum
281
+ @default_per_page = nil
282
+ @per_page = nil
283
+ end
283
284
 
284
- it 'should use default per page from model' do
285
- get :index_with_no_per_page, params: {count: 100}
285
+ get :index_with_no_per_page, params: {count: 100}
286
286
 
287
- expect(response.header['Per-Page']).to eq('6')
287
+ expect(response.header['Per-Page']).to eq(
288
+ case ApiPagination.config.paginator
289
+ when :pagy then Pagy::DEFAULT[:items].to_s
290
+ when :kaminari then Kaminari.config.default_per_page.to_s
291
+ when :will_paginate then WillPaginate.per_page.to_s
292
+ end
293
+ )
294
+ end
288
295
  end
296
+ end
289
297
 
298
+ context 'default per page in objects without paginator defaults' do
290
299
  it 'should not fail if model does not respond to per page' do
291
- class Fixnum
292
- @default_per_page = nil
293
- @per_page = nil
294
- end
295
-
296
300
  get :index_with_no_per_page, params: {count: 100}
297
301
 
298
302
  expect(response.header['Per-Page']).to eq(
299
303
  case ApiPagination.config.paginator
304
+ when :pagy then Pagy::DEFAULT[:items].to_s
300
305
  when :kaminari then Kaminari.config.default_per_page.to_s
301
306
  when :will_paginate then WillPaginate.per_page.to_s
302
307
  end
data/spec/sequel_spec.rb CHANGED
@@ -23,9 +23,8 @@ if ApiPagination.config.paginator == :will_paginate
23
23
  end
24
24
 
25
25
  it 'returns a Sequel::Dataset' do
26
- collection = ApiPagination.paginate(people)
26
+ collection = ApiPagination.paginate(people).first
27
27
  expect(collection.kind_of?(Sequel::Dataset)).to be_truthy
28
28
  end
29
29
  end
30
30
  end
31
-
data/spec/spec_helper.rb CHANGED
@@ -3,14 +3,20 @@ require 'support/numbers_api'
3
3
  require 'api-pagination'
4
4
 
5
5
  if ENV['PAGINATOR'].nil?
6
- warn 'No PAGINATOR set. Defaulting to kaminari. To test against will_paginate, run `PAGINATOR=will_paginate bundle exec rspec`'
7
- ENV['PAGINATOR'] = 'kaminari'
6
+ warn <<-WARNING
7
+ No PAGINATOR set. Defaulting to pagy.
8
+
9
+ To test against kaminari, run `PAGINATOR=kaminari bundle exec rspec`
10
+ To test against will_paginate, run `PAGINATOR=will_paginate bundle exec rspec`
11
+ WARNING
12
+
13
+ ENV['PAGINATOR'] = 'pagy'
8
14
  end
9
15
 
10
16
  require ENV['PAGINATOR']
11
17
  ApiPagination.config.paginator = ENV['PAGINATOR'].to_sym
12
18
 
13
- require 'will_paginate/array'
19
+ require 'will_paginate/array' if ENV['PAGINATOR'].to_sym == :will_paginate
14
20
 
15
21
  RSpec.configure do |config|
16
22
  config.include Rack::Test::Methods
@@ -0,0 +1,3 @@
1
+ require 'active_record'
2
+
3
+ class Foo < ActiveRecord::Base; end
@@ -0,0 +1,5 @@
1
+ ActiveRecord::Schema.define(version: 0) do
2
+ create_table "foos", :force => true do |t|
3
+ t.string "foo"
4
+ end
5
+ end
@@ -1,10 +1,10 @@
1
1
  shared_examples 'an endpoint with a first page' do
2
2
  it 'should not give a link with rel "first"' do
3
- expect(links).not_to include('rel="first"')
3
+ expect(link).not_to include('rel="first"')
4
4
  end
5
5
 
6
6
  it 'should not give a link with rel "prev"' do
7
- expect(links).not_to include('rel="prev"')
7
+ expect(link).not_to include('rel="prev"')
8
8
  end
9
9
 
10
10
  it 'should give a link with rel "last"' do
@@ -1,10 +1,10 @@
1
1
  shared_examples 'an endpoint with a last page' do
2
2
  it 'should not give a link with rel "last"' do
3
- expect(links).not_to include('rel="last"')
3
+ expect(link).not_to include('rel="last"')
4
4
  end
5
5
 
6
6
  it 'should not give a link with rel "next"' do
7
- expect(links).not_to include('rel="next"')
7
+ expect(link).not_to include('rel="next"')
8
8
  end
9
9
 
10
10
  it 'should give a link with rel "first"' do
metadata CHANGED
@@ -1,85 +1,171 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api-pagination
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.7.2
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Celis
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-08 00:00:00.000000000 Z
11
+ date: 2021-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rspec
14
+ name: kaminari
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '3.0'
19
+ version: '1.2'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.2.1
20
23
  type: :development
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - "~>"
25
28
  - !ruby/object:Gem::Version
26
- version: '3.0'
29
+ version: '1.2'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.2.1
27
33
  - !ruby/object:Gem::Dependency
28
- name: grape
34
+ name: pagy
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '5.1'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 5.1.2
43
+ type: :development
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '5.1'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 5.1.2
53
+ - !ruby/object:Gem::Dependency
54
+ name: will_paginate
29
55
  requirement: !ruby/object:Gem::Requirement
30
56
  requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '3.3'
31
60
  - - ">="
32
61
  - !ruby/object:Gem::Version
33
- version: 0.10.0
62
+ version: 3.3.1
34
63
  type: :development
35
64
  prerelease: false
36
65
  version_requirements: !ruby/object:Gem::Requirement
37
66
  requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '3.3'
38
70
  - - ">="
39
71
  - !ruby/object:Gem::Version
40
- version: 0.10.0
72
+ version: 3.3.1
73
+ - !ruby/object:Gem::Dependency
74
+ name: rspec
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '3.10'
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: '3.10'
87
+ - !ruby/object:Gem::Dependency
88
+ name: grape
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "~>"
92
+ - !ruby/object:Gem::Version
93
+ version: '1.6'
94
+ type: :development
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '1.6'
41
101
  - !ruby/object:Gem::Dependency
42
102
  name: railties
43
103
  requirement: !ruby/object:Gem::Requirement
44
104
  requirements:
105
+ - - "~>"
106
+ - !ruby/object:Gem::Version
107
+ version: '6.1'
45
108
  - - ">="
46
109
  - !ruby/object:Gem::Version
47
- version: 5.0.0
110
+ version: 6.1.4.1
48
111
  type: :development
49
112
  prerelease: false
50
113
  version_requirements: !ruby/object:Gem::Requirement
51
114
  requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '6.1'
52
118
  - - ">="
53
119
  - !ruby/object:Gem::Version
54
- version: 5.0.0
120
+ version: 6.1.4.1
55
121
  - !ruby/object:Gem::Dependency
56
122
  name: actionpack
57
123
  requirement: !ruby/object:Gem::Requirement
58
124
  requirements:
125
+ - - "~>"
126
+ - !ruby/object:Gem::Version
127
+ version: '6.1'
59
128
  - - ">="
60
129
  - !ruby/object:Gem::Version
61
- version: 5.0.0
130
+ version: 6.1.4.1
62
131
  type: :development
63
132
  prerelease: false
64
133
  version_requirements: !ruby/object:Gem::Requirement
65
134
  requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '6.1'
66
138
  - - ">="
67
139
  - !ruby/object:Gem::Version
68
- version: 5.0.0
140
+ version: 6.1.4.1
69
141
  - !ruby/object:Gem::Dependency
70
142
  name: sequel
71
143
  requirement: !ruby/object:Gem::Requirement
72
144
  requirements:
73
- - - ">="
145
+ - - "~>"
74
146
  - !ruby/object:Gem::Version
75
- version: 4.9.0
147
+ version: '5.49'
76
148
  type: :development
77
149
  prerelease: false
78
150
  version_requirements: !ruby/object:Gem::Requirement
79
151
  requirements:
80
- - - ">="
152
+ - - "~>"
153
+ - !ruby/object:Gem::Version
154
+ version: '5.49'
155
+ - !ruby/object:Gem::Dependency
156
+ name: activerecord-nulldb-adapter
157
+ requirement: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - "~>"
81
160
  - !ruby/object:Gem::Version
82
- version: 4.9.0
161
+ version: 0.7.0
162
+ type: :development
163
+ prerelease: false
164
+ version_requirements: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - "~>"
167
+ - !ruby/object:Gem::Version
168
+ version: 0.7.0
83
169
  description: Link header pagination for Rails and Grape APIs
84
170
  email:
85
171
  - me@davidcel.is
@@ -94,11 +180,14 @@ files:
94
180
  - lib/api-pagination/version.rb
95
181
  - lib/grape/pagination.rb
96
182
  - lib/rails/pagination.rb
183
+ - spec/active_record_spec.rb
97
184
  - spec/api-pagination_spec.rb
98
185
  - spec/grape_spec.rb
99
186
  - spec/rails_spec.rb
100
187
  - spec/sequel_spec.rb
101
188
  - spec/spec_helper.rb
189
+ - spec/support/active_record/foo.rb
190
+ - spec/support/active_record/schema.rb
102
191
  - spec/support/numbers_api.rb
103
192
  - spec/support/numbers_controller.rb
104
193
  - spec/support/shared_examples/existing_headers.rb
@@ -109,35 +198,37 @@ homepage: https://github.com/davidcelis/api-pagination
109
198
  licenses:
110
199
  - MIT
111
200
  metadata: {}
112
- post_install_message:
201
+ post_install_message:
113
202
  rdoc_options: []
114
203
  require_paths:
115
204
  - lib
116
205
  required_ruby_version: !ruby/object:Gem::Requirement
117
206
  requirements:
118
- - - ">="
207
+ - - ">"
119
208
  - !ruby/object:Gem::Version
120
- version: '0'
209
+ version: '2.7'
121
210
  required_rubygems_version: !ruby/object:Gem::Requirement
122
211
  requirements:
123
212
  - - ">="
124
213
  - !ruby/object:Gem::Version
125
214
  version: '0'
126
215
  requirements: []
127
- rubyforge_project:
128
- rubygems_version: 2.7.6
129
- signing_key:
216
+ rubygems_version: 3.2.22
217
+ signing_key:
130
218
  specification_version: 4
131
219
  summary: Link header pagination for Rails and Grape APIs. Don't use the request body.
132
220
  test_files:
133
- - spec/spec_helper.rb
221
+ - spec/active_record_spec.rb
134
222
  - spec/api-pagination_spec.rb
223
+ - spec/grape_spec.rb
224
+ - spec/rails_spec.rb
135
225
  - spec/sequel_spec.rb
226
+ - spec/spec_helper.rb
227
+ - spec/support/active_record/foo.rb
228
+ - spec/support/active_record/schema.rb
136
229
  - spec/support/numbers_api.rb
137
230
  - spec/support/numbers_controller.rb
231
+ - spec/support/shared_examples/existing_headers.rb
138
232
  - spec/support/shared_examples/first_page.rb
139
- - spec/support/shared_examples/middle_page.rb
140
233
  - spec/support/shared_examples/last_page.rb
141
- - spec/support/shared_examples/existing_headers.rb
142
- - spec/grape_spec.rb
143
- - spec/rails_spec.rb
234
+ - spec/support/shared_examples/middle_page.rb