arid_cache 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +27 -9
- data/VERSION +1 -1
- data/arid_cache.gemspec +11 -4
- data/lib/arid_cache/cache_proxy/options.rb +73 -0
- data/lib/arid_cache/cache_proxy/result_processor.rb +199 -0
- data/lib/arid_cache/cache_proxy/utilities.rb +35 -0
- data/lib/arid_cache/cache_proxy.rb +63 -304
- data/lib/arid_cache.rb +1 -1
- data/spec/arid_cache/{cache_proxy_result_spec.rb → cache_proxy/cached_result_spec.rb} +2 -2
- data/spec/arid_cache/cache_proxy/options_spec.rb +80 -0
- data/spec/arid_cache/cache_proxy/result_processor_spec.rb +217 -0
- data/spec/arid_cache/cache_proxy_spec.rb +118 -89
- data/test/console +2 -0
- metadata +13 -6
@@ -1,13 +1,15 @@
|
|
1
|
+
require 'arid_cache/cache_proxy/utilities'
|
2
|
+
require 'arid_cache/cache_proxy/options'
|
3
|
+
require 'arid_cache/cache_proxy/result_processor'
|
4
|
+
|
1
5
|
module AridCache
|
2
6
|
class CacheProxy
|
3
|
-
attr_accessor :object, :key, :opts, :blueprint, :cached, :cache_key, :block, :records, :combined_options, :klass
|
4
7
|
|
5
|
-
# AridCache::CacheProxy::
|
8
|
+
# AridCache::CacheProxy::CachedResult
|
6
9
|
#
|
7
|
-
# This struct is stored in the cache and stores information
|
8
|
-
#
|
9
|
-
|
10
|
-
|
10
|
+
# This struct is stored in the cache and stores information about a
|
11
|
+
# collection of ActiveRecords.
|
12
|
+
CachedResult = Struct.new(:ids, :klass, :count) do
|
11
13
|
def has_count?
|
12
14
|
!count.nil?
|
13
15
|
end
|
@@ -25,6 +27,12 @@ module AridCache
|
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
30
|
+
OPTIONS_FOR_PAGINATE = [:page, :per_page, :total_entries, :finder]
|
31
|
+
OPTIONS_FOR_CACHE_PROXY = [:raw, :clear]
|
32
|
+
OPTIONS_FOR_FIND = [ :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly, :group, :having, :from, :lock ]
|
33
|
+
OPTIONS_FOR_CACHE = [ :expires_in ]
|
34
|
+
OPTIONS_FOR_CACHE_KEY = [ :auto_expire ]
|
35
|
+
|
28
36
|
#
|
29
37
|
# Managing your caches
|
30
38
|
#
|
@@ -34,26 +42,36 @@ module AridCache
|
|
34
42
|
end
|
35
43
|
|
36
44
|
def self.clear_class_caches(object)
|
37
|
-
key = (
|
45
|
+
key = (Utilities.object_class(object)).name.downcase + '-'
|
38
46
|
Rails.cache.delete_matched(%r[arid-cache-#{key}.*])
|
39
47
|
end
|
40
48
|
|
41
49
|
def self.clear_instance_caches(object)
|
42
|
-
key = AridCache::Inflector.pluralize((
|
50
|
+
key = AridCache::Inflector.pluralize((Utilities.object_class(object)).name).downcase
|
43
51
|
Rails.cache.delete_matched(%r[arid-cache-#{key}.*])
|
44
52
|
end
|
45
53
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
# Clear the cached result for this cache only
|
55
|
+
def clear_cached
|
56
|
+
Rails.cache.delete(@cache_key, @options.opts_for_cache)
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Initialize
|
61
|
+
#
|
53
62
|
|
54
|
-
|
55
|
-
|
56
|
-
|
63
|
+
def initialize(receiver, method, opts={}, &block)
|
64
|
+
@receiver = receiver
|
65
|
+
@method = method
|
66
|
+
@block = block
|
67
|
+
@blueprint = AridCache.store.find(@receiver, @method)
|
68
|
+
|
69
|
+
# Combine the options from the blueprint with the options for this call
|
70
|
+
opts = opts.symbolize_keys
|
71
|
+
@options = Options.new(@blueprint.nil? ? opts : @blueprint.opts.merge(opts))
|
72
|
+
@options[:receiver] = receiver
|
73
|
+
@cache_key = @receiver.arid_cache_key(@method, @options.opts_for_cache_key)
|
74
|
+
@cached = Rails.cache.read(@cache_key, @options.opts_for_cache)
|
57
75
|
end
|
58
76
|
|
59
77
|
#
|
@@ -61,308 +79,49 @@ module AridCache
|
|
61
79
|
#
|
62
80
|
|
63
81
|
# Return a count of ids in the cache, or return whatever is in the cache if it is
|
64
|
-
# not a CacheProxy::
|
82
|
+
# not a CacheProxy::CachedResult
|
65
83
|
def fetch_count
|
66
|
-
|
67
|
-
|
68
|
-
elsif cached.is_a?(AridCache::CacheProxy::Result)
|
69
|
-
cached.has_count? ? cached.count : execute_count
|
70
|
-
elsif cached.is_a?(Fixnum)
|
71
|
-
cached
|
72
|
-
elsif cached.respond_to?(:count)
|
73
|
-
cached.count
|
74
|
-
else
|
75
|
-
cached # what else can we do? return it
|
76
|
-
end
|
84
|
+
@options[:count_only] = true
|
85
|
+
result_processor.to_result
|
77
86
|
end
|
78
87
|
|
79
88
|
# Return a list of records using the options provided. If the item in the cache
|
80
|
-
# is not a CacheProxy::
|
89
|
+
# is not a CacheProxy::CachedResult it is returned after applying options. If there is nothing in the cache
|
81
90
|
# the block defining the cache is exectued. If the :raw option is true, returns the
|
82
|
-
# CacheProxy::
|
83
|
-
# are
|
91
|
+
# CacheProxy::CachedResult unmodified, ignoring other options, except where those options
|
92
|
+
# are needed to initialize the cache.
|
84
93
|
def fetch
|
85
|
-
|
86
|
-
|
87
|
-
result = if refresh_cache?
|
88
|
-
execute_find(@raw_result)
|
89
|
-
elsif cached.is_a?(AridCache::CacheProxy::Result)
|
90
|
-
if cached.has_ids? && @raw_result
|
91
|
-
self.cached # return it unmodified
|
92
|
-
elsif cached.has_ids?
|
93
|
-
fetch_from_cache # return a list of active records after applying options
|
94
|
-
else # true if we have only calculated the count thus far
|
95
|
-
execute_find(@raw_result)
|
96
|
-
end
|
97
|
-
else
|
98
|
-
cached # some base type, return it unmodified
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
# Clear the cached result for this cache only
|
103
|
-
def clear_cached
|
104
|
-
Rails.cache.delete(self.cache_key, opts_for_cache)
|
105
|
-
end
|
106
|
-
|
107
|
-
# Return the cached result for this object's key
|
108
|
-
def cached
|
109
|
-
@cached ||= Rails.cache.read(self.cache_key, opts_for_cache)
|
94
|
+
result_processor.to_result
|
110
95
|
end
|
111
96
|
|
112
|
-
# Return the class of the cached results i.e. if the cached result is a
|
113
|
-
# list of Album records, then klass returns Album. If there is nothing
|
114
|
-
# in the cache, then the class is inferred to be the class of the object
|
115
|
-
# that the cached method is being called on.
|
116
|
-
def klass
|
117
|
-
@klass ||= if self.cached && self.cached.is_a?(AridCache::CacheProxy::Result)
|
118
|
-
self.cached.klass
|
119
|
-
else
|
120
|
-
object_base_class
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
|
125
97
|
private
|
126
98
|
|
127
|
-
# Return a
|
128
|
-
# the
|
129
|
-
|
130
|
-
|
131
|
-
# a regular list of ActiveRecord results is returned.
|
132
|
-
#
|
133
|
-
# If no :order is specified, the current ordering of the ids is
|
134
|
-
# preserved with some fancy SQL.
|
135
|
-
def fetch_from_cache
|
136
|
-
if paginate?
|
137
|
-
|
138
|
-
# Return a paginated collection
|
139
|
-
if cached.ids.empty?
|
140
|
-
|
141
|
-
# No ids, return an empty WillPaginate result
|
142
|
-
[].paginate(opts_for_paginate)
|
143
|
-
|
144
|
-
elsif combined_options.include?(:order)
|
145
|
-
|
146
|
-
# An order has been specified. We have to go to the database
|
147
|
-
# and paginate there because the contents of the requested
|
148
|
-
# page will be different.
|
149
|
-
klass.paginate(cached.ids, { :total_entries => cached.ids.size }.merge(opts_for_find.merge(opts_for_paginate)))
|
150
|
-
|
151
|
-
else
|
152
|
-
|
153
|
-
# Order is unchanged. We can paginate in memory and only select
|
154
|
-
# those ids that we actually need. This is the most efficient.
|
155
|
-
paged_ids = cached.ids.paginate(opts_for_paginate)
|
156
|
-
paged_ids.replace(klass.find_all_by_id(paged_ids, opts_for_find(paged_ids)))
|
157
|
-
|
158
|
-
end
|
159
|
-
|
160
|
-
elsif cached.ids.empty?
|
161
|
-
|
162
|
-
# We are returning a regular (non-paginated) result.
|
163
|
-
# If we don't have any ids, that's an empty result
|
164
|
-
# in any language.
|
165
|
-
[]
|
166
|
-
|
167
|
-
elsif combined_options.include?(:order)
|
168
|
-
|
169
|
-
# An order has been specified, so use it.
|
170
|
-
klass.find_all_by_id(cached.ids, opts_for_find)
|
171
|
-
|
172
|
-
else
|
173
|
-
|
174
|
-
# No order has been specified, so we have to maintain
|
175
|
-
# the current order. We do this by passing some extra
|
176
|
-
# SQL which orders by the current array ordering.
|
177
|
-
offset, limit = combined_options.delete(:offset) || 0, combined_options.delete(:limit) || cached.count
|
178
|
-
ids = cached.ids[offset, limit]
|
179
|
-
|
180
|
-
klass.find_all_by_id(ids, opts_for_find(ids))
|
181
|
-
end
|
99
|
+
# Return a ResultProcessor instance. Seed the cache if we need to, otherwise
|
100
|
+
# use what is in the cache.
|
101
|
+
def result_processor
|
102
|
+
seed_cache? ? seed_cache : ResultProcessor.new(@cached, @options)
|
182
103
|
end
|
183
104
|
|
184
|
-
|
185
|
-
|
105
|
+
# Return a boolean indicating whether we need to seed the cache. Seed the cache
|
106
|
+
# if :force => true, the cache is empty or records have been requested and there
|
107
|
+
# are none in the cache yet.
|
108
|
+
def seed_cache?
|
109
|
+
@cached.nil? || @options.force? || (@cached.is_a?(CachedResult) && !@options.count_only? && !@cached.has_ids?)
|
186
110
|
end
|
187
111
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
# Seed the cache by executing the stored block (or by calling a method on the object).
|
198
|
-
# Then apply any options like pagination or ordering before returning the result, which
|
199
|
-
# is either some base type, or usually, a list of active records.
|
200
|
-
#
|
201
|
-
# Options:
|
202
|
-
# raw - if true, return the CacheProxy::Result after seeding the cache, ignoring
|
203
|
-
# other options. Default is false.
|
204
|
-
def execute_find(raw = false)
|
205
|
-
get_records
|
206
|
-
cached = AridCache::CacheProxy::Result.new
|
207
|
-
|
208
|
-
if !records.is_a?(Enumerable) || (!records.empty? && !records.first.is_a?(::ActiveRecord::Base))
|
209
|
-
cached = records # some base type, cache it as itself
|
210
|
-
else
|
211
|
-
cached.ids = records.collect(&:id)
|
212
|
-
cached.count = records.size
|
213
|
-
if records.respond_to?(:proxy_reflection) # association proxy
|
214
|
-
cached.klass = records.proxy_reflection.klass
|
215
|
-
elsif !records.empty?
|
216
|
-
cached.klass = records.first.class
|
217
|
-
else
|
218
|
-
cached.klass = object_base_class
|
219
|
-
end
|
220
|
-
end
|
221
|
-
Rails.cache.write(cache_key, cached, opts_for_cache)
|
222
|
-
self.cached = cached
|
223
|
-
|
224
|
-
# Return the raw result?
|
225
|
-
return self.cached if raw
|
226
|
-
|
227
|
-
# An order has been specified. We have to go to the database
|
228
|
-
# to order because we can't be sure that the current order is the same as the cache.
|
229
|
-
if cached.is_a?(AridCache::CacheProxy::Result) && combined_options.include?(:order)
|
230
|
-
self.klass = self.cached.klass # TODO used by fetch_from_cache needs refactor
|
231
|
-
fetch_from_cache
|
232
|
-
else
|
233
|
-
process_result_in_memory(records)
|
234
|
-
end
|
112
|
+
# Seed the cache by executing the stored block (or by calling a method on the object)
|
113
|
+
# and storing the result in the cache. Return the processed result ready to return
|
114
|
+
# to the user.
|
115
|
+
def seed_cache
|
116
|
+
block = @block || (@blueprint && @blueprint.proc)
|
117
|
+
block_result = block.nil? ? @receiver.instance_eval(@method) : @receiver.instance_eval(&block)
|
118
|
+
@result = ResultProcessor.new(block_result, @options)
|
119
|
+
write_cache(@result.to_cache)
|
120
|
+
@result
|
235
121
|
end
|
236
122
|
|
237
|
-
|
238
|
-
|
239
|
-
# to load the page rather than just using the records we have already fetched.
|
240
|
-
#
|
241
|
-
# If we are not paginating and the options include :limit (and optionally :offset)
|
242
|
-
# apply the limit and offset to the records before returning them.
|
243
|
-
#
|
244
|
-
# Otherwise we have an issue where all the records are returned the first time
|
245
|
-
# the collection is loaded, but on subsequent calls the options_for_find are
|
246
|
-
# included and you get different results. Note that with options like :order
|
247
|
-
# this cannot be helped. We don't want to modify the query that generates the
|
248
|
-
# collection because the idea is to allow getting different perspectives of the
|
249
|
-
# cached collection without relying on modifying the collection as a whole.
|
250
|
-
#
|
251
|
-
# If you do want a specialized, modified, or subset of the collection it's best
|
252
|
-
# to define it in a block and have a new cache for it:
|
253
|
-
#
|
254
|
-
# model.my_special_collection { the_collection(:order => 'new order', :limit => 10) }
|
255
|
-
def process_result_in_memory(records)
|
256
|
-
if opts.include?(:page)
|
257
|
-
records = records.respond_to?(:to_a) ? records.to_a : records
|
258
|
-
records.respond_to?(:paginate) ? records.paginate(opts_for_paginate) : records
|
259
|
-
elsif opts.include?(:limit)
|
260
|
-
records = records.respond_to?(:to_a) ? records.to_a : records
|
261
|
-
offset = opts[:offset] || 0
|
262
|
-
records[offset, opts[:limit]]
|
263
|
-
else
|
264
|
-
records
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
def execute_count
|
269
|
-
get_records
|
270
|
-
cached = AridCache::CacheProxy::Result.new
|
271
|
-
|
272
|
-
# Just get the count if we can.
|
273
|
-
#
|
274
|
-
# Because of how AssociationProxy works, if we even look at it, it'll
|
275
|
-
# trigger the query. So don't look.
|
276
|
-
#
|
277
|
-
# Association proxy or named scope. Check for an association first, because
|
278
|
-
# it doesn't trigger the select if it's actually named scope. Calling respond_to?
|
279
|
-
# on an association proxy will hower trigger a select because it loads up the target
|
280
|
-
# and passes the respond_to? on to it.
|
281
|
-
if records.respond_to?(:proxy_reflection) || records.respond_to?(:proxy_options)
|
282
|
-
cached.count = records.count # just get the count
|
283
|
-
cached.klass = object_base_class
|
284
|
-
elsif records.is_a?(Enumerable) && (records.empty? || records.first.is_a?(::ActiveRecord::Base))
|
285
|
-
cached.ids = records.collect(&:id) # get everything now that we have it
|
286
|
-
cached.count = records.size
|
287
|
-
cached.klass = records.empty? ? object_base_class : records.first.class
|
288
|
-
else
|
289
|
-
cached = records # some base type, cache it as itself
|
290
|
-
end
|
291
|
-
|
292
|
-
Rails.cache.write(cache_key, cached, opts_for_cache)
|
293
|
-
self.cached = cached
|
294
|
-
cached.respond_to?(:count) ? cached.count : cached
|
295
|
-
end
|
296
|
-
|
297
|
-
OPTIONS_FOR_PAGINATE = [:page, :per_page, :total_entries, :finder]
|
298
|
-
|
299
|
-
# Filter options for paginate, if *klass* is set, we get the :per_page value from it.
|
300
|
-
def opts_for_paginate
|
301
|
-
paginate_opts = combined_options.reject { |k,v| !OPTIONS_FOR_PAGINATE.include?(k) }
|
302
|
-
paginate_opts[:finder] = :find_all_by_id unless paginate_opts.include?(:finder)
|
303
|
-
paginate_opts[:per_page] = klass.per_page if klass && !paginate_opts.include?(:per_page)
|
304
|
-
paginate_opts
|
305
|
-
end
|
306
|
-
|
307
|
-
OPTIONS_FOR_FIND = [ :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly, :group, :having, :from, :lock ]
|
308
|
-
|
309
|
-
# Preserve the original order of the results if no :order option is specified.
|
310
|
-
#
|
311
|
-
# @arg ids array of ids to order by unless an :order option is specified. If not
|
312
|
-
# specified, cached.ids is used.
|
313
|
-
def opts_for_find(ids=nil)
|
314
|
-
ids ||= cached.ids
|
315
|
-
find_opts = combined_options.reject { |k,v| !OPTIONS_FOR_FIND.include?(k) }
|
316
|
-
find_opts[:order] = preserve_order(ids) unless find_opts.include?(:order)
|
317
|
-
find_opts
|
318
|
-
end
|
319
|
-
|
320
|
-
OPTIONS_FOR_CACHE = [ :expires_in ]
|
321
|
-
|
322
|
-
def opts_for_cache
|
323
|
-
combined_options.reject { |k,v| !OPTIONS_FOR_CACHE.include?(k) }
|
324
|
-
end
|
325
|
-
|
326
|
-
OPTIONS_FOR_CACHE_KEY = [ :auto_expire ]
|
327
|
-
|
328
|
-
def opts_for_cache_key
|
329
|
-
combined_options.reject { |k,v| !OPTIONS_FOR_CACHE_KEY.include?(k) }
|
330
|
-
end
|
331
|
-
|
332
|
-
OPTIONS_FOR_CACHE_PROXY = [:raw, :clear]
|
333
|
-
|
334
|
-
# Returns options that affect the cache proxy result
|
335
|
-
def opts_for_cache_proxy
|
336
|
-
combined_options.reject { |k,v| !OPTIONS_FOR_CACHE_PROXY.include?(k) }
|
337
|
-
end
|
338
|
-
|
339
|
-
def object_base_class #:nodoc:
|
340
|
-
object.is_a?(Class) ? object : object.class
|
341
|
-
end
|
342
|
-
|
343
|
-
# Generate an ORDER BY clause that preserves the ordering of the ids in *ids*.
|
344
|
-
#
|
345
|
-
# The method we use depends on the database adapter because only MySQL
|
346
|
-
# supports the ORDER BY FIELD() function. For other databases we use
|
347
|
-
# a CASE statement.
|
348
|
-
#
|
349
|
-
# TODO: is it quicker to sort in memory?
|
350
|
-
def preserve_order(ids)
|
351
|
-
column = if self.klass.respond_to?(:table_name)
|
352
|
-
::ActiveRecord::Base.connection.quote_table_name(self.klass.table_name) + '.id'
|
353
|
-
else
|
354
|
-
"id"
|
355
|
-
end
|
356
|
-
|
357
|
-
if ids.empty?
|
358
|
-
nil
|
359
|
-
elsif ::ActiveRecord::Base.is_mysql_adapter?
|
360
|
-
"FIELD(#{column},#{ids.join(',')})"
|
361
|
-
else
|
362
|
-
order = ''
|
363
|
-
ids.each_index { |i| order << "WHEN #{column}=#{ids[i]} THEN #{i+1} " }
|
364
|
-
"CASE " + order + " END"
|
365
|
-
end
|
123
|
+
def write_cache(data)
|
124
|
+
Rails.cache.write(@cache_key, data, @options.opts_for_cache)
|
366
125
|
end
|
367
126
|
end
|
368
127
|
end
|
data/lib/arid_cache.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe AridCache::CacheProxy::
|
3
|
+
describe AridCache::CacheProxy::CachedResult do
|
4
4
|
before :each do
|
5
5
|
class X; end
|
6
|
-
@result = AridCache::CacheProxy::
|
6
|
+
@result = AridCache::CacheProxy::CachedResult.new
|
7
7
|
end
|
8
8
|
|
9
9
|
it "should set the klass from a class" do
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AridCache::CacheProxy::Options do
|
4
|
+
def new_options(opts={})
|
5
|
+
AridCache::CacheProxy::Options.new(opts)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "defaults" do
|
9
|
+
before :each do
|
10
|
+
@opt = new_options
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have default" do
|
14
|
+
@opt.force?.should be_false
|
15
|
+
@opt.paginate?.should be_false
|
16
|
+
@opt.raw?.should be_false
|
17
|
+
@opt.count_only?.should be_false
|
18
|
+
@opt.order_by_proc?.should be_false
|
19
|
+
@opt.order_by_key?.should be_false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "force?" do
|
24
|
+
new_options(:force => true).force?.should be_true
|
25
|
+
end
|
26
|
+
|
27
|
+
it "paginate?" do
|
28
|
+
new_options(:page => 1).paginate?.should be_true
|
29
|
+
new_options(:per_page => 1).paginate?.should be_false
|
30
|
+
new_options(:page => 1, :per_page => 1).paginate?.should be_true
|
31
|
+
end
|
32
|
+
|
33
|
+
it "raw?" do
|
34
|
+
new_options(:raw => true).raw?.should be_true
|
35
|
+
end
|
36
|
+
|
37
|
+
it "count_only?" do
|
38
|
+
new_options(:count_only => true).count_only?.should be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
it "order options" do
|
42
|
+
@opt = new_options(:order => 'key')
|
43
|
+
@opt.order_by_key?.should be_true
|
44
|
+
@opt.order_by_proc?.should be_false
|
45
|
+
@opt = new_options(:order => :symbol)
|
46
|
+
@opt.order_by_key?.should be_true
|
47
|
+
@opt.order_by_proc?.should be_false
|
48
|
+
@opt = new_options(:order => Proc.new {})
|
49
|
+
@opt.order_by_key?.should be_false
|
50
|
+
@opt.order_by_proc?.should be_true
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "options for paginate" do
|
54
|
+
before :each do
|
55
|
+
@result_klass = Class.new do
|
56
|
+
def self.per_page; 23; end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should get per_page from the result_klass" do
|
61
|
+
@opts = new_options(:result_klass => @result_klass).opts_for_paginate
|
62
|
+
@opts[:per_page].should == 23
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should use the provided per_page value" do
|
66
|
+
@opts = new_options(:result_klass => @result_klass, :per_page => 3).opts_for_paginate
|
67
|
+
@opts[:per_page].should == 3
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should set total_entries" do
|
71
|
+
new_options.opts_for_paginate[:total_entries].should be_nil
|
72
|
+
@opts = new_options.opts_for_paginate((1..10).to_a)
|
73
|
+
@opts[:total_entries].should == 10
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should use find_all_by_id as the finder" do
|
77
|
+
new_options.opts_for_paginate[:finder].should == :find_all_by_id
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|