ashleym1972-cache-money 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
File without changes
data/lib/cache_money.rb CHANGED
@@ -14,7 +14,7 @@ require 'cash/config'
14
14
  require 'cash/accessor'
15
15
 
16
16
  require 'cash/request'
17
- require 'cash/mock'
17
+ require 'cash/fake'
18
18
  require 'cash/local'
19
19
 
20
20
  require 'cash/query/abstract'
@@ -28,8 +28,8 @@ require 'cash/util/marshal'
28
28
  class ActiveRecord::Base
29
29
  def self.is_cached(options = {})
30
30
  options.assert_valid_keys(:ttl, :repository, :version)
31
- include Cash
32
- ::Cash::Config::Config.create(self, options)
31
+ include Cash unless ancestors.include?(Cash)
32
+ Cash::Config::Config.create(self, options)
33
33
  end
34
34
  end
35
35
 
data/lib/cash/accessor.rb CHANGED
@@ -11,8 +11,10 @@ module Cash
11
11
  def fetch(keys, options = {}, &block)
12
12
  case keys
13
13
  when Array
14
+ return {} if keys.empty?
15
+
14
16
  keys = keys.collect { |key| cache_key(key) }
15
- hits = repository.get_multi(keys)
17
+ hits = repository.get_multi(*keys)
16
18
  if (missed_keys = keys - hits.keys).any?
17
19
  missed_values = block.call(missed_keys)
18
20
  hits.merge!(missed_keys.zip(Array(missed_values)).to_hash_without_nils)
data/lib/cash/buffered.rb CHANGED
@@ -62,7 +62,7 @@ module Cash
62
62
  buffer_command Command.new(:delete, key, *options)
63
63
  end
64
64
 
65
- def get_multi(keys)
65
+ def get_multi(*keys)
66
66
  values = keys.collect { |key| get(key) }
67
67
  keys.zip(values).to_hash_without_nils
68
68
  end
data/lib/cash/config.rb CHANGED
@@ -1,5 +1,10 @@
1
1
  module Cash
2
2
  module Config
3
+ def self.create(active_record, options, indices = [])
4
+ active_record.cache_config = Config.new(active_record, options)
5
+ indices.each { |i| active_record.index i.attributes, i.options }
6
+ end
7
+
3
8
  def self.included(a_module)
4
9
  a_module.module_eval do
5
10
  extend ClassMethods
@@ -38,11 +43,6 @@ module Cash
38
43
  class Config
39
44
  attr_reader :active_record, :options
40
45
 
41
- def self.create(active_record, options, indices = [])
42
- active_record.cache_config = new(active_record, options)
43
- indices.each { |i| active_record.index i.attributes, i.options }
44
- end
45
-
46
46
  def initialize(active_record, options = {})
47
47
  @active_record, @options = active_record, options
48
48
  end
@@ -64,7 +64,7 @@ module Cash
64
64
  end
65
65
 
66
66
  def inherit(active_record)
67
- self.class.create(active_record, @options, indices)
67
+ Cash::Config.create(active_record, @options, indices)
68
68
  end
69
69
  end
70
70
  end
data/lib/cash/fake.rb ADDED
@@ -0,0 +1,83 @@
1
+ module Cash
2
+ class Fake < HashWithIndifferentAccess
3
+ attr_accessor :servers
4
+
5
+ def get_multi(*keys)
6
+ slice(*keys).collect { |k,v| [k, Marshal.load(v)] }.to_hash
7
+ end
8
+
9
+ def set(key, value, ttl = 0, raw = false)
10
+ self[key] = marshal(value, raw)
11
+ end
12
+
13
+ def get(key, raw = false)
14
+ if raw
15
+ self[key]
16
+ else
17
+ if self.has_key?(key)
18
+ Marshal.load(self[key])
19
+ else
20
+ nil
21
+ end
22
+ end
23
+ end
24
+
25
+ def incr(key, amount = 1)
26
+ if self.has_key?(key)
27
+ self[key] = (self[key].to_i + amount).to_s
28
+ self[key].to_i
29
+ end
30
+ end
31
+
32
+ def decr(key, amount = 1)
33
+ if self.has_key?(key)
34
+ self[key] = (self[key].to_i - amount).to_s
35
+ self[key].to_i
36
+ end
37
+ end
38
+
39
+ def add(key, value, ttl = 0, raw = false)
40
+ return false if self.has_key?(key)
41
+
42
+ self[key] = marshal(value, raw)
43
+ true
44
+ end
45
+
46
+ def append(key, value)
47
+ set(key, get(key, true).to_s + value.to_s, nil, true)
48
+ end
49
+
50
+ def namespace
51
+ nil
52
+ end
53
+
54
+ def flush_all
55
+ clear
56
+ end
57
+
58
+ def stats
59
+ {}
60
+ end
61
+
62
+ def reset_runtime
63
+ [0, Hash.new(0)]
64
+ end
65
+
66
+ private
67
+ def marshal(value, raw)
68
+ if raw
69
+ value.to_s
70
+ else
71
+ Marshal.dump(value)
72
+ end
73
+ end
74
+
75
+ def unmarshal(marshaled_obj)
76
+ Marshal.load(marshaled_obj)
77
+ end
78
+
79
+ def deep_clone(obj)
80
+ unmarshal(marshal(obj))
81
+ end
82
+ end
83
+ end
data/lib/cash/index.rb CHANGED
@@ -22,15 +22,13 @@ module Cash
22
22
 
23
23
  module Commands
24
24
  def add(object)
25
- clone = object.shallow_clone
26
25
  _, new_attribute_value_pairs = old_and_new_attribute_value_pairs(object)
27
- add_to_index_with_minimal_network_operations(new_attribute_value_pairs, clone)
26
+ add_to_index_with_minimal_network_operations(new_attribute_value_pairs, object)
28
27
  end
29
28
 
30
29
  def update(object)
31
- clone = object.shallow_clone
32
30
  old_attribute_value_pairs, new_attribute_value_pairs = old_and_new_attribute_value_pairs(object)
33
- update_index_with_minimal_network_operations(old_attribute_value_pairs, new_attribute_value_pairs, clone)
31
+ update_index_with_minimal_network_operations(old_attribute_value_pairs, new_attribute_value_pairs, object)
34
32
  end
35
33
 
36
34
  def remove(object)
@@ -70,7 +68,7 @@ module Cash
70
68
  include Attributes
71
69
 
72
70
  def serialize_object(object)
73
- primary_key? ? object : object.id
71
+ primary_key? ? object.shallow_clone : object.id
74
72
  end
75
73
 
76
74
  def matches?(query)
@@ -105,7 +103,7 @@ module Cash
105
103
  end
106
104
 
107
105
  def add_object_to_primary_key_cache(attribute_value_pairs, object)
108
- set(cache_key(attribute_value_pairs), [object], :ttl => ttl)
106
+ set(cache_key(attribute_value_pairs), [serialize_object(object)], :ttl => ttl)
109
107
  end
110
108
 
111
109
  def cache_key(attribute_value_pairs)
data/lib/cash/local.rb CHANGED
@@ -14,7 +14,20 @@ module Cash
14
14
  end
15
15
 
16
16
  def method_missing(method, *args, &block)
17
- @remote_cache.send(method, *args, &block)
17
+ autoload_missing_constants do
18
+ @remote_cache.send(method, *args, &block)
19
+ end
20
+ end
21
+
22
+ def autoload_missing_constants
23
+ yield if block_given?
24
+ rescue ArgumentError, MemCache::MemCacheError => error
25
+ lazy_load ||= Hash.new { |hash, hash_key| hash[hash_key] = true; false }
26
+ if error.to_s[/undefined class|referred/] && !lazy_load[error.to_s.split.last.constantize]
27
+ retry
28
+ else
29
+ raise error
30
+ end
18
31
  end
19
32
  end
20
33
 
data/lib/cash/lock.rb CHANGED
@@ -2,19 +2,19 @@ module Cash
2
2
  class Lock
3
3
  class Error < RuntimeError; end
4
4
 
5
+ INITIAL_WAIT = 1
5
6
  DEFAULT_RETRY = 5
6
7
  DEFAULT_EXPIRY = 30
7
8
 
8
9
  def initialize(cache)
9
10
  @cache = cache
10
- @runtime = Benchmark::Tms.new
11
11
  end
12
12
 
13
- def synchronize(key, lock_expiry = DEFAULT_EXPIRY, retries = DEFAULT_RETRY)
13
+ def synchronize(key, lock_expiry = DEFAULT_EXPIRY, retries = DEFAULT_RETRY, initial_wait = INITIAL_WAIT)
14
14
  if recursive_lock?(key)
15
15
  yield
16
16
  else
17
- acquire_lock(key, lock_expiry, retries)
17
+ acquire_lock(key, lock_expiry, retries, initial_wait)
18
18
  begin
19
19
  yield
20
20
  ensure
@@ -23,14 +23,12 @@ module Cash
23
23
  end
24
24
  end
25
25
 
26
- def acquire_lock(key, lock_expiry = DEFAULT_EXPIRY, retries = DEFAULT_RETRY)
26
+ def acquire_lock(key, lock_expiry = DEFAULT_EXPIRY, retries = DEFAULT_RETRY, initial_wait = INITIAL_WAIT)
27
27
  retries.times do |count|
28
- begin
29
- response = @cache.add("lock/#{key}", Process.pid, lock_expiry)
30
- return if response == "STORED\r\n"
31
- raise Error if count == retries - 1
32
- end
33
- exponential_sleep(count) unless count == retries - 1
28
+ response = @cache.add("lock/#{key}", Process.pid, lock_expiry)
29
+ return if response == "STORED\r\n"
30
+ raise Error if count == retries - 1
31
+ exponential_sleep(count, initial_wait) unless count == retries - 1
34
32
  end
35
33
  raise Error, "Couldn't acquire memcache lock for: #{key}"
36
34
  end
@@ -39,8 +37,8 @@ module Cash
39
37
  @cache.delete("lock/#{key}")
40
38
  end
41
39
 
42
- def exponential_sleep(count)
43
- @runtime += Benchmark::measure { sleep((2**count) / 2.0) }
40
+ def exponential_sleep(count, initial_wait)
41
+ sleep((2**count) / initial_wait)
44
42
  end
45
43
 
46
44
  private
@@ -33,7 +33,7 @@ module Cash
33
33
  def order
34
34
  @order ||= begin
35
35
  if order_sql = @options1[:order] || @options2[:order]
36
- matched, table_name, column_name, direction = *(ORDER.match(order_sql))
36
+ matched, table_name, column_name, direction = *(ORDER.match(order_sql.to_s))
37
37
  [column_name, direction =~ DESC ? :desc : :asc]
38
38
  else
39
39
  ['id', :asc]
data/rails/init.rb CHANGED
@@ -10,9 +10,9 @@ if memcache_config.nil? || memcache_config[:cache_money].nil?
10
10
  else
11
11
  require 'cache_money'
12
12
 
13
- ##$memcache = Rails.cache
14
13
  memcache_config[:logger] = Rails.logger
15
14
  $memcache = MemCache.new(memcache_config[:servers], memcache_config)
15
+ # $memcache = Memcached::Rails.new(memcache_config['servers'], memcache_config)
16
16
 
17
17
  ActionController::Base.cache_store = :cache_money_mem_cache_store
18
18
  ActionController::Base.session_options[:cache] = $memcache if memcache_options[:sessions]
@@ -19,6 +19,12 @@ module Cash
19
19
  end
20
20
 
21
21
  describe '#fetch([...])', :shared => true do
22
+ describe '#fetch([])' do
23
+ it 'returns the empty hash' do
24
+ Story.fetch([]).should == {}
25
+ end
26
+ end
27
+
22
28
  describe 'when there is a total cache miss' do
23
29
  it 'yields the keys to the block' do
24
30
  Story.fetch(["yabba", "dabba"]) { |*missing_ids| ["doo", "doo"] }.should == {
@@ -104,9 +110,18 @@ module Cash
104
110
 
105
111
  describe '#add' do
106
112
  describe 'when the value already exists' do
107
- it 'yields to the block' do
108
- Story.set("count", 1)
109
- Story.add("count", 1) { "yield me" }.should == "yield me"
113
+ describe 'when a block is given' do
114
+ it 'yields to the block' do
115
+ Story.set("count", 1)
116
+ Story.add("count", 1) { "yield me" }.should == "yield me"
117
+ end
118
+ end
119
+
120
+ describe 'when no block is given' do
121
+ it 'does not error' do
122
+ Story.set("count", 1)
123
+ lambda { Story.add("count", 1) }.should_not raise_error
124
+ end
110
125
  end
111
126
  end
112
127
 
@@ -109,27 +109,28 @@ module Cash
109
109
  end
110
110
  end
111
111
 
112
- describe '#find(:first, ..., :offset => ...)' do
113
- it "#finds the object in the correct order" do
114
- story1 = Story.create!(:title => 'title1')
115
- story2 = Story.create!(:title => story1.title)
116
- Story.find(:first, :conditions => { :title => story1.title }, :offset => 1).should == story2
112
+ describe '#find(:first, ...)' do
113
+ describe '#find(:first, ..., :offset => ...)' do
114
+ it "#finds the object in the correct order" do
115
+ story1 = Story.create!(:title => 'title1')
116
+ story2 = Story.create!(:title => story1.title)
117
+ Story.find(:first, :conditions => { :title => story1.title }, :offset => 1).should == story2
118
+ end
117
119
  end
118
- end
119
120
 
120
- describe '#find(:first, :conditions => [])' do
121
- it 'works' do
122
- story = Story.create!
123
- Story.find(:first, :conditions => []).should == story
121
+ describe '#find(:first, :conditions => [])' do
122
+ it 'finds the object in the correct order' do
123
+ story = Story.create!
124
+ Story.find(:first, :conditions => []).should == story
125
+ end
124
126
  end
125
- end
126
127
 
127
- describe "#find(:first, :conditions => '...')" do
128
- it "uses the active record instance to typecast values extracted from the conditions" do
129
- story1 = Story.create! :title => 'a story', :published => true
130
- story2 = Story.create! :title => 'another story', :published => false
131
- Story.get('published/false').should == [story2.id]
132
- Story.find(:first, :conditions => 'published = 0').should == story2
128
+ describe "#find(:first, :conditions => '...')" do
129
+ it "coerces ruby values to the appropriate database values" do
130
+ story1 = Story.create! :title => 'a story', :published => true
131
+ story2 = Story.create! :title => 'another story', :published => false
132
+ Story.find(:first, :conditions => 'published = 0').should == story2
133
+ end
133
134
  end
134
135
  end
135
136
  end
@@ -22,7 +22,7 @@ module Cash
22
22
  end
23
23
 
24
24
  describe '#find(:first, ...)' do
25
- describe '#find(:first, :conditions => { :id => ?})' do
25
+ describe '#find(:first, :conditions => { :id => ? })' do
26
26
  it "does not use the database" do
27
27
  story = Story.create!
28
28
  mock(Story.connection).execute.never
@@ -99,6 +99,15 @@ module Cash
99
99
  .should == story
100
100
  end
101
101
  end
102
+
103
+ describe 'when the attributes must be coerced to sql values' do
104
+ it 'does not use the database' do
105
+ story1 = Story.create!(:published => true)
106
+ story2 = Story.create!(:published => false)
107
+ mock(Story.connection).execute.never
108
+ Story.find(:first, :conditions => 'published = 0').should == story2
109
+ end
110
+ end
102
111
  end
103
112
 
104
113
  describe '#find(:first, :conditions => [...])' do
@@ -31,7 +31,7 @@ module Cash
31
31
  $memcache.get("lock/lock_key").should == nil
32
32
  end
33
33
 
34
- specify "does not block on recursive lock acquisition" do
34
+ it "does not block on recursive lock acquisition" do
35
35
  $lock.synchronize('lock_key') do
36
36
  lambda { $lock.synchronize('lock_key') {} }.should_not raise_error
37
37
  end
@@ -39,43 +39,64 @@ module Cash
39
39
  end
40
40
 
41
41
  describe '#acquire_lock' do
42
- specify "creates a lock at a given cache key" do
42
+ it "creates a lock at a given cache key" do
43
43
  $memcache.get("lock/lock_key").should == nil
44
44
  $lock.acquire_lock("lock_key")
45
45
  $memcache.get("lock/lock_key").should_not == nil
46
46
  end
47
47
 
48
- specify "retries specified number of times" do
49
- $lock.acquire_lock('lock_key')
50
- as_another_process do
51
- mock($memcache).add("lock/lock_key", Process.pid, timeout = 10) { "NOT_STORED\r\n" }.times(3)
52
- stub($lock).exponential_sleep
53
- lambda { $lock.acquire_lock('lock_key', timeout, 3) }.should raise_error
48
+ describe 'when given a timeout for the lock' do
49
+ it "correctly sets timeout on memcache entries" do
50
+ mock($memcache).add('lock/lock_key', Process.pid, timeout = 10) { true }
51
+ $lock.acquire_lock('lock_key', timeout)
54
52
  end
55
53
  end
56
54
 
57
- specify "correctly sets timeout on memcache entries" do
58
- mock($memcache).add('lock/lock_key', Process.pid, timeout = 10) { "STORED\r\n" }
59
- $lock.acquire_lock('lock_key', timeout)
60
- end
61
-
62
- specify "prevents two processes from acquiring the same lock at the same time" do
63
- $lock.acquire_lock('lock_key')
64
- as_another_process do
65
- lambda { $lock.acquire_lock('lock_key') }.should raise_error
55
+ describe 'when to processes contend for a lock' do
56
+ it "prevents two processes from acquiring the same lock at the same time" do
57
+ $lock.acquire_lock('lock_key')
58
+ as_another_process do
59
+ stub($lock).exponential_sleep
60
+ lambda { $lock.acquire_lock('lock_key') }.should raise_error
61
+ end
62
+ end
63
+
64
+ describe 'when given a number of times to retry' do
65
+ it "retries specified number of times" do
66
+ $lock.acquire_lock('lock_key')
67
+ as_another_process do
68
+ mock($memcache).add("lock/lock_key", Process.pid, timeout = 10) { false }.times(retries = 3)
69
+ stub($lock).exponential_sleep
70
+ lambda { $lock.acquire_lock('lock_key', timeout, retries) }.should raise_error
71
+ end
72
+ end
73
+ end
74
+
75
+ describe 'when given an initial wait' do
76
+ it 'sleeps exponentially starting with the initial wait' do
77
+ mock($lock).sleep(initial_wait = 0.123)
78
+ mock($lock).sleep(2 * initial_wait)
79
+ mock($lock).sleep(4 * initial_wait)
80
+ mock($lock).sleep(8 * initial_wait)
81
+ $lock.acquire_lock('lock_key')
82
+ as_another_process do
83
+ lambda { $lock.acquire_lock('lock_key', Lock::DEFAULT_EXPIRY, Lock::DEFAULT_RETRY, initial_wait) }.should raise_error
84
+ end
85
+ end
66
86
  end
67
- end
68
87
 
69
- def as_another_process
70
- current_pid = Process.pid
71
- stub(Process).pid { current_pid + 1 }
72
- yield
88
+ def as_another_process
89
+ current_pid = Process.pid
90
+ stub(Process).pid { current_pid + 1 }
91
+ yield
92
+ end
93
+
73
94
  end
74
95
 
75
96
  end
76
97
 
77
98
  describe '#release_lock' do
78
- specify "deletes the lock for a given cache key" do
99
+ it "deletes the lock for a given cache key" do
79
100
  $memcache.get("lock/lock_key").should == nil
80
101
  $lock.acquire_lock("lock_key")
81
102
  $memcache.get("lock/lock_key").should_not == nil
@@ -87,6 +87,12 @@ module Cash
87
87
  FairyTale.find(:all, :conditions => { :title => @title }, :order => '`stories`.id').should == @fairy_tales
88
88
  FairyTale.find(:all, :conditions => { :title => @title }, :order => '`stories`.`id`').should == @fairy_tales
89
89
  end
90
+
91
+ describe 'when the order is passed as a symbol' do
92
+ it 'works' do
93
+ FairyTale.find(:all, :conditions => { :title => @title }, :order => :id)
94
+ end
95
+ end
90
96
  end
91
97
 
92
98
  describe 'when the cache is not populated' do
@@ -73,14 +73,14 @@ module Cash
73
73
  it 'returns a hash' do
74
74
  @cache.set('key1', @value)
75
75
  @cache.set('key2', @value)
76
- @cache.get_multi(['key1', 'key2']).should == { 'key1' => @value, 'key2' => @value }
76
+ @cache.get_multi('key1', 'key2').should == { 'key1' => @value, 'key2' => @value }
77
77
  end
78
78
  end
79
79
 
80
80
  describe 'when there are misses' do
81
81
  it 'only returns results for hits' do
82
82
  @cache.set('key1', @value)
83
- @cache.get_multi(['key1', 'key2']).should == { 'key1' => @value }
83
+ @cache.get_multi('key1', 'key2').should == { 'key1' => @value }
84
84
  end
85
85
  end
86
86
  end
@@ -203,7 +203,7 @@ module Cash
203
203
  @cache.transaction do
204
204
  @cache.set('key1', @value)
205
205
  @cache.set('key2', [])
206
- @cache.get_multi(['key1', 'key2']).should == { 'key1' => @value, 'key2' => [] }
206
+ @cache.get_multi('key1', 'key2').should == { 'key1' => @value, 'key2' => [] }
207
207
  end
208
208
  end
209
209
  end
@@ -213,7 +213,7 @@ module Cash
213
213
  @cache.transaction do
214
214
  @cache.set('key1', @value)
215
215
  @cache.set('key2', @value)
216
- @cache.get_multi(['key1', 'key2']).should == { 'key1' => @value, 'key2' => @value }
216
+ @cache.get_multi('key1', 'key2').should == { 'key1' => @value, 'key2' => @value }
217
217
  end
218
218
  end
219
219
  end
@@ -222,7 +222,7 @@ module Cash
222
222
  it 'only returns results for hits' do
223
223
  @cache.transaction do
224
224
  @cache.set('key1', @value)
225
- @cache.get_multi(['key1', 'key2']).should == { 'key1' => @value }
225
+ @cache.get_multi('key1', 'key2').should == { 'key1' => @value }
226
226
  end
227
227
  end
228
228
  end
@@ -286,8 +286,8 @@ module Cash
286
286
  @cache.transaction do
287
287
  @cache.set('key1', @value)
288
288
  @cache.set('key2', @value)
289
- @cache.get_multi(['key1', 'key2']).should == { 'key1' => @value, 'key2' => @value }
290
- $memcache.get_multi(['key1', 'key2']).should == {}
289
+ @cache.get_multi('key1', 'key2').should == { 'key1' => @value, 'key2' => @value }
290
+ $memcache.get_multi('key1', 'key2').should == {}
291
291
  end
292
292
  end
293
293
 
data/spec/spec_helper.rb CHANGED
@@ -6,6 +6,7 @@ require 'spec'
6
6
  require 'pp'
7
7
  require 'cache_money'
8
8
  require 'memcache'
9
+ # require 'memcached'
9
10
  require File.join(dir, '../config/environment')
10
11
 
11
12
  Spec::Runner.configure do |config|
@@ -13,9 +14,9 @@ Spec::Runner.configure do |config|
13
14
  config.before :suite do
14
15
  load File.join(dir, "../db/schema.rb")
15
16
 
16
- config = YAML.load(IO.read((File.expand_path(File.dirname(__FILE__) + "/../config/memcache.yml"))))['test']
17
- $memcache = MemCache.new(config)
18
- $memcache.servers = config['servers']
17
+ config = YAML.load(IO.read((File.expand_path(File.dirname(__FILE__) + "/../config/memcached.yml"))))['test']
18
+ $memcache = MemCache.new(config['servers'], config)
19
+ # $memcache = Memcached::Rails.new(config['servers'], config)
19
20
  $lock = Cash::Lock.new($memcache)
20
21
  end
21
22
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ashleym1972-cache-money
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Kallen
@@ -61,7 +61,7 @@ files:
61
61
  - lib/cash/index.rb
62
62
  - lib/cash/local.rb
63
63
  - lib/cash/lock.rb
64
- - lib/cash/mock.rb
64
+ - lib/cash/fake.rb
65
65
  - lib/cash/query/abstract.rb
66
66
  - lib/cash/query/calculation.rb
67
67
  - lib/cash/query/primary_key.rb
@@ -103,7 +103,7 @@ specification_version: 2
103
103
  summary: Write-through and Read-through Cacheing for ActiveRecord
104
104
  test_files:
105
105
  - config/environment.rb
106
- - config/memcache.yml
106
+ - config/memcached.yml
107
107
  - db/schema.rb
108
108
  - spec/cash/accessor_spec.rb
109
109
  - spec/cash/active_record_spec.rb
data/lib/cash/mock.rb DELETED
@@ -1,154 +0,0 @@
1
- module Cash
2
- class Mock < HashWithIndifferentAccess
3
- attr_accessor :servers
4
-
5
- class CacheEntry
6
- attr_reader :value
7
-
8
- def self.default_ttl
9
- 1_000_000
10
- end
11
-
12
- def self.now
13
- Time.now
14
- end
15
-
16
- def initialize(value, raw, ttl)
17
- if raw
18
- @value = value.to_s
19
- else
20
- @value = Marshal.dump(value)
21
- end
22
-
23
- if ttl.zero?
24
- @ttl = self.class.default_ttl
25
- else
26
- @ttl = ttl
27
- end
28
-
29
- @expires_at = self.class.now + @ttl
30
- end
31
-
32
-
33
- def expired?
34
- self.class.now > @expires_at
35
- end
36
-
37
- def increment(amount = 1)
38
- @value = (@value.to_i + amount).to_s
39
- end
40
-
41
- def decrement(amount = 1)
42
- @value = (@value.to_i - amount).to_s
43
- end
44
-
45
- def unmarshal
46
- Marshal.load(@value)
47
- end
48
-
49
- def to_i
50
- @value.to_i
51
- end
52
- end
53
-
54
- attr_accessor :logging
55
-
56
- def initialize
57
- @logging = false
58
- end
59
-
60
- def get_multi(keys)
61
- slice(*keys).collect { |k,v| [k, v.unmarshal] }.to_hash_without_nils
62
- end
63
-
64
- def set(key, value, ttl = CacheEntry.default_ttl, raw = false)
65
- log "< set #{key} #{ttl}"
66
- self[key] = CacheEntry.new(value, raw, ttl)
67
- log('> STORED')
68
- end
69
-
70
- def get(key, raw = false)
71
- log "< get #{key}"
72
- unless self.has_unexpired_key?(key)
73
- log('> END')
74
- return nil
75
- end
76
-
77
- log("> sending key #{key}")
78
- log('> END')
79
- if raw
80
- self[key].value
81
- else
82
- self[key].unmarshal
83
- end
84
- end
85
-
86
- def delete(key, options = {})
87
- log "< delete #{key}"
88
- if self.has_unexpired_key?(key)
89
- log "> DELETED"
90
- super(key)
91
- else
92
- log "> NOT FOUND"
93
- end
94
- end
95
-
96
- def incr(key, amount = 1)
97
- if self.has_unexpired_key?(key)
98
- self[key].increment(amount)
99
- self[key].to_i
100
- end
101
- end
102
-
103
- def decr(key, amount = 1)
104
- if self.has_unexpired_key?(key)
105
- self[key].decrement(amount)
106
- self[key].to_i
107
- end
108
- end
109
-
110
- def add(key, value, ttl = CacheEntry.default_ttl, raw = false)
111
- if self.has_unexpired_key?(key)
112
- "NOT_STORED\r\n"
113
- else
114
- set(key, value, ttl, raw)
115
- "STORED\r\n"
116
- end
117
- end
118
-
119
- def append(key, value)
120
- set(key, get(key, true).to_s + value.to_s, nil, true)
121
- end
122
-
123
- def namespace
124
- nil
125
- end
126
-
127
- def flush_all
128
- log('< flush_all')
129
- clear
130
- end
131
-
132
- def stats
133
- {}
134
- end
135
-
136
- def reset_runtime
137
- [0, Hash.new(0)]
138
- end
139
-
140
- def has_unexpired_key?(key)
141
- self.has_key?(key) && !self[key].expired?
142
- end
143
-
144
- def log(message)
145
- return unless logging
146
- logger.debug(message)
147
- end
148
-
149
- def logger
150
- @logger ||= ActiveSupport::BufferedLogger.new(Rails.root.join('log/cash_mock.log'))
151
- end
152
-
153
- end
154
- end