fat_cache 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. data/VERSION +1 -1
  2. data/lib/fat_cache.rb +56 -39
  3. data/spec/fat_cache_spec.rb +63 -50
  4. metadata +2 -2
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.5
1
+ 0.0.6
data/lib/fat_cache.rb CHANGED
@@ -4,29 +4,22 @@ class FatCache
4
4
 
5
5
  class << self
6
6
  @initted = false
7
- attr_accessor :fetchers, :fatcache, :indexed_fatcache
8
-
9
- def store(*key_and_maybe_data, &fetcher)
10
- init unless initted? # for first time store
11
-
12
- if key_and_maybe_data.length == 2 && fetcher.nil?
13
- key, data = key_and_maybe_data
14
- fatcache[key] = data
15
- elsif key_and_maybe_data.length == 1 && fetcher
16
- key = key_and_maybe_data.first
17
- fetchers[key] = fetcher
18
- fatcache[key] = fetcher.call
19
- else
20
- argstr = "#{key_and_maybe_data.length} arguments"
21
- blockstr = (block_given?) ? 'a block' : 'no block'
22
- raise "Got #{argstr} and #{blockstr}, expected (key, data) or (key) { fetcher block }"
23
- end
7
+ attr_accessor :fatcache, :indexed_fatcache
8
+ attr_accessor :fetchers, :index_fetchers
9
+
10
+ # Simply store value as key
11
+ def set(key, &fetcher)
12
+ init unless initted? # for first time set
13
+
14
+ fetchers[key] = fetcher
24
15
  end
25
16
 
17
+ # Gets from cache or pays fetch cost if necessary to get, raises if none
18
+ # available
26
19
  def get(key)
27
20
  unless cached?(key)
28
21
  if fetchable?(key)
29
- fatcache[key] = fetchers[key].call
22
+ fetch!(key)
30
23
  else
31
24
  raise "no data for #{key}"
32
25
  end
@@ -39,23 +32,17 @@ class FatCache
39
32
  by = [*options.delete(:by)]
40
33
  using = [*options.delete(:using)]
41
34
 
42
- # create index if it doesn't exist
43
- index(key, by) unless indexed?(key, by)
44
-
45
- return indexed_fatcache[key][by][using]
35
+ fetch_index!(key, by) unless indexed?(key, by)
36
+
37
+ indexed_fatcache[key][by][using]
46
38
  end
47
39
 
48
40
  def index(key, on, &block)
49
- # must have cache data to work with
50
- ensure_cached(key)
51
-
52
- # ensure we're dealing with an array, we're such a friendly API!
53
- on = [*on]
41
+ on = [*on] # ensure we're dealing with an array, we're such a friendly API!
54
42
 
55
- # init hash if we've never indexed for this key before
56
- indexed_fatcache[key] = {} unless indexed_fatcache.has_key?(key)
43
+ ensure_fetchable(key)
57
44
 
58
- raw_data = get(key)
45
+ index_fetchers[key] = {} unless index_fetchers.has_key?(key)
59
46
 
60
47
  if block
61
48
  # make the cache available to the passed block, and ensure that
@@ -65,14 +52,39 @@ class FatCache
65
52
 
66
53
  # pass each element of the raw data set into the block, which will
67
54
  # compute the key for us
68
- indexed_fatcache[key][on] = raw_data.group_by(&wrapped_block)
55
+ index_fetchers[key][on] = lambda { |data| data.group_by(&wrapped_block) }
69
56
  else
70
57
  # call each method specified in the `on` array once on each element in
71
58
  # the raw dataset, and use the results of those calls to key this index
72
- indexed_fatcache[key][on] = raw_data.group_by { |x| on.map { |b| x.send(b) } }
59
+ index_fetchers[key][on] = lambda { |data| data.group_by { |x| on.map { |b| x.send(b) } } }
73
60
  end
74
61
  end
75
62
 
63
+ def invalidate!(key)
64
+ return unless cached?(key)
65
+
66
+ indexed_fatcache.delete(key)
67
+ fatcache.delete(key)
68
+ end
69
+
70
+ def fetch!(key)
71
+ ensure_fetchable(key)
72
+ fatcache[key] = fetchers[key].call(self)
73
+ end
74
+
75
+ def fetch_index!(key, on)
76
+ on = [*on]
77
+
78
+ index(key, on) unless index_defined?(key, on)
79
+
80
+ # init hash if we've never indexed for this key before
81
+ indexed_fatcache[key] = {} unless indexed_fatcache.has_key?(key)
82
+
83
+ raw_data = get(key)
84
+
85
+ indexed_fatcache[key][on] = index_fetchers[key][on].call(raw_data)
86
+ end
87
+
76
88
  def get_index(key, on)
77
89
  on = [*on]
78
90
 
@@ -82,14 +94,17 @@ class FatCache
82
94
  end
83
95
 
84
96
  def ensure_cached(key)
85
- raise "no data for #{key}" unless cached?(key)
97
+ raise "no data in cache for #{key}" unless cached?(key)
86
98
  end
87
99
 
88
100
  def ensure_indexed(key, on)
89
- ensure_cached(key)
90
101
  raise "no index for #{key} on #{on.inspect}" unless indexed?(key, on)
91
102
  end
92
103
 
104
+ def ensure_fetchable(key)
105
+ raise "cannot fetch for #{key}" unless fetchable?(key)
106
+ end
107
+
93
108
  def cached?(key)
94
109
  fatcache && fatcache.has_key?(key)
95
110
  end
@@ -103,15 +118,16 @@ class FatCache
103
118
  def fetchable?(key)
104
119
  fetchers && fetchers.has_key?(key)
105
120
  end
106
-
107
- def invalidate(key)
108
- init unless initted?
109
-
110
- fatcache.delete(key)
121
+
122
+ def index_defined?(key, on)
123
+ index_fetchers &&
124
+ index_fetchers.has_key?(key) &&
125
+ index_fetchers[key].has_key?(on)
111
126
  end
112
127
 
113
128
  def reset!
114
129
  self.fetchers = nil
130
+ self.index_fetchers = nil
115
131
  self.fatcache = nil
116
132
  self.indexed_fatcache = nil
117
133
  @initted = nil
@@ -121,6 +137,7 @@ class FatCache
121
137
 
122
138
  def init
123
139
  self.fetchers = {}
140
+ self.index_fetchers = {}
124
141
  self.fatcache = {}
125
142
  self.indexed_fatcache = {}
126
143
  @initted = true
@@ -5,63 +5,71 @@ describe FatCache do
5
5
  after { FatCache.reset! }
6
6
 
7
7
  describe 'get(key)' do
8
- it 'raises an exception if no data is stored for this key' do
8
+ it 'raises an exception if no data is set for this key' do
9
9
  lambda {
10
10
  FatCache.get(:not_there)
11
11
  }.should raise_error(/not_there/)
12
12
  end
13
13
 
14
- describe 'when data has been invalidated for a key with a fetcher' do
15
- it 'uses a fetcher to get new data' do
16
- i = 0
17
- FatCache.store(:increment) { i += 1 }
18
- FatCache.invalidate(:increment)
19
- FatCache.get(:increment).should == 2
20
- end
14
+ it 'uses specified fetcher to get new data' do
15
+ needy = mock('needy')
16
+ needy.should_receive(:called).once
17
+ FatCache.set(:call_me) { needy.called }
18
+ FatCache.get(:call_me)
21
19
  end
22
- end
23
20
 
24
- describe 'store(key[, data])' do
25
- describe 'when called with key and data arguments' do
26
- it 'stores data for specified key' do
27
- FatCache.store(:five_alive, 5)
28
- FatCache.get(:five_alive).should == 5
29
- end
21
+ it 'calls the block only once, caching the data returned' do
22
+ i = 0
23
+ FatCache.set(:increment) { i += 1 }
30
24
 
31
- it 'properly stores nil for key if explicitly specified' do
32
- FatCache.store(:empty_inside, nil)
33
- FatCache.get(:empty_inside).should be_nil
34
- end
25
+ first_result = FatCache.get(:increment)
26
+ second_result = FatCache.get(:increment)
27
+
28
+ first_result.should == 1
29
+ second_result.should == 1
35
30
  end
31
+ end
36
32
 
37
- describe 'when called with key and fetcher block' do
38
- it 'uses block as fetcher to retrieve data to store' do
39
- FatCache.store(:fetched_from_block) { 'cheese sandwich' }
40
- FatCache.get(:fetched_from_block).should == 'cheese sandwich'
41
- end
33
+ describe 'set(key) { fetcher_block }' do
34
+ it 'does not evaluate fetcher_block' do
35
+ independent = mock('independent')
36
+ independent.should_not_receive(:called)
37
+ FatCache.set(:dont_need_you) { independent.called }
38
+ end
42
39
 
43
- it 'calls the block only once, caching the data returned' do
44
- i = 0
45
- FatCache.store(:increment) { i += 1 }
40
+ it 'makes data available on get' do
41
+ FatCache.set(:fetched_from_block) { 'cheese sandwich' }
42
+ FatCache.get(:fetched_from_block).should == 'cheese sandwich'
43
+ end
44
+ end
46
45
 
47
- first_result = FatCache.get(:increment)
48
- second_result = FatCache.get(:increment)
46
+ describe 'fetch!(key)' do
47
+ it 'activates evaluation of a fetcher block' do
48
+ needy = mock('needy')
49
+ needy.should_receive(:called)
50
+ FatCache.set(:call_me) { needy.called }
51
+ FatCache.fetch!(:call_me)
52
+ end
49
53
 
50
- first_result.should == 1
51
- second_result.should == 1
52
- end
54
+ it 'prevents evaluation fetcher block in future gets' do
55
+ fool_me_once = stub('fool_me_once')
56
+ fool_me_once.should_receive(:fooled!).once
57
+
58
+ FatCache.set(:dont_fool_me_twice) { fool_me_once.fooled! }
59
+ FatCache.fetch!(:dont_fool_me_twice)
60
+ FatCache.get(:dont_fool_me_twice)
53
61
  end
54
62
  end
55
63
 
56
64
  describe 'lookup(key, :by => [:method_names], :using => [:index_key])' do
57
- it 'returns a records stored in the dataset specified by key, indexed by the specified methods, and with the following key to the index' do
58
- FatCache.store(:a_set, [0,1,2,3,4,5])
65
+ it 'returns a records set in the dataset specified by key, indexed by the specified methods, and with the following key to the index' do
66
+ FatCache.set(:a_set) { [0,1,2,3,4,5] }
59
67
  result = FatCache.lookup(:a_set, :by => :odd?, :using => true)
60
68
  result.should == [1,3,5]
61
69
  end
62
70
 
63
71
  it 'works with multi-element index keys' do
64
- FatCache.store(:a_set, [0,1,2,3,4,5])
72
+ FatCache.set(:a_set) { [0,1,2,3,4,5] }
65
73
  result = FatCache.lookup(:a_set, :by => [:even?, :zero?], :using => [true, true])
66
74
  result.should == [0]
67
75
  end
@@ -69,13 +77,14 @@ describe FatCache do
69
77
 
70
78
  describe 'get_index(key, on)' do
71
79
  it 'returns the given index for a key' do
72
- FatCache.store(:numbers, [0,1,2,3,4])
80
+ FatCache.set(:numbers) { [0,1,2,3,4] }
73
81
  FatCache.index(:numbers, :odd?)
82
+ FatCache.fetch_index!(:numbers, :odd?)
74
83
  FatCache.get_index(:numbers, :odd?).should be_a Hash
75
84
  end
76
85
 
77
86
  it 'raises an error if no index exists for on specified key' do
78
- FatCache.store(:indexed_one_way, [123])
87
+ FatCache.set(:indexed_one_way) { [123] }
79
88
  FatCache.index(:indexed_one_way, :zero?)
80
89
  lambda {
81
90
  FatCache.get_index(:indexed_one_way, :odd?)
@@ -91,9 +100,10 @@ describe FatCache do
91
100
  end
92
101
 
93
102
  it 'raises an error if the elements of the dataset do not respond to the index key methods' do
94
- FatCache.store(:numbers, [1,2,3,4,5,6])
103
+ FatCache.set(:numbers) { [1,2,3,4,5,6] }
95
104
  lambda {
96
105
  FatCache.index(:numbers, :millionaire?)
106
+ FatCache.fetch_index!(:numbers, :millionaire?)
97
107
  }.should raise_error(/millionaire?/)
98
108
  end
99
109
 
@@ -104,11 +114,12 @@ describe FatCache do
104
114
  stub(:banana, :grams_of_awesome => 10),
105
115
  stub(:apple, :grams_of_awesome => 3)
106
116
  ]
107
- FatCache.store(:fruit, @fruit)
117
+ FatCache.set(:fruit) { @fruit }
108
118
  end
109
119
 
110
120
  it 'calls each method specified in `on` array and uses the results as the index key' do
111
121
  FatCache.index(:fruit, [:grams_of_awesome])
122
+ FatCache.fetch_index!(:fruit, [:grams_of_awesome])
112
123
  index = FatCache.get_index(:fruit, :grams_of_awesome)
113
124
  index.keys.should =~ [[3],[10]]
114
125
  end
@@ -134,33 +145,35 @@ describe FatCache do
134
145
  it 'passes each item into the block as the second argument' do
135
146
  FatCache.get(:fruit).each { |f| f.should_receive(:seen) }
136
147
  FatCache.index(:fruit, :grams_of_awesome) { |_, item| item.seen }
148
+ FatCache.fetch_index!(:fruit, :grams_of_awesome)
137
149
  end
138
150
  end
139
151
  end
140
152
 
141
153
  end
142
154
 
143
- describe 'invalidate(key)' do
155
+ describe 'invalidate!(key)' do
144
156
  describe 'when no fetcher has been specified for key' do
145
157
  it 'returns the last value the cache had for the key' do
146
- FatCache.store(:once_upon_a_time, 33)
147
- retval = FatCache.invalidate(:once_upon_a_time)
158
+ FatCache.set(:once_upon_a_time) { 33 }
159
+ FatCache.get(:once_upon_a_time)
160
+ retval = FatCache.invalidate!(:once_upon_a_time)
148
161
  retval.should == 33
149
162
  end
150
163
 
151
- it 'removes data stored for a given key' do
152
- FatCache.store(:there_and_gone, 100)
153
- FatCache.invalidate(:there_and_gone)
154
- lambda {
155
- FatCache.get(:there_and_gone)
156
- }.should raise_error(/there_and_gone/)
164
+ it 'causes data to be retreived from the fetcher again' do
165
+ i = 0
166
+ FatCache.set(:increment) { i += 1 }
167
+ FatCache.get(:increment).should == 1
168
+ FatCache.invalidate!(:increment)
169
+ FatCache.get(:increment).should == 2
157
170
  end
158
171
  end
159
172
 
160
173
  describe 'when a fetcher has been specified for a key' do
161
174
  it 'does not clear out the fetcher, which can be used in the next lookup' do
162
- FatCache.store(:fetch_me) { "I've been fetched" }
163
- FatCache.invalidate(:fetch_me)
175
+ FatCache.set(:fetch_me) { "I've been fetched" }
176
+ FatCache.invalidate!(:fetch_me)
164
177
  FatCache.get(:fetch_me).should == "I've been fetched"
165
178
  end
166
179
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fat_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - phinze
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-03-03 00:00:00 -06:00
12
+ date: 2010-03-05 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency