cache_method 0.0.1 → 0.0.2
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.
- data/.gitignore +2 -0
- data/README.rdoc +4 -4
- data/cache_method.gemspec +4 -9
- data/lib/cache_method/cached_result.rb +56 -0
- data/lib/cache_method/config.rb +11 -8
- data/lib/cache_method/epoch.rb +44 -0
- data/lib/cache_method/version.rb +1 -1
- data/lib/cache_method.rb +15 -7
- data/test/helper.rb +41 -35
- data/test/{test_cache_instance_methods.rb → test_cache_method.rb} +44 -38
- metadata +15 -91
- data/DEVELOPER_NOTES.rdoc +0 -45
- data/lib/cache_method/cache/epoch.rb +0 -45
- data/lib/cache_method/cache/key.rb +0 -56
- data/lib/cache_method/cache.rb +0 -65
- data/test/test_cache_class_methods.rb +0 -53
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -42,17 +42,17 @@ And clear them too
|
|
42
42
|
|
43
43
|
== Configuration (and supported cache clients)
|
44
44
|
|
45
|
-
You need to set
|
45
|
+
You need to set where the cache will be stored:
|
46
46
|
|
47
|
-
CacheMethod.config.
|
47
|
+
CacheMethod.config.storage = Memcached.new '127.0.0.1:11211'
|
48
48
|
|
49
49
|
or
|
50
50
|
|
51
|
-
CacheMethod.config.
|
51
|
+
CacheMethod.config.storage = Redis.new
|
52
52
|
|
53
53
|
or this might even work...
|
54
54
|
|
55
|
-
CacheMethod.config.
|
55
|
+
CacheMethod.config.storage = Rails.cache
|
56
56
|
|
57
57
|
See <tt>Config</tt> for the full list of supported caches.
|
58
58
|
|
data/cache_method.gemspec
CHANGED
@@ -8,9 +8,9 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ["Seamus Abshere"]
|
10
10
|
s.email = ["seamus@abshere.net"]
|
11
|
-
s.homepage = ""
|
12
|
-
s.summary = %q{
|
13
|
-
s.description = %q{
|
11
|
+
s.homepage = "https://github.com/seamusabshere/cache_method"
|
12
|
+
s.summary = %q{Lets you cache methods (to memcached, redis, etc.) sort of like you can memoize them}
|
13
|
+
s.description = %q{Like alias_method, but it's cache_method!}
|
14
14
|
|
15
15
|
s.rubyforge_project = "cache_method"
|
16
16
|
|
@@ -18,13 +18,8 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
-
s.
|
22
|
-
s.add_development_dependency 'activesupport', '>=2.3.4'
|
23
|
-
s.add_development_dependency 'i18n' # activesupport
|
24
|
-
s.add_development_dependency 'test-unit'
|
21
|
+
s.add_dependency 'cache'
|
25
22
|
s.add_development_dependency 'memcached'
|
26
|
-
s.add_development_dependency 'dalli'
|
27
|
-
s.add_development_dependency 'memcache-client'
|
28
23
|
# if RUBY_VERSION >= '1.9'
|
29
24
|
# s.add_development_dependency 'ruby-debug19'
|
30
25
|
# else
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
module CacheMethod
|
3
|
+
class CachedResult #:nodoc: all
|
4
|
+
class << self
|
5
|
+
def fetch(options = {})
|
6
|
+
cached_result = new options
|
7
|
+
cached_result.fetch
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
options.each do |k, v|
|
13
|
+
instance_variable_set "@#{k}", v
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :obj
|
18
|
+
attr_reader :method_id
|
19
|
+
attr_reader :original_method_id
|
20
|
+
attr_reader :args
|
21
|
+
|
22
|
+
def fetch
|
23
|
+
if v = Config.instance.storage.get(cache_key) and v.is_a?(::Array)
|
24
|
+
v[0]
|
25
|
+
else
|
26
|
+
v = obj.send original_method_id, *args
|
27
|
+
Config.instance.storage.set cache_key, [v], ttl
|
28
|
+
v
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def ttl
|
33
|
+
@ttl ||= Config.instance.default_ttl
|
34
|
+
end
|
35
|
+
|
36
|
+
def cache_key
|
37
|
+
[ method_signature, current_epoch, obj_hash, args_digest ].join ','
|
38
|
+
end
|
39
|
+
|
40
|
+
def method_signature
|
41
|
+
@method_signature ||= ::CacheMethod.method_signature(obj, method_id)
|
42
|
+
end
|
43
|
+
|
44
|
+
def obj_hash
|
45
|
+
@obj_hash ||= obj.hash
|
46
|
+
end
|
47
|
+
|
48
|
+
def args_digest
|
49
|
+
@args_digest ||= ::Digest::MD5.hexdigest(args.flatten.join)
|
50
|
+
end
|
51
|
+
|
52
|
+
def current_epoch
|
53
|
+
@current_epoch ||= Epoch.current(:obj => obj, :method_id => method_id)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/cache_method/config.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
|
+
require 'cache'
|
1
2
|
require 'singleton'
|
2
3
|
module CacheMethod
|
3
4
|
# Here's where you set config options.
|
4
5
|
#
|
5
6
|
# Example:
|
6
|
-
# CacheMethod.config.
|
7
|
+
# CacheMethod.config.storage = Memcached.new '127.0.0.1:11211'
|
7
8
|
# CacheMethod.config.default_ttl = 120 # seconds
|
8
9
|
#
|
9
10
|
# You'd probably put this in your Rails config/initializers, for example.
|
10
11
|
class Config
|
11
12
|
include ::Singleton
|
12
13
|
|
13
|
-
#
|
14
|
+
# Storage for the cache.
|
14
15
|
#
|
15
16
|
# Supported memcached clients:
|
16
17
|
# * memcached[https://github.com/fauna/memcached] (either a Memcached or a Memcached::Rails)
|
@@ -18,16 +19,18 @@ module CacheMethod
|
|
18
19
|
# * memcache-client[https://github.com/mperham/memcache-client] (MemCache, the one commonly used by Rails)
|
19
20
|
#
|
20
21
|
# Supported Redis clients:
|
21
|
-
# * redis[https://github.com/ezmobius/redis-rb]
|
22
|
+
# * redis[https://github.com/ezmobius/redis-rb]
|
23
|
+
#
|
24
|
+
# Uses the cache[https://github.com/seamusabshere/cache] gem to wrap these, so support depends on that gem
|
22
25
|
#
|
23
26
|
# Example:
|
24
|
-
# CacheMethod.config.
|
25
|
-
def
|
26
|
-
@
|
27
|
+
# CacheMethod.config.storage = Memcached.new '127.0.0.1:11211'
|
28
|
+
def storage=(raw_client)
|
29
|
+
@storage = ::Cache.new raw_client
|
27
30
|
end
|
28
31
|
|
29
|
-
def
|
30
|
-
@
|
32
|
+
def storage #:nodoc:
|
33
|
+
@storage || raise("You need to set CacheMethod.config.storage with a cache storage of your choice")
|
31
34
|
end
|
32
35
|
|
33
36
|
# TTL for method caches. Defaults to 60 seconds.
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module CacheMethod
|
2
|
+
class Epoch #:nodoc: all
|
3
|
+
class << self
|
4
|
+
def current(options = {})
|
5
|
+
epoch = new options
|
6
|
+
epoch.current
|
7
|
+
end
|
8
|
+
|
9
|
+
def mark_passing(options = {})
|
10
|
+
epoch = new options
|
11
|
+
epoch.mark_passing
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(options = {})
|
16
|
+
options.each do |k, v|
|
17
|
+
instance_variable_set "@#{k}", v
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :obj
|
22
|
+
attr_reader :method_id
|
23
|
+
|
24
|
+
def method_signature
|
25
|
+
@method_signature ||= ::CacheMethod.method_signature(obj, method_id)
|
26
|
+
end
|
27
|
+
|
28
|
+
def obj_hash
|
29
|
+
@obj_hash ||= obj.hash
|
30
|
+
end
|
31
|
+
|
32
|
+
def cache_key
|
33
|
+
[ 'CacheMethod', method_signature, obj_hash ].join ','
|
34
|
+
end
|
35
|
+
|
36
|
+
def current
|
37
|
+
Config.instance.storage.get(cache_key).to_i
|
38
|
+
end
|
39
|
+
|
40
|
+
def mark_passing
|
41
|
+
Config.instance.storage.set cache_key, (current+1), 0
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/cache_method/version.rb
CHANGED
data/lib/cache_method.rb
CHANGED
@@ -1,14 +1,24 @@
|
|
1
|
+
require 'cache_method/version'
|
1
2
|
# See the README.rdoc for more info!
|
2
3
|
module CacheMethod
|
3
4
|
autoload :Config, 'cache_method/config'
|
4
|
-
autoload :
|
5
|
+
autoload :CachedResult, 'cache_method/cached_result'
|
6
|
+
autoload :Epoch, 'cache_method/epoch'
|
5
7
|
|
6
8
|
def self.config #:nodoc:
|
7
9
|
Config.instance
|
8
10
|
end
|
9
11
|
|
10
|
-
def self.
|
11
|
-
|
12
|
+
def self.klass_name(obj) #:nodoc:
|
13
|
+
obj.is_a?(::Class) ? obj.to_s : obj.class.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.method_delimiter(obj) #:nodoc:
|
17
|
+
obj.is_a?(::Class) ? '.' : '#'
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.method_signature(obj, method_id) #:nodoc:
|
21
|
+
[ klass_name(obj), method_id ].join method_delimiter(obj)
|
12
22
|
end
|
13
23
|
|
14
24
|
# All Objects, including instances and Classes, get the <tt>#clear_method_cache</tt> method.
|
@@ -20,7 +30,7 @@ module CacheMethod
|
|
20
30
|
# Example:
|
21
31
|
# my_blog.clear_method_cache :get_latest_entries
|
22
32
|
def clear_method_cache(method_id)
|
23
|
-
::CacheMethod.
|
33
|
+
::CacheMethod::Epoch.mark_passing :obj => self, :method_id => method_id
|
24
34
|
end
|
25
35
|
end
|
26
36
|
|
@@ -47,9 +57,7 @@ module CacheMethod
|
|
47
57
|
original_method_id = "_uncached_#{method_id}"
|
48
58
|
alias_method original_method_id, method_id
|
49
59
|
define_method method_id do |*args|
|
50
|
-
::CacheMethod.
|
51
|
-
send original_method_id, *args
|
52
|
-
end
|
60
|
+
::CacheMethod::CachedResult.fetch :obj => self, :method_id => method_id, :original_method_id => original_method_id, :args => args, :ttl => ttl
|
53
61
|
end
|
54
62
|
end
|
55
63
|
end
|
data/test/helper.rb
CHANGED
@@ -8,44 +8,50 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
8
8
|
require 'cache_method'
|
9
9
|
|
10
10
|
class Test::Unit::TestCase
|
11
|
-
def setup
|
12
|
-
CacheMethod.cache.flush
|
13
|
-
end
|
14
11
|
end
|
15
12
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
13
|
+
class Blog1
|
14
|
+
attr_reader :name
|
15
|
+
attr_reader :url
|
16
|
+
def initialize(name, url)
|
17
|
+
@name = name
|
18
|
+
@url = url
|
19
|
+
end
|
20
|
+
attr_writer :request_count
|
21
|
+
def request_count
|
22
|
+
@request_count ||= 0
|
23
|
+
end
|
24
|
+
def get_latest_entries
|
25
|
+
self.request_count += 1
|
26
|
+
["hello from #{name}"]
|
27
|
+
end
|
28
|
+
cache_method :get_latest_entries
|
29
|
+
def get_latest_entries2
|
30
|
+
self.request_count += 1
|
31
|
+
["voo vaa #{name}"]
|
27
32
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
Memcached.new 'localhost:11211'
|
32
|
-
when 1
|
33
|
-
$stderr.puts 'using memcache-client'
|
34
|
-
MemCache.new ['localhost:11211']
|
35
|
-
when 2
|
36
|
-
$stderr.puts 'using dalli'
|
37
|
-
Dalli::Client.new ['localhost:11211']
|
38
|
-
when 3
|
39
|
-
$stderr.puts 'using dalli_store'
|
40
|
-
ActiveSupport::Cache::DalliStore.new ['localhost:11211']
|
41
|
-
when 4
|
42
|
-
$stderr.puts 'using memcached-rails'
|
43
|
-
Memcached::Rails.new 'localhost:11211'
|
44
|
-
when 5
|
45
|
-
$stderr.puts 'using Redis'
|
46
|
-
Redis.new
|
33
|
+
cache_method :get_latest_entries2, 1 # second
|
34
|
+
def hash
|
35
|
+
{ :name => name, :url => url }.hash
|
47
36
|
end
|
48
37
|
end
|
38
|
+
def new_instance_of_my_blog
|
39
|
+
Blog1.new 'my_blog', 'http://my_blog.example.com'
|
40
|
+
end
|
41
|
+
def new_instance_of_another_blog
|
42
|
+
Blog1.new 'another_blog', 'http://another_blog.example.com'
|
43
|
+
end
|
49
44
|
|
50
|
-
|
51
|
-
|
45
|
+
class Blog2
|
46
|
+
class << self
|
47
|
+
attr_writer :request_count
|
48
|
+
def request_count
|
49
|
+
@request_count ||= 0
|
50
|
+
end
|
51
|
+
def get_latest_entries
|
52
|
+
self.request_count += 1
|
53
|
+
'danke schoen'
|
54
|
+
end
|
55
|
+
cache_method :get_latest_entries
|
56
|
+
end
|
57
|
+
end
|
@@ -1,40 +1,16 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
-
|
4
|
-
attr_reader :name
|
5
|
-
attr_reader :url
|
6
|
-
def initialize(name, url)
|
7
|
-
@name = name
|
8
|
-
@url = url
|
9
|
-
end
|
10
|
-
attr_writer :request_count
|
11
|
-
def request_count
|
12
|
-
@request_count ||= 0
|
13
|
-
end
|
14
|
-
def get_latest_entries
|
15
|
-
self.request_count += 1
|
16
|
-
["hello from #{name}"]
|
17
|
-
end
|
18
|
-
cache_method :get_latest_entries
|
19
|
-
def get_latest_entries2
|
20
|
-
self.request_count += 1
|
21
|
-
["voo vaa #{name}"]
|
22
|
-
end
|
23
|
-
cache_method :get_latest_entries2, 1 # second
|
24
|
-
def hash
|
25
|
-
{ :name => name, :url => url }.hash
|
26
|
-
end
|
27
|
-
end
|
3
|
+
require 'memcached'
|
28
4
|
|
29
|
-
class
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
5
|
+
class TestCacheMethod < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
Blog2.request_count = 0
|
8
|
+
my_cache = Memcached.new '127.0.0.1:11211'
|
9
|
+
CacheMethod.config.storage = my_cache
|
10
|
+
my_cache.flush
|
35
11
|
end
|
36
12
|
|
37
|
-
def
|
13
|
+
def test_cache_instance_method
|
38
14
|
a = new_instance_of_my_blog
|
39
15
|
assert_equal ["hello from #{a.name}"], a.get_latest_entries
|
40
16
|
assert_equal 1, a.request_count
|
@@ -46,7 +22,7 @@ class TestCacheInstanceMethods < Test::Unit::TestCase
|
|
46
22
|
assert_equal 1, xxx.request_count
|
47
23
|
end
|
48
24
|
|
49
|
-
def
|
25
|
+
def test_clear_instance_method
|
50
26
|
a = new_instance_of_my_blog
|
51
27
|
assert_equal ["hello from #{a.name}"], a.get_latest_entries
|
52
28
|
assert_equal 1, a.request_count
|
@@ -55,7 +31,7 @@ class TestCacheInstanceMethods < Test::Unit::TestCase
|
|
55
31
|
assert_equal 2, a.request_count
|
56
32
|
end
|
57
33
|
|
58
|
-
def
|
34
|
+
def test_clear_correct_instance_method
|
59
35
|
a = new_instance_of_my_blog
|
60
36
|
assert_equal ["hello from #{a.name}"], a.get_latest_entries
|
61
37
|
assert_equal 1, a.request_count
|
@@ -64,7 +40,7 @@ class TestCacheInstanceMethods < Test::Unit::TestCase
|
|
64
40
|
assert_equal 1, a.request_count
|
65
41
|
end
|
66
42
|
|
67
|
-
def
|
43
|
+
def test_clear_instance_method_from_correct_instance
|
68
44
|
a = new_instance_of_my_blog
|
69
45
|
assert_equal ["hello from #{a.name}"], a.get_latest_entries
|
70
46
|
assert_equal 1, a.request_count
|
@@ -78,13 +54,43 @@ class TestCacheInstanceMethods < Test::Unit::TestCase
|
|
78
54
|
assert_equal 2, xxx.request_count
|
79
55
|
end
|
80
56
|
|
81
|
-
def
|
57
|
+
def test_cache_instance_method_ttl
|
82
58
|
a = new_instance_of_my_blog
|
83
59
|
assert_equal ["voo vaa #{a.name}"], a.get_latest_entries2
|
84
60
|
assert_equal 1, a.request_count
|
85
|
-
a = new_instance_of_my_blog
|
86
61
|
sleep 2
|
87
62
|
assert_equal ["voo vaa #{a.name}"], a.get_latest_entries2
|
88
|
-
assert_equal
|
63
|
+
assert_equal 2, a.request_count
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_cache_class_method
|
67
|
+
assert_equal 0, Blog2.request_count
|
68
|
+
assert_equal 'danke schoen', Blog2.get_latest_entries
|
69
|
+
assert_equal 1, Blog2.request_count
|
70
|
+
assert_equal 'danke schoen', Blog2.get_latest_entries
|
71
|
+
assert_equal 1, Blog2.request_count
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_clear_class_method
|
75
|
+
assert_equal 0, Blog2.request_count
|
76
|
+
assert_equal 'danke schoen', Blog2.get_latest_entries
|
77
|
+
assert_equal 1, Blog2.request_count
|
78
|
+
Blog2.clear_method_cache :get_latest_entries
|
79
|
+
assert_equal 'danke schoen', Blog2.get_latest_entries
|
80
|
+
assert_equal 2, Blog2.request_count
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_clear_correct_class_method
|
84
|
+
assert_equal 0, Blog2.request_count
|
85
|
+
assert_equal 'danke schoen', Blog2.get_latest_entries
|
86
|
+
assert_equal 1, Blog2.request_count
|
87
|
+
|
88
|
+
Blog2.clear_method_cache :foobar
|
89
|
+
assert_equal 'danke schoen', Blog2.get_latest_entries
|
90
|
+
assert_equal 1, Blog2.request_count
|
91
|
+
|
92
|
+
Blog2.clear_method_cache :get_latest_entries
|
93
|
+
assert_equal 'danke schoen', Blog2.get_latest_entries
|
94
|
+
assert_equal 2, Blog2.request_count
|
89
95
|
end
|
90
96
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cache_method
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Seamus Abshere
|
@@ -15,11 +15,11 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-02-
|
18
|
+
date: 2011-02-17 00:00:00 -06:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
name:
|
22
|
+
name: cache
|
23
23
|
prerelease: false
|
24
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
@@ -30,84 +30,12 @@ dependencies:
|
|
30
30
|
segments:
|
31
31
|
- 0
|
32
32
|
version: "0"
|
33
|
-
type: :
|
33
|
+
type: :runtime
|
34
34
|
version_requirements: *id001
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: activesupport
|
37
|
-
prerelease: false
|
38
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
-
none: false
|
40
|
-
requirements:
|
41
|
-
- - ">="
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
hash: 11
|
44
|
-
segments:
|
45
|
-
- 2
|
46
|
-
- 3
|
47
|
-
- 4
|
48
|
-
version: 2.3.4
|
49
|
-
type: :development
|
50
|
-
version_requirements: *id002
|
51
|
-
- !ruby/object:Gem::Dependency
|
52
|
-
name: i18n
|
53
|
-
prerelease: false
|
54
|
-
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
-
none: false
|
56
|
-
requirements:
|
57
|
-
- - ">="
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
hash: 3
|
60
|
-
segments:
|
61
|
-
- 0
|
62
|
-
version: "0"
|
63
|
-
type: :development
|
64
|
-
version_requirements: *id003
|
65
|
-
- !ruby/object:Gem::Dependency
|
66
|
-
name: test-unit
|
67
|
-
prerelease: false
|
68
|
-
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
-
none: false
|
70
|
-
requirements:
|
71
|
-
- - ">="
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
hash: 3
|
74
|
-
segments:
|
75
|
-
- 0
|
76
|
-
version: "0"
|
77
|
-
type: :development
|
78
|
-
version_requirements: *id004
|
79
35
|
- !ruby/object:Gem::Dependency
|
80
36
|
name: memcached
|
81
37
|
prerelease: false
|
82
|
-
requirement: &
|
83
|
-
none: false
|
84
|
-
requirements:
|
85
|
-
- - ">="
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
hash: 3
|
88
|
-
segments:
|
89
|
-
- 0
|
90
|
-
version: "0"
|
91
|
-
type: :development
|
92
|
-
version_requirements: *id005
|
93
|
-
- !ruby/object:Gem::Dependency
|
94
|
-
name: dalli
|
95
|
-
prerelease: false
|
96
|
-
requirement: &id006 !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
|
-
requirements:
|
99
|
-
- - ">="
|
100
|
-
- !ruby/object:Gem::Version
|
101
|
-
hash: 3
|
102
|
-
segments:
|
103
|
-
- 0
|
104
|
-
version: "0"
|
105
|
-
type: :development
|
106
|
-
version_requirements: *id006
|
107
|
-
- !ruby/object:Gem::Dependency
|
108
|
-
name: memcache-client
|
109
|
-
prerelease: false
|
110
|
-
requirement: &id007 !ruby/object:Gem::Requirement
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
111
39
|
none: false
|
112
40
|
requirements:
|
113
41
|
- - ">="
|
@@ -117,8 +45,8 @@ dependencies:
|
|
117
45
|
- 0
|
118
46
|
version: "0"
|
119
47
|
type: :development
|
120
|
-
version_requirements: *
|
121
|
-
description:
|
48
|
+
version_requirements: *id002
|
49
|
+
description: Like alias_method, but it's cache_method!
|
122
50
|
email:
|
123
51
|
- seamus@abshere.net
|
124
52
|
executables: []
|
@@ -129,22 +57,19 @@ extra_rdoc_files: []
|
|
129
57
|
|
130
58
|
files:
|
131
59
|
- .gitignore
|
132
|
-
- DEVELOPER_NOTES.rdoc
|
133
60
|
- Gemfile
|
134
61
|
- README.rdoc
|
135
62
|
- Rakefile
|
136
63
|
- cache_method.gemspec
|
137
64
|
- lib/cache_method.rb
|
138
|
-
- lib/cache_method/
|
139
|
-
- lib/cache_method/cache/epoch.rb
|
140
|
-
- lib/cache_method/cache/key.rb
|
65
|
+
- lib/cache_method/cached_result.rb
|
141
66
|
- lib/cache_method/config.rb
|
67
|
+
- lib/cache_method/epoch.rb
|
142
68
|
- lib/cache_method/version.rb
|
143
69
|
- test/helper.rb
|
144
|
-
- test/
|
145
|
-
- test/test_cache_instance_methods.rb
|
70
|
+
- test/test_cache_method.rb
|
146
71
|
has_rdoc: true
|
147
|
-
homepage:
|
72
|
+
homepage: https://github.com/seamusabshere/cache_method
|
148
73
|
licenses: []
|
149
74
|
|
150
75
|
post_install_message:
|
@@ -176,8 +101,7 @@ rubyforge_project: cache_method
|
|
176
101
|
rubygems_version: 1.3.7
|
177
102
|
signing_key:
|
178
103
|
specification_version: 3
|
179
|
-
summary:
|
104
|
+
summary: Lets you cache methods (to memcached, redis, etc.) sort of like you can memoize them
|
180
105
|
test_files:
|
181
106
|
- test/helper.rb
|
182
|
-
- test/
|
183
|
-
- test/test_cache_instance_methods.rb
|
107
|
+
- test/test_cache_method.rb
|
data/DEVELOPER_NOTES.rdoc
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
= Developer notes
|
2
|
-
|
3
|
-
== Lots of cache method signatures...
|
4
|
-
|
5
|
-
def get(k)
|
6
|
-
if defined?(::Memcached) and raw_client.is_a?(::Memcached)
|
7
|
-
# def get(keys, marshal=true)
|
8
|
-
begin; raw_client.get(k.to_s); rescue ::Memcached::NotFound; nil; end
|
9
|
-
elsif defined?(::Memcached::Rails) and raw_client.is_a?(::Memcached::Rails)
|
10
|
-
# def get(key, raw=false)
|
11
|
-
raw_client.get k.to_s
|
12
|
-
elsif defined?(::Dalli::Client) and raw_client.is_a?(::Dalli::Client)
|
13
|
-
# def get(key, options=nil)
|
14
|
-
raw_client.get k.to_s
|
15
|
-
elsif defined?(::MemCache) and raw_client.is_a?(::MemCache)
|
16
|
-
# def get(key, raw = false)
|
17
|
-
raw_client.get k.to_s
|
18
|
-
elsif defined?(::ActiveSupport::Cache::Store) and raw_client.is_a?(::ActiveSupport::Cache::Store)
|
19
|
-
# def read(name, options = nil)
|
20
|
-
raw_client.read k.to_s
|
21
|
-
else
|
22
|
-
raise "Unknown client: #{raw_client.inspect}"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def set(k, v)
|
27
|
-
if defined?(::Memcached) and raw_client.is_a?(::Memcached)
|
28
|
-
# def set(key, value, ttl=@default_ttl, marshal=true, flags=FLAGS)
|
29
|
-
raw_client.set k.to_s, v, ttl
|
30
|
-
elsif defined?(::Memcached::Rails) and raw_client.is_a?(::Memcached::Rails)
|
31
|
-
# def set(key, value, ttl=@default_ttl, raw=false)
|
32
|
-
raw_client.set k.to_s, v, ttl
|
33
|
-
elsif defined?(::Dalli::Client) and raw_client.is_a?(::Dalli::Client)
|
34
|
-
# def set(key, value, ttl=nil, options=nil)
|
35
|
-
raw_client.set k.to_s, v, ttl
|
36
|
-
elsif defined?(::MemCache) and raw_client.is_a?(::MemCache)
|
37
|
-
# def set(key, value, expiry = 0, raw = false)
|
38
|
-
raw_client.set k.to_s, v, ttl
|
39
|
-
elsif defined?(::ActiveSupport::Cache::Store) and raw_client.is_a?(::ActiveSupport::Cache::Store)
|
40
|
-
# def write(name, value, options = nil)
|
41
|
-
raw_client.write k.to_s, v, :expires_in => ttl
|
42
|
-
else
|
43
|
-
raise "Unknown client: #{raw_client.inspect}"
|
44
|
-
end
|
45
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
module CacheMethod
|
2
|
-
class Cache
|
3
|
-
class Epoch
|
4
|
-
class << self
|
5
|
-
def mark_passing(options = {})
|
6
|
-
e = new options
|
7
|
-
e.mark_passing
|
8
|
-
end
|
9
|
-
def current(options = {})
|
10
|
-
e = new options
|
11
|
-
e.current
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def initialize(options = {})
|
16
|
-
options.each do |k, v|
|
17
|
-
instance_variable_set "@#{k}", v
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
attr_reader :obj
|
22
|
-
attr_reader :method_id
|
23
|
-
|
24
|
-
def method_signature
|
25
|
-
@method_signature ||= Key.method_signature(obj, method_id)
|
26
|
-
end
|
27
|
-
|
28
|
-
def obj_hash
|
29
|
-
@obj_hash ||= obj.hash
|
30
|
-
end
|
31
|
-
|
32
|
-
def cache_key
|
33
|
-
[ 'CacheMethod', method_signature, obj_hash ].join ','
|
34
|
-
end
|
35
|
-
|
36
|
-
def current
|
37
|
-
Cache.instance.get(cache_key).to_i
|
38
|
-
end
|
39
|
-
|
40
|
-
def mark_passing
|
41
|
-
Cache.instance.set cache_key, (current+1), 0
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
require 'digest/md5'
|
2
|
-
module CacheMethod
|
3
|
-
class Cache
|
4
|
-
class Key
|
5
|
-
class << self
|
6
|
-
def digest(*ary)
|
7
|
-
::Digest::MD5.hexdigest ary.flatten.map { |i| i.to_s }.join
|
8
|
-
end
|
9
|
-
def parse(str)
|
10
|
-
method_signature, epoch, obj_hash, args_digest = str.split ','
|
11
|
-
new :method_signature => method_signature, :epoch => epoch, :obj_hash => obj_hash, :args_digest => args_digest
|
12
|
-
end
|
13
|
-
def klass_name(obj)
|
14
|
-
obj.is_a?(::Class) ? obj.to_s : obj.class.to_s
|
15
|
-
end
|
16
|
-
def method_delimiter(obj)
|
17
|
-
obj.is_a?(::Class) ? '.' : '#'
|
18
|
-
end
|
19
|
-
def method_signature(obj, method_id)
|
20
|
-
[ klass_name(obj), method_id ].join method_delimiter(obj)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def initialize(options = {})
|
25
|
-
options.each do |k, v|
|
26
|
-
instance_variable_set "@#{k}", v
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
attr_reader :obj
|
31
|
-
attr_reader :method_id
|
32
|
-
attr_reader :args
|
33
|
-
|
34
|
-
def obj_hash
|
35
|
-
@obj_hash ||= obj.hash
|
36
|
-
end
|
37
|
-
|
38
|
-
def args_digest
|
39
|
-
@args_digest ||= Key.digest(args)
|
40
|
-
end
|
41
|
-
|
42
|
-
def method_signature
|
43
|
-
@method_signature ||= Key.method_signature(obj, method_id)
|
44
|
-
end
|
45
|
-
|
46
|
-
def epoch
|
47
|
-
@epoch ||= Epoch.current(:obj => obj, :method_id => method_id)
|
48
|
-
end
|
49
|
-
|
50
|
-
def to_str
|
51
|
-
[ method_signature, epoch, obj_hash, args_digest ].join ','
|
52
|
-
end
|
53
|
-
alias :to_s :to_str
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
data/lib/cache_method/cache.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
require 'singleton'
|
2
|
-
module CacheMethod
|
3
|
-
# All cache requests go through a clearinghouse, allowing uncaching.
|
4
|
-
class Cache #:nodoc: all
|
5
|
-
autoload :Key, 'cache_method/cache/key'
|
6
|
-
autoload :Epoch, 'cache_method/cache/epoch'
|
7
|
-
|
8
|
-
include ::Singleton
|
9
|
-
|
10
|
-
def flush
|
11
|
-
bare_client.send %w{ flush flush_all clear flushdb }.detect { |c| bare_client.respond_to? c }
|
12
|
-
end
|
13
|
-
|
14
|
-
def fetch(obj, method_id, ttl, *args)
|
15
|
-
k = Key.new :obj => obj, :method_id => method_id, :args => args
|
16
|
-
if cached_v = get(k.to_s)
|
17
|
-
return cached_v
|
18
|
-
end
|
19
|
-
v = yield
|
20
|
-
set k.to_s, v, ttl
|
21
|
-
v
|
22
|
-
end
|
23
|
-
|
24
|
-
def delete(obj, method_id)
|
25
|
-
Epoch.mark_passing :obj => obj, :method_id => method_id
|
26
|
-
end
|
27
|
-
|
28
|
-
def get(k)
|
29
|
-
if defined?(::Memcached) and bare_client.is_a?(::Memcached)
|
30
|
-
begin; bare_client.get(k); rescue ::Memcached::NotFound; nil; end
|
31
|
-
elsif defined?(::Redis) and bare_client.is_a?(::Redis)
|
32
|
-
if cached_v = bare_client.get(k)
|
33
|
-
::Marshal.load cached_v
|
34
|
-
end
|
35
|
-
elsif bare_client.respond_to?(:get)
|
36
|
-
bare_client.get k
|
37
|
-
elsif bare_client.respond_to?(:read)
|
38
|
-
bare_client.read k
|
39
|
-
else
|
40
|
-
raise "Don't know how to work with #{bare_client.inspect}"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def set(k, v, ttl)
|
45
|
-
ttl ||= ::CacheMethod.config.default_ttl
|
46
|
-
if defined?(::Redis) and bare_client.is_a?(::Redis)
|
47
|
-
bare_client.set k, ::Marshal.dump(v)
|
48
|
-
elsif bare_client.respond_to?(:set)
|
49
|
-
bare_client.set k, v, ttl
|
50
|
-
elsif bare_client.respond_to?(:write)
|
51
|
-
if ttl == 0
|
52
|
-
bare_client.write k, v # never expire
|
53
|
-
else
|
54
|
-
bare_client.write k, v, :expires_in => ttl
|
55
|
-
end
|
56
|
-
else
|
57
|
-
raise "Don't know how to work with #{bare_client.inspect}"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def bare_client
|
62
|
-
::CacheMethod.config.client
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class Blog2
|
4
|
-
class << self
|
5
|
-
attr_writer :request_count
|
6
|
-
def request_count
|
7
|
-
@request_count ||= 0
|
8
|
-
end
|
9
|
-
def get_latest_entries
|
10
|
-
self.request_count += 1
|
11
|
-
'danke schoen'
|
12
|
-
end
|
13
|
-
cache_method :get_latest_entries
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
class TestCacheClassMethods < Test::Unit::TestCase
|
18
|
-
def setup
|
19
|
-
super
|
20
|
-
Blog2.request_count = 0
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_cache_method
|
24
|
-
assert_equal 0, Blog2.request_count
|
25
|
-
assert_equal 'danke schoen', Blog2.get_latest_entries
|
26
|
-
assert_equal 1, Blog2.request_count
|
27
|
-
assert_equal 'danke schoen', Blog2.get_latest_entries
|
28
|
-
assert_equal 1, Blog2.request_count
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_clear_method
|
32
|
-
assert_equal 0, Blog2.request_count
|
33
|
-
assert_equal 'danke schoen', Blog2.get_latest_entries
|
34
|
-
assert_equal 1, Blog2.request_count
|
35
|
-
Blog2.clear_method_cache :get_latest_entries
|
36
|
-
assert_equal 'danke schoen', Blog2.get_latest_entries
|
37
|
-
assert_equal 2, Blog2.request_count
|
38
|
-
end
|
39
|
-
|
40
|
-
def test_clear_method_doesnt_overstep
|
41
|
-
assert_equal 0, Blog2.request_count
|
42
|
-
assert_equal 'danke schoen', Blog2.get_latest_entries
|
43
|
-
assert_equal 1, Blog2.request_count
|
44
|
-
|
45
|
-
Blog2.clear_method_cache :foobar
|
46
|
-
assert_equal 'danke schoen', Blog2.get_latest_entries
|
47
|
-
assert_equal 1, Blog2.request_count
|
48
|
-
|
49
|
-
Blog2.clear_method_cache :get_latest_entries
|
50
|
-
assert_equal 'danke schoen', Blog2.get_latest_entries
|
51
|
-
assert_equal 2, Blog2.request_count
|
52
|
-
end
|
53
|
-
end
|