arid_cache 1.3.0 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +81 -5
- data/VERSION +1 -1
- data/arid_cache.gemspec +2 -2
- data/lib/arid_cache/active_record.rb +3 -1
- data/lib/arid_cache/cache_proxy/options.rb +4 -0
- data/lib/arid_cache/cache_proxy/result_processor.rb +48 -21
- data/spec/arid_cache/cache_proxy/options_spec.rb +6 -0
- data/spec/arid_cache/cache_proxy/result_processor_spec.rb +151 -10
- metadata +4 -4
data/README.rdoc
CHANGED
@@ -8,6 +8,7 @@ AridCache simplifies caching by supporting auto-expiring cache keys - as well as
|
|
8
8
|
|
9
9
|
== Changes
|
10
10
|
|
11
|
+
v1.3.1: Support proxies which allow you to control how your objects get serialized and unserialized
|
11
12
|
v1.3.0: Support limits, ordering and pagination on cached Enumerables
|
12
13
|
v1.2.0: Fix Rails 3 ActiveRecord hooks & remove some Rails dependencies
|
13
14
|
v1.0.5: Support <tt>:raw</tt> and <tt>:clear</tt> options.
|
@@ -42,11 +43,12 @@ Then
|
|
42
43
|
* Supports limits, ordering & pagination of cached Enumerables and ActiveRecord collections
|
43
44
|
* Define caches and their options on your class using +instance_caches+ and +class_caches+
|
44
45
|
* Counts for free - if you have already cached the result, you get the count for free
|
45
|
-
*
|
46
|
-
|
46
|
+
* Smart counts - if you only ask for the count it will only calculate the count; useful when the result is an Association Reflection or a named scope.
|
47
|
+
* Supports eager-loading and other options to <tt>ActiveRecord::Base#find</tt> like <tt>:conditions</tt>, <tt>:include</tt>, <tt>:joins</tt>, <tt>:select</tt>, <tt>:readonly</tt>, <tt>:group</tt>, <tt>:having</tt>, <tt>:from</tt>
|
47
48
|
* Provides methods to clear caches individually, at the instance-level, class-level and globally
|
48
49
|
* Preserves the order of your cached ActiveRecord collections
|
49
50
|
* Optimized to make as few cache and database accesses as absolutely neccessary
|
51
|
+
* Define your own cache proxy to serialize your objects as they go to and from the cache
|
50
52
|
|
51
53
|
== Introduction
|
52
54
|
|
@@ -63,10 +65,25 @@ The way you interact with the cache via your model methods is to prepend the met
|
|
63
65
|
|
64
66
|
You can also define caches that use compositions of methods or named scopes, or other complex queries, without having to add a new method to your class. This way you can also create different caches that all use the same method. For example,
|
65
67
|
|
66
|
-
User
|
67
|
-
active
|
68
|
+
class User
|
69
|
+
named_scope :active, :conditions => { :active => true }
|
70
|
+
class_caches do
|
71
|
+
most_active_users(:limit => 5) do
|
72
|
+
active.find(:order => 'activity DESC')
|
73
|
+
end
|
74
|
+
end
|
68
75
|
end
|
69
76
|
|
77
|
+
This defines a cache +most_active_users+ on the User class which we can call with:
|
78
|
+
|
79
|
+
User.cached_most_active_users
|
80
|
+
>> [#<User>, #<User>]
|
81
|
+
|
82
|
+
This will return up to five users, but there may be many more in the cache, because we didn't apply a limit in our call to <tt>active.find()</tt>. We can also pass options to the call to override the stored options:
|
83
|
+
|
84
|
+
User.cached_most_active_users(:limit => 1)
|
85
|
+
>> [#<User>]
|
86
|
+
|
70
87
|
=== ActiveRecord Collections
|
71
88
|
|
72
89
|
If the result of your <tt>cached_</tt> call is an array of ActiveRecords, AridCache only stores the IDs in the cache (because it's a bad idea to store records in the cache).
|
@@ -358,6 +375,65 @@ In some circumstances - like when you are querying on a named scope - if you hav
|
|
358
375
|
:ids => [2, 235, 236, 237] # the ids array is seeded before returning
|
359
376
|
}
|
360
377
|
|
378
|
+
== Proxies
|
379
|
+
|
380
|
+
Proxies allow you to do anything you want to your objects as they go into - and come out of - the cache. They are most useful for serializing your objects, for example if you want to store JSON, or hashes.
|
381
|
+
|
382
|
+
The <tt>:proxy</tt> option should be a Symbol giving the name of a class method. The method is passed the result of your cache block (or method) as the first parameter, and in future may also pass a Hash of options. The method is called on the class that calls +cached_+.
|
383
|
+
|
384
|
+
A simple example of a proxy which stores hashes of ActiveRecord attributes:
|
385
|
+
|
386
|
+
class User
|
387
|
+
has_many :companies
|
388
|
+
|
389
|
+
instance_caches do
|
390
|
+
companies(:proxy => :serializing_proxy)
|
391
|
+
end
|
392
|
+
|
393
|
+
def self.serializing_proxy(records, *args)
|
394
|
+
return records if records.empty?
|
395
|
+
records.first.is_a?(ActiveRecord::Base) ? records.collect(&:attributes) : records.collect { |r| Company.find_by_id(r['id']) }
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
Now when we first call <tt>User.first.cached_companies<tt> the cache is empty, so the cache method (<tt>companies</tt>) is called and the result is passed to <tt>User.serializing_proxy</tt> which converts the records to Hashes. The result of the proxy is stored in the cache. The next time we call <tt>User.first.cached_companies<tt> the cached result is retrieved and passed to <tt>User.serializing_proxy</tt> which converts the hashes to records, so we get ActiveRecords back.
|
400
|
+
|
401
|
+
@user = User.first
|
402
|
+
@user.cached_companies
|
403
|
+
>> [#<Company id: 1>, #<Company id: 2>]
|
404
|
+
|
405
|
+
@user.cached_companies(:raw => true)
|
406
|
+
>> [{ 'id' => 1 }, { 'id' => 2 }]
|
407
|
+
|
408
|
+
The <tt>:raw</tt> option bypasses the proxy on the way out of the cache because we are asking for a raw result. The <tt>:raw</tt> option works a bit differently from the default behaviour (which is to return a <tt>CachedResult</tt> object if the cached result is an ActiveRecord collection) because you can use options to do limiting, pagination and in-memory ordering with <tt>:raw</tt> to get different views of your cached enumerable.
|
409
|
+
|
410
|
+
Proxies still support limits, pagination and ordering, which is applied to the cached result. For example:
|
411
|
+
|
412
|
+
Limits:
|
413
|
+
|
414
|
+
@user.cached_companies(:limit => 2, :offset => 1)
|
415
|
+
>> [#<Company id: 2>]
|
416
|
+
|
417
|
+
Pagination returns a <tt>WillPaginate::Collection</tt>:
|
418
|
+
|
419
|
+
result = @user.cached_companies(:page => 2, :per_page => 1)
|
420
|
+
>> [#<Company id: 2>]
|
421
|
+
result.total_entries
|
422
|
+
>> 1
|
423
|
+
result.current_page
|
424
|
+
>> 2
|
425
|
+
|
426
|
+
Order by:
|
427
|
+
|
428
|
+
@user.cached_companies(:order => Proc.new { |a, b| b['id'] <=> a['id'] })
|
429
|
+
>> [#<Company id: 2>, #<Company id: 1>]
|
430
|
+
|
431
|
+
The above Proc orders by id reversed. We can also combine all the options. The order by will be applied first, then the limits and finally the pagination.
|
432
|
+
|
433
|
+
All of the above calls work with <tt>raw => true</tt>. With that option the results would be same but instead of returning records, it returns hashes.
|
434
|
+
|
435
|
+
In practice you probably want to define your proxy method on <tt>ActiveRecord::Base</tt> so that it is available to all your models. In future AridCache will probably have some built-in proxies that you can make use of.
|
436
|
+
|
361
437
|
== Efficiency
|
362
438
|
|
363
439
|
* AridCache intercepts calls to <tt>cached_</tt> methods using <tt>method_missing</tt> then defines those methods on your models as they are called, so they bypass method missing on subsequent calls.
|
@@ -383,7 +459,7 @@ For Ruby < 1.8.7 you probably want to include the following to extend the Array
|
|
383
459
|
== Known Issues
|
384
460
|
|
385
461
|
1. <b>Caches that contains duplicate records will only return unique records on subsequent calls</b>. This is because of the way <tt>find</tt> works when selecting multiple ids. For example, if your query returns <tt>[#<User id: 1>, #<User id: 1>, #<User id: 1>]</tt>, the IDs are cached as <tt>[1,1,1]</tt>. On the next call to the cache we load the IDs using <tt>User.find_all_by_id([1,1,1])</tt> which returns <tt>[#<User id: 1>]</tt>, not <tt>[#<User id: 1>, #<User id: 1>, #<User id: 1>]</tt> as you might have expected.
|
386
|
-
2. <b>You can't cache polymorphic arrays</b> e.g. [#<User id: 1>, #<Pet id: 5>] because it expects all ActiveRecords to be of the same class.
|
462
|
+
2. <b>You can't cache polymorphic arrays</b> e.g. [#<User id: 1>, #<Pet id: 5>] because it expects all ActiveRecords to be of the same class. If you need polymorphism consider using a proxy.
|
387
463
|
|
388
464
|
== Contributors
|
389
465
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.3.
|
1
|
+
1.3.1
|
data/arid_cache.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{arid_cache}
|
8
|
-
s.version = "1.3.
|
8
|
+
s.version = "1.3.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Karl Varga"]
|
12
|
-
s.date = %q{2011-04-
|
12
|
+
s.date = %q{2011-04-06}
|
13
13
|
s.description = %q{AridCache makes caching easy and effective. AridCache supports caching on all your model named scopes, class methods and instance methods right out of the box. AridCache prevents caching logic from cluttering your models and clarifies your logic by making explicit calls to cached result sets.
|
14
14
|
AridCache is designed for handling large, expensive ActiveRecord collections but is equally useful for caching anything else as well.
|
15
15
|
}
|
@@ -36,7 +36,9 @@ module AridCache
|
|
36
36
|
elsif options[:auto_expire]
|
37
37
|
self.cache_key
|
38
38
|
else
|
39
|
-
"#{AridCache::Inflector.pluralize(self.class.name.downcase)}
|
39
|
+
result = "#{AridCache::Inflector.pluralize(self.class.name.downcase)}"
|
40
|
+
result += "/#{self[:id]}" if self.respond_to?(:[]) && !self[:id].nil?
|
41
|
+
result
|
40
42
|
end
|
41
43
|
'arid-cache-' + object_key + '-' + key.to_s
|
42
44
|
end
|
@@ -6,6 +6,11 @@ module AridCache
|
|
6
6
|
# Provides methods to introspect the result. The contents could be a base type,
|
7
7
|
# or an enumerable of sorts...any type really. We are only concerned with enumerables,
|
8
8
|
# and especially those containing active records.
|
9
|
+
#
|
10
|
+
# TODO: a lot of this logic should be encompassed in the CachedResult. It's probably
|
11
|
+
# a good idea to always cache a CachedResult and move the result-related methods
|
12
|
+
# into that class. We have to keep whatever is cached as small as possible tho,
|
13
|
+
# so it's probably best to cache a Hash and load it with CachedResult.
|
9
14
|
class ResultProcessor
|
10
15
|
|
11
16
|
def initialize(result, opts={})
|
@@ -54,23 +59,29 @@ module AridCache
|
|
54
59
|
# Check if it's an association first, because it doesn't trigger the select if it's
|
55
60
|
# a named scope. Calling respond_to? on an association proxy will trigger a select
|
56
61
|
# because it loads up the target and passes the respond_to? on to it.
|
57
|
-
@cached =
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
+
@cached =
|
63
|
+
if @options.proxy?
|
64
|
+
if is_activerecord_reflection?
|
65
|
+
@result = @result.collect { |r| r } # force it to load
|
66
|
+
end
|
67
|
+
Utilities.object_class(@options[:receiver]).send(@options[:proxy], @result)
|
68
|
+
elsif is_activerecord_reflection?
|
69
|
+
lazy_cache.klass = @result.proxy_reflection.klass if @result.respond_to?(:proxy_reflection)
|
70
|
+
if @options.count_only?
|
71
|
+
lazy_cache.count = @result.count
|
72
|
+
else
|
73
|
+
lazy_cache.ids = @result.collect { |r| r[:id] }
|
74
|
+
lazy_cache.count = @result.size
|
75
|
+
end
|
76
|
+
lazy_cache
|
77
|
+
elsif is_activerecord? || is_empty?
|
62
78
|
lazy_cache.ids = @result.collect { |r| r[:id] }
|
63
79
|
lazy_cache.count = @result.size
|
80
|
+
lazy_cache.klass = @result.first.class
|
81
|
+
lazy_cache
|
82
|
+
else
|
83
|
+
@result
|
64
84
|
end
|
65
|
-
lazy_cache
|
66
|
-
elsif is_activerecord? || is_empty?
|
67
|
-
lazy_cache.ids = @result.collect { |r| r[:id] }
|
68
|
-
lazy_cache.count = @result.size
|
69
|
-
lazy_cache.klass = @result.first.class
|
70
|
-
lazy_cache
|
71
|
-
else
|
72
|
-
@result
|
73
|
-
end
|
74
85
|
end
|
75
86
|
|
76
87
|
# Apply any options like pagination or ordering and return the result, which
|
@@ -78,16 +89,32 @@ module AridCache
|
|
78
89
|
def to_result
|
79
90
|
if @options.count_only?
|
80
91
|
get_count
|
81
|
-
elsif
|
92
|
+
elsif is_cached_result? && @options.raw?
|
82
93
|
@result
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
94
|
+
elsif @options.proxy?
|
95
|
+
results =
|
96
|
+
if @cached.nil? || !@options.raw?
|
97
|
+
@result
|
98
|
+
else
|
99
|
+
@cached
|
100
|
+
end
|
101
|
+
filtered = filter_results(results)
|
102
|
+
if @cached.nil? && !@options.raw?
|
103
|
+
proxy_result = Utilities.object_class(@options[:receiver]).send(@options[:proxy], filtered)
|
104
|
+
if filtered.is_a?(WillPaginate::Collection) && proxy_result.is_a?(Enumerable)
|
105
|
+
filtered.replace(proxy_result)
|
106
|
+
else
|
107
|
+
proxy_result
|
108
|
+
end
|
88
109
|
else
|
89
|
-
|
110
|
+
filtered
|
90
111
|
end
|
112
|
+
elsif is_cached_result?
|
113
|
+
fetch_activerecords(filter_results(@result.ids))
|
114
|
+
elsif order_in_database?
|
115
|
+
fetch_activerecords(filter_results(@result))
|
116
|
+
else
|
117
|
+
filter_results(@result)
|
91
118
|
end
|
92
119
|
end
|
93
120
|
|
@@ -76,5 +76,11 @@ describe AridCache::CacheProxy::Options do
|
|
76
76
|
it "should use find_all_by_id as the finder" do
|
77
77
|
new_options.opts_for_paginate[:finder].should == :find_all_by_id
|
78
78
|
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "proxies" do
|
82
|
+
it "should use proxy" do
|
83
|
+
new_options(:proxy => :serializing_proxy).proxy?.should be_true
|
84
|
+
end
|
79
85
|
end
|
80
86
|
end
|
@@ -179,8 +179,8 @@ describe AridCache::CacheProxy::ResultProcessor do
|
|
179
179
|
it "should order hashes by symbol key" do
|
180
180
|
new_result(@hashes, :order => :high).to_result.collect { |h| h[:high] }.should == @high
|
181
181
|
end
|
182
|
-
end
|
183
|
-
|
182
|
+
end
|
183
|
+
|
184
184
|
describe "paginating arrays" do
|
185
185
|
before :each do
|
186
186
|
@value = (1..10).to_a
|
@@ -191,27 +191,168 @@ describe AridCache::CacheProxy::ResultProcessor do
|
|
191
191
|
@result.should be_a(WillPaginate::Collection)
|
192
192
|
@result.total_entries.should == @value.size
|
193
193
|
@result.current_page.should == 1
|
194
|
-
end
|
195
|
-
|
194
|
+
end
|
195
|
+
|
196
196
|
it "should handle per_page option" do
|
197
197
|
@result = new_result(@value, :page => 3, :per_page => 3).to_result
|
198
198
|
@result.should be_a(WillPaginate::Collection)
|
199
199
|
@result.total_entries.should == @value.size
|
200
200
|
@result.current_page.should == 3
|
201
|
-
@result.per_page.should == 3
|
201
|
+
@result.per_page.should == 3
|
202
202
|
end
|
203
203
|
end
|
204
|
-
|
205
|
-
it "should order limit and then paginate all at once" do
|
204
|
+
|
205
|
+
it "should order limit and then paginate all at once" do
|
206
206
|
# It will reverse it, offset 2, limit 15, then paginate
|
207
207
|
@options = {
|
208
|
-
:limit => 15,
|
209
|
-
:offset => 2,
|
208
|
+
:limit => 15,
|
209
|
+
:offset => 2,
|
210
210
|
:order => Proc.new { |a, b| b <=> a },
|
211
|
-
:page => 2,
|
211
|
+
:page => 2,
|
212
212
|
:per_page => 5
|
213
213
|
}
|
214
214
|
@result = new_result((1..20).to_a, @options).to_result.should == [13, 12, 11, 10, 9]
|
215
215
|
end
|
216
216
|
end
|
217
|
+
|
218
|
+
describe "proxies" do
|
219
|
+
before :each do
|
220
|
+
class User
|
221
|
+
instance_caches do
|
222
|
+
companies(:proxy => :abc)
|
223
|
+
end
|
224
|
+
|
225
|
+
def self.abc(records)
|
226
|
+
return records if records.empty?
|
227
|
+
records.first.is_a?(ActiveRecord::Base) ? records.collect(&:attributes) : records.collect { |r| Company.find_by_id(r['id']) }
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
@user = User.make
|
232
|
+
@company = Company.make
|
233
|
+
@user.companies << @company
|
234
|
+
@user.cached_companies(:clear => true)
|
235
|
+
end
|
236
|
+
|
237
|
+
it "the proxy called on itself should return the original value" do
|
238
|
+
User.abc(User.abc([@company])).should == [@company]
|
239
|
+
end
|
240
|
+
|
241
|
+
it "should serialize" do
|
242
|
+
@user.cached_companies.should == [@company]
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should un-serialize" do
|
246
|
+
@user.cached_companies # seed the cache
|
247
|
+
@user.cached_companies.should == [@company]
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should return json with :raw => true" do
|
251
|
+
# Seed the cache; it should use the serialized result in the return value.
|
252
|
+
value = @user.cached_companies(:raw => true)
|
253
|
+
|
254
|
+
# Comparing the hashes directly doesn't work because the updated_at Time are
|
255
|
+
# not considered equal...don't know why, cause the to_s looks the same.
|
256
|
+
# debugger
|
257
|
+
value.should be_a(Array)
|
258
|
+
value.first.should be_a(Hash)
|
259
|
+
value.first.each_pair do |k, v|
|
260
|
+
v.to_s.should == @company.attributes[k].to_s
|
261
|
+
end
|
262
|
+
|
263
|
+
# Cache is seeded, it should use the cached result
|
264
|
+
User.expects(:abc).never
|
265
|
+
value = @user.cached_companies(:raw => true)
|
266
|
+
value.should be_a(Array)
|
267
|
+
value.first.should be_a(Hash)
|
268
|
+
value.first.each_pair do |k, v|
|
269
|
+
v.to_s.should == @company.attributes[k].to_s
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
describe "with options" do
|
274
|
+
before :each do
|
275
|
+
@c2 = Company.make
|
276
|
+
@c3 = Company.make
|
277
|
+
@user.companies << @c2
|
278
|
+
@user.companies << @c3
|
279
|
+
end
|
280
|
+
|
281
|
+
it "should apply limit and offset" do
|
282
|
+
@companies = @user.cached_companies
|
283
|
+
@user.cached_companies(:limit => 2, :offset => 1).should == @companies[1,2]
|
284
|
+
end
|
285
|
+
|
286
|
+
it "should apply limit and offset with :raw => true" do
|
287
|
+
@companies = @user.cached_companies
|
288
|
+
@user.cached_companies(:limit => 2, :offset => 1, :raw => true).should == User.abc(@companies[1,2])
|
289
|
+
end
|
290
|
+
|
291
|
+
it "should apply pagination" do
|
292
|
+
@companies = @user.cached_companies
|
293
|
+
value = @user.cached_companies(:page => 2, :per_page => 2)
|
294
|
+
value.should be_a(WillPaginate::Collection)
|
295
|
+
value.first.should be_a(Company)
|
296
|
+
value.first.should == @companies[-1]
|
297
|
+
value.total_entries.should == @companies.size
|
298
|
+
value.current_page.should == 2
|
299
|
+
value.size.should == 1
|
300
|
+
end
|
301
|
+
|
302
|
+
it "should get the count for free" do
|
303
|
+
lambda { @user.cached_companies_count }.should query(1)
|
304
|
+
lambda { @user.cached_companies_count }.should query(0)
|
305
|
+
end
|
306
|
+
|
307
|
+
it "should paginate with :raw => true" do
|
308
|
+
@companies = User.abc(@user.cached_companies)
|
309
|
+
value = @user.cached_companies(:page => 2, :per_page => 2, :raw => true)
|
310
|
+
value.should be_a(WillPaginate::Collection)
|
311
|
+
value.first.should be_a(Hash)
|
312
|
+
value.first.should == @companies[-1]
|
313
|
+
value.total_entries.should == @companies.size
|
314
|
+
value.current_page.should == 2
|
315
|
+
value.size.should == 1
|
316
|
+
end
|
317
|
+
|
318
|
+
it "should order by" do
|
319
|
+
@companies = @user.cached_companies
|
320
|
+
@user.cached_companies(:order => 'id').should == @companies
|
321
|
+
@user.cached_companies(:order => Proc.new { |a, b| b['id'] <=> a['id'] }).should == @companies.reverse
|
322
|
+
end
|
323
|
+
|
324
|
+
it "should order by with :raw => true" do
|
325
|
+
@companies = @user.cached_companies(:raw => true)
|
326
|
+
@companies.first.should be_a(Hash)
|
327
|
+
@user.cached_companies(:order => 'id', :raw => true).should == @companies
|
328
|
+
@user.cached_companies(:order => Proc.new { |a, b| b['id'] <=> a['id'] }, :raw => true).should == @companies.reverse
|
329
|
+
end
|
330
|
+
|
331
|
+
it "should apply all options at once" do
|
332
|
+
@companies = @user.cached_companies
|
333
|
+
value = @user.cached_companies(
|
334
|
+
:order => Proc.new { |a, b| b['id'] <=> a['id'] },
|
335
|
+
:limit => 2, :offset => 1,
|
336
|
+
:page => 1, :per_page => 2)
|
337
|
+
value.should be_a(WillPaginate::Collection)
|
338
|
+
value.current_page.should == 1
|
339
|
+
value.total_entries.should == 2
|
340
|
+
value.to_a.should == [@companies[1], @companies[0]]
|
341
|
+
end
|
342
|
+
|
343
|
+
it "should apply all options with :raw => true" do
|
344
|
+
@companies = @user.cached_companies(:raw => true)
|
345
|
+
value = @user.cached_companies(
|
346
|
+
:order => Proc.new { |a, b| b['id'] <=> a['id'] },
|
347
|
+
:limit => 2, :offset => 1,
|
348
|
+
:page => 1, :per_page => 2,
|
349
|
+
:raw => true)
|
350
|
+
value.should be_a(WillPaginate::Collection)
|
351
|
+
value.current_page.should == 1
|
352
|
+
value.total_entries.should == 2
|
353
|
+
value.first.should be_a(Hash)
|
354
|
+
value.to_a.should == [@companies[1], @companies[0]]
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
217
358
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arid_cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 1.3.
|
9
|
+
- 1
|
10
|
+
version: 1.3.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Karl Varga
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-04-
|
18
|
+
date: 2011-04-06 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|