method_cache 0.6.3
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/LICENSE +20 -0
- data/README.rdoc +42 -0
- data/Rakefile +45 -0
- data/VERSION.yml +5 -0
- data/lib/method_cache/proxy.rb +172 -0
- data/lib/method_cache.rb +177 -0
- data/method_cache.gemspec +53 -0
- data/test/method_cache_test.rb +131 -0
- data/test/test_helper.rb +13 -0
- metadata +74 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Justin Balthrop
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
= MethodCache
|
2
|
+
|
3
|
+
MethodCache lets you easily cache the results of any instance method or class method in
|
4
|
+
Ruby.
|
5
|
+
|
6
|
+
== Usage:
|
7
|
+
|
8
|
+
class Foo
|
9
|
+
extend MethodCache
|
10
|
+
|
11
|
+
cache_method :bar
|
12
|
+
def bar
|
13
|
+
# do expensive calculation
|
14
|
+
end
|
15
|
+
|
16
|
+
cache_class_method :baz, :clone => true, :expiry => 1.day
|
17
|
+
def self.baz
|
18
|
+
# do some expensive calculation that will be invalid tomorrow
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
foo = Foo.new
|
23
|
+
foo.bar # does calculation
|
24
|
+
foo.bar # cached
|
25
|
+
|
26
|
+
Foo.baz # does calculation
|
27
|
+
Foo.baz # cached
|
28
|
+
|
29
|
+
Foo.invalidate_cached_method(:baz)
|
30
|
+
|
31
|
+
Foo.baz # does calculation
|
32
|
+
Foo.baz # cached
|
33
|
+
|
34
|
+
== Install:
|
35
|
+
|
36
|
+
sudo gem install ninjudd-memcache -s http://gems.github.com
|
37
|
+
sudo gem install ninjudd-cache_version -s http://gems.github.com
|
38
|
+
sudo gem install ninjudd-method_cache -s http://gems.github.com
|
39
|
+
|
40
|
+
== License:
|
41
|
+
|
42
|
+
Copyright (c) 2009 Justin Balthrop, Geni.com; Published under The MIT License, see LICENSE
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'jeweler'
|
7
|
+
Jeweler::Tasks.new do |s|
|
8
|
+
s.name = "method_cache"
|
9
|
+
s.summary = %Q{Simple memcache-based memoization library for Ruby}
|
10
|
+
s.email = "code@justinbalthrop.com"
|
11
|
+
s.homepage = "http://github.com/ninjudd/method_cache"
|
12
|
+
s.description = "Simple memcache-based memoization library for Ruby"
|
13
|
+
s.authors = ["Justin Balthrop"]
|
14
|
+
s.add_dependency('memcache', '>= 1.0.0')
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
19
|
+
end
|
20
|
+
|
21
|
+
Rake::TestTask.new do |t|
|
22
|
+
t.libs << 'lib'
|
23
|
+
t.pattern = 'test/**/*_test.rb'
|
24
|
+
t.verbose = false
|
25
|
+
end
|
26
|
+
|
27
|
+
Rake::RDocTask.new do |rdoc|
|
28
|
+
rdoc.rdoc_dir = 'rdoc'
|
29
|
+
rdoc.title = 'method_cache'
|
30
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
31
|
+
rdoc.rdoc_files.include('README*')
|
32
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
33
|
+
end
|
34
|
+
|
35
|
+
begin
|
36
|
+
require 'rcov/rcovtask'
|
37
|
+
Rcov::RcovTask.new do |t|
|
38
|
+
t.libs << 'test'
|
39
|
+
t.test_files = FileList['test/**/*_test.rb']
|
40
|
+
t.verbose = true
|
41
|
+
end
|
42
|
+
rescue LoadError
|
43
|
+
end
|
44
|
+
|
45
|
+
task :default => :test
|
data/VERSION.yml
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
module MethodCache
|
2
|
+
class Proxy
|
3
|
+
attr_reader :method_name, :opts, :args, :target
|
4
|
+
|
5
|
+
def initialize(method_name, opts)
|
6
|
+
@method_name = method_name
|
7
|
+
@opts = opts
|
8
|
+
end
|
9
|
+
|
10
|
+
def bind(target, args)
|
11
|
+
self.clone.bind!(target, args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def bind!(target, args)
|
15
|
+
@target = target
|
16
|
+
@args = args
|
17
|
+
@key = nil
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def invalidate
|
22
|
+
if block_given?
|
23
|
+
# Only invalidate if the block returns true.
|
24
|
+
value = cache[key]
|
25
|
+
return if value and not yield(value)
|
26
|
+
end
|
27
|
+
cache.delete(key)
|
28
|
+
end
|
29
|
+
|
30
|
+
def context
|
31
|
+
opts[:context]
|
32
|
+
end
|
33
|
+
|
34
|
+
def version
|
35
|
+
dynamic_opt(:version)
|
36
|
+
end
|
37
|
+
|
38
|
+
def cached?
|
39
|
+
not cache[key].nil?
|
40
|
+
end
|
41
|
+
|
42
|
+
def update
|
43
|
+
value = block_given? ? yield(cache[key]) : target.send(method_name_without_caching, *args)
|
44
|
+
write_to_cache(key, value)
|
45
|
+
value
|
46
|
+
end
|
47
|
+
|
48
|
+
def value
|
49
|
+
value = cache[key] unless MethodCache.disabled?
|
50
|
+
value = nil unless valid?(:load, value)
|
51
|
+
|
52
|
+
if value.nil?
|
53
|
+
value = target.send(method_name_without_caching, *args)
|
54
|
+
write_to_cache(key, value) if valid?(:save, value)
|
55
|
+
end
|
56
|
+
|
57
|
+
value = nil if value == NULL
|
58
|
+
if clone? and value
|
59
|
+
value.clone
|
60
|
+
else
|
61
|
+
value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
NULL = 'NULL'
|
66
|
+
def method_with_caching
|
67
|
+
proxy = self # Need access to the proxy in the closure.
|
68
|
+
|
69
|
+
lambda do |*args|
|
70
|
+
proxy.bind(self, args).value
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def method_name_without_caching
|
75
|
+
@method_name_without_caching ||= begin
|
76
|
+
base_name, punctuation = method_name.to_s.sub(/([?!=])$/, ''), $1
|
77
|
+
"#{base_name}_without_caching#{punctuation}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def cache
|
82
|
+
if @cache.nil?
|
83
|
+
@cache = opts[:cache] || MethodCache.default_cache
|
84
|
+
@cache = Memcache.pool[@cache] if @cache.kind_of?(Symbol)
|
85
|
+
end
|
86
|
+
@cache
|
87
|
+
end
|
88
|
+
|
89
|
+
def local?
|
90
|
+
cache.kind_of?(Hash)
|
91
|
+
end
|
92
|
+
|
93
|
+
def clone?
|
94
|
+
!!opts[:clone]
|
95
|
+
end
|
96
|
+
|
97
|
+
def key
|
98
|
+
if @key.nil?
|
99
|
+
arg_string = ([method_name, target] + args).collect do |arg|
|
100
|
+
object_key(arg)
|
101
|
+
end.join('|')
|
102
|
+
@key = ['m', version, arg_string].compact.join('|')
|
103
|
+
end
|
104
|
+
@key
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def expiry(value)
|
110
|
+
dynamic_opt(:expiry, value).to_i
|
111
|
+
end
|
112
|
+
|
113
|
+
def valid?(type, value)
|
114
|
+
name = "#{type}_validation".to_sym
|
115
|
+
return true unless opts[name]
|
116
|
+
return unless value
|
117
|
+
|
118
|
+
dynamic_opt(name, value)
|
119
|
+
end
|
120
|
+
|
121
|
+
def dynamic_opt(name, value = nil)
|
122
|
+
if opts[name].kind_of?(Proc)
|
123
|
+
proc = opts[name].bind(target)
|
124
|
+
case proc.arity
|
125
|
+
when 0: proc.call()
|
126
|
+
when 1: proc.call(value)
|
127
|
+
else
|
128
|
+
proc.call(value, *args)
|
129
|
+
end
|
130
|
+
else
|
131
|
+
opts[name]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def write_to_cache(key, value)
|
136
|
+
if cache.kind_of?(Hash)
|
137
|
+
raise 'expiry not permitted when cache is a Hash' if opts[:expiry]
|
138
|
+
cache[key] = value
|
139
|
+
else
|
140
|
+
value = value.nil? ? NULL : value
|
141
|
+
cache.set(key, value, :expiry => expiry(value))
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def object_key(arg)
|
146
|
+
return "#{class_key(arg.class)}-#{arg.string_hash}" if arg.respond_to?(:string_hash)
|
147
|
+
|
148
|
+
case arg
|
149
|
+
when NilClass : 'nil'
|
150
|
+
when TrueClass : 'true'
|
151
|
+
when FalseClass : 'false'
|
152
|
+
when Numeric : arg.to_s
|
153
|
+
when Symbol : ":#{arg}"
|
154
|
+
when String : "'#{arg}'"
|
155
|
+
when Class, Module : class_key(arg)
|
156
|
+
when Hash
|
157
|
+
'{' + arg.collect {|key, value| "#{object_key(key)}=#{object_key(value)}"}.sort.join(',') + '}'
|
158
|
+
when Array
|
159
|
+
'[' + arg.collect {|item| object_key(item)}.join(',') + ']'
|
160
|
+
when defined?(ActiveRecord::Base) && ActiveRecord::Base
|
161
|
+
"#{class_key(arg.class)}-#{arg.id}"
|
162
|
+
else
|
163
|
+
hash = local? ? arg.hash : Marshal.dump(arg).hash
|
164
|
+
"#{class_key(arg.class)}-#{hash}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def class_key(klass)
|
169
|
+
klass.respond_to?(:version) ? "#{klass.name}_#{klass.version(context)}" : klass.name
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
data/lib/method_cache.rb
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'memcache'
|
2
|
+
|
3
|
+
$:.unshift(File.dirname(__FILE__))
|
4
|
+
require 'method_cache/proxy'
|
5
|
+
|
6
|
+
module MethodCache
|
7
|
+
def cache_method(method_name, opts = {})
|
8
|
+
method_name = method_name.to_sym
|
9
|
+
proxy = opts.kind_of?(Proxy) ? opts : Proxy.new(method_name, opts)
|
10
|
+
|
11
|
+
if self.class == Class
|
12
|
+
return if instance_methods.include?(proxy.method_name_without_caching)
|
13
|
+
|
14
|
+
if cached_instance_methods.empty?
|
15
|
+
include(InvalidationMethods)
|
16
|
+
extend(MethodAdded)
|
17
|
+
end
|
18
|
+
|
19
|
+
cached_instance_methods[method_name] = nil
|
20
|
+
begin
|
21
|
+
# Replace instance method.
|
22
|
+
alias_method proxy.method_name_without_caching, method_name
|
23
|
+
define_method method_name, proxy.method_with_caching
|
24
|
+
rescue NameError => e
|
25
|
+
# The method has not been defined yet. We will alias it in method_added.
|
26
|
+
# pp e, e.backtrace
|
27
|
+
end
|
28
|
+
cached_instance_methods[method_name] = proxy
|
29
|
+
|
30
|
+
elsif self.class == Module
|
31
|
+
# We will alias all methods when the module is mixed-in.
|
32
|
+
extend(ModuleAdded) if cached_module_methods.empty?
|
33
|
+
cached_module_methods[method_name.to_sym] = proxy
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def cache_class_method(method_name, opts = {})
|
38
|
+
method_name = method_name.to_sym
|
39
|
+
proxy = opts.kind_of?(Proxy) ? opts : Proxy.new(method_name, opts)
|
40
|
+
|
41
|
+
return if methods.include?(proxy.method_name_without_caching)
|
42
|
+
|
43
|
+
if cached_class_methods.empty?
|
44
|
+
extend(InvalidationMethods)
|
45
|
+
extend(SingletonMethodAdded)
|
46
|
+
end
|
47
|
+
|
48
|
+
method_name = method_name.to_sym
|
49
|
+
cached_class_methods[method_name] = nil
|
50
|
+
begin
|
51
|
+
# Replace class method.
|
52
|
+
(class << self; self; end).module_eval do
|
53
|
+
alias_method proxy.method_name_without_caching, method_name
|
54
|
+
define_method method_name, proxy.method_with_caching
|
55
|
+
end
|
56
|
+
rescue NameError => e
|
57
|
+
# The method has not been defined yet. We will alias it in singleton_method_added.
|
58
|
+
# pp e, e.backtrace
|
59
|
+
end
|
60
|
+
cached_class_methods[method_name] = proxy
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.default_cache
|
64
|
+
@default_cache ||= {}
|
65
|
+
end
|
66
|
+
|
67
|
+
def cached_instance_methods(method_name = nil)
|
68
|
+
if method_name
|
69
|
+
method_name = method_name.to_sym
|
70
|
+
ancestors.each do |klass|
|
71
|
+
next unless klass.kind_of?(MethodCache)
|
72
|
+
proxy = klass.cached_instance_methods[method_name]
|
73
|
+
return proxy if proxy
|
74
|
+
end
|
75
|
+
nil
|
76
|
+
else
|
77
|
+
@cached_instance_methods ||= {}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def cached_class_methods(method_name = nil)
|
82
|
+
if method_name
|
83
|
+
method_name = method_name.to_sym
|
84
|
+
ancestors.each do |klass|
|
85
|
+
next unless klass.kind_of?(MethodCache)
|
86
|
+
proxy = klass.cached_class_methods[method_name]
|
87
|
+
return proxy if proxy
|
88
|
+
end
|
89
|
+
nil
|
90
|
+
else
|
91
|
+
@cached_class_methods ||= {}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def cached_module_methods(method_name = nil)
|
96
|
+
if method_name
|
97
|
+
cached_module_methods[method_name.to_sym]
|
98
|
+
else
|
99
|
+
@cached_module_methods ||= {}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.disable(&block)
|
104
|
+
@disabled, old = true, @disabled
|
105
|
+
yield
|
106
|
+
ensure
|
107
|
+
@disabled = old
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.disabled?
|
111
|
+
@disabled
|
112
|
+
end
|
113
|
+
|
114
|
+
module InvalidationMethods
|
115
|
+
def invalidate_cached_method(method_name, *args, &block)
|
116
|
+
cached_method(method_name, args).invalidate(&block)
|
117
|
+
end
|
118
|
+
|
119
|
+
def method_value_cached?(method_name, *args)
|
120
|
+
cached_method(method_name, args).cached?
|
121
|
+
end
|
122
|
+
|
123
|
+
def update_cached_method(method_name, *args, &block)
|
124
|
+
cached_method(method_name, args).update(&block)
|
125
|
+
end
|
126
|
+
|
127
|
+
def without_method_cache(&block)
|
128
|
+
MethodCache.disable(&block)
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def cached_method(method_name, args)
|
134
|
+
if self.kind_of?(Class) or self.kind_of?(Module)
|
135
|
+
proxy = cached_class_methods(method_name)
|
136
|
+
else
|
137
|
+
proxy = self.class.send(:cached_instance_methods, method_name)
|
138
|
+
end
|
139
|
+
raise "method '#{method_name}' not cached" unless proxy
|
140
|
+
proxy.bind(self, args)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
module MethodAdded
|
145
|
+
def method_added(method_name)
|
146
|
+
if proxy = cached_instance_methods(method_name)
|
147
|
+
cache_method(method_name, proxy)
|
148
|
+
end
|
149
|
+
super
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
module SingletonMethodAdded
|
154
|
+
def singleton_method_added(method_name)
|
155
|
+
if proxy = cached_class_methods(method_name)
|
156
|
+
cache_class_method(method_name, proxy)
|
157
|
+
end
|
158
|
+
super
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
module ModuleAdded
|
163
|
+
def extended(mod)
|
164
|
+
mod.extend(MethodCache)
|
165
|
+
cached_module_methods.each do |method_name, proxy|
|
166
|
+
mod.cache_class_method(method_name, proxy)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def included(mod)
|
171
|
+
mod.extend(MethodCache)
|
172
|
+
cached_module_methods.each do |method_name, proxy|
|
173
|
+
mod.cache_method(method_name, proxy)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{method_cache}
|
8
|
+
s.version = "0.6.3"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Justin Balthrop"]
|
12
|
+
s.date = %q{2010-04-13}
|
13
|
+
s.description = %q{Simple memcache-based memoization library for Ruby}
|
14
|
+
s.email = %q{code@justinbalthrop.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"LICENSE",
|
21
|
+
"README.rdoc",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION.yml",
|
24
|
+
"lib/method_cache.rb",
|
25
|
+
"lib/method_cache/proxy.rb",
|
26
|
+
"method_cache.gemspec",
|
27
|
+
"test/method_cache_test.rb",
|
28
|
+
"test/test_helper.rb"
|
29
|
+
]
|
30
|
+
s.homepage = %q{http://github.com/ninjudd/method_cache}
|
31
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
32
|
+
s.require_paths = ["lib"]
|
33
|
+
s.rubygems_version = %q{1.3.5}
|
34
|
+
s.summary = %q{Simple memcache-based memoization library for Ruby}
|
35
|
+
s.test_files = [
|
36
|
+
"test/method_cache_test.rb",
|
37
|
+
"test/test_helper.rb"
|
38
|
+
]
|
39
|
+
|
40
|
+
if s.respond_to? :specification_version then
|
41
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
42
|
+
s.specification_version = 3
|
43
|
+
|
44
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
45
|
+
s.add_runtime_dependency(%q<memcache>, [">= 1.0.0"])
|
46
|
+
else
|
47
|
+
s.add_dependency(%q<memcache>, [">= 1.0.0"])
|
48
|
+
end
|
49
|
+
else
|
50
|
+
s.add_dependency(%q<memcache>, [">= 1.0.0"])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class Foo
|
4
|
+
extend MethodCache
|
5
|
+
|
6
|
+
def foo(i)
|
7
|
+
@i ||= 0
|
8
|
+
@i += i
|
9
|
+
end
|
10
|
+
cache_method :foo
|
11
|
+
|
12
|
+
cache_method :bar
|
13
|
+
def bar
|
14
|
+
@i ||= 0
|
15
|
+
@i += 1
|
16
|
+
end
|
17
|
+
|
18
|
+
@@i = 0
|
19
|
+
def baz(i)
|
20
|
+
@@i += i
|
21
|
+
end
|
22
|
+
cache_method :baz, :cache => :remote
|
23
|
+
end
|
24
|
+
|
25
|
+
module Bar
|
26
|
+
extend MethodCache
|
27
|
+
|
28
|
+
cache_method :foo
|
29
|
+
def foo(i)
|
30
|
+
@i ||= 0
|
31
|
+
@i += i
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Baz
|
36
|
+
include Bar
|
37
|
+
end
|
38
|
+
|
39
|
+
class TestMethodCache < Test::Unit::TestCase
|
40
|
+
should 'cache methods locally' do
|
41
|
+
a = Foo.new
|
42
|
+
f1 = a.foo(1)
|
43
|
+
f2 = a.foo(2)
|
44
|
+
|
45
|
+
assert_equal 1, f1
|
46
|
+
assert_equal 3, f2
|
47
|
+
|
48
|
+
assert f1 == a.foo(1)
|
49
|
+
assert f1 != f2
|
50
|
+
assert f2 == a.foo(2)
|
51
|
+
|
52
|
+
b = a.bar
|
53
|
+
assert b == a.bar
|
54
|
+
assert b == a.bar
|
55
|
+
end
|
56
|
+
|
57
|
+
should 'disable method_cache' do
|
58
|
+
a = Foo.new
|
59
|
+
f1 = a.foo(1)
|
60
|
+
|
61
|
+
f2 = a.without_method_cache do
|
62
|
+
a.foo(1)
|
63
|
+
end
|
64
|
+
|
65
|
+
f3 = MethodCache.disable do
|
66
|
+
a.foo(1)
|
67
|
+
end
|
68
|
+
|
69
|
+
assert f1 != f2
|
70
|
+
assert f1 != f3
|
71
|
+
assert f2 != f3
|
72
|
+
end
|
73
|
+
|
74
|
+
should 'cache methods remotely' do
|
75
|
+
a = Foo.new
|
76
|
+
b1 = a.baz(1)
|
77
|
+
b2 = a.baz(2)
|
78
|
+
|
79
|
+
assert_equal 1, b1
|
80
|
+
assert_equal 3, b2
|
81
|
+
|
82
|
+
assert b1 == a.baz(1)
|
83
|
+
assert b1 != b2
|
84
|
+
assert b2 == a.baz(2)
|
85
|
+
end
|
86
|
+
|
87
|
+
should 'cache methods for mixins' do
|
88
|
+
a = Baz.new
|
89
|
+
|
90
|
+
assert_equal 1, a.foo(1)
|
91
|
+
assert_equal 1, a.foo(1)
|
92
|
+
assert_equal 3, a.foo(2)
|
93
|
+
assert_equal 3, a.foo(2)
|
94
|
+
end
|
95
|
+
|
96
|
+
should 'invalidate cached method' do
|
97
|
+
a = Foo.new
|
98
|
+
|
99
|
+
assert_equal 1, a.foo(1)
|
100
|
+
assert_equal 3, a.foo(2)
|
101
|
+
|
102
|
+
a.invalidate_cached_method(:foo, 1)
|
103
|
+
|
104
|
+
assert_equal 4, a.foo(1)
|
105
|
+
assert_equal 3, a.foo(2)
|
106
|
+
end
|
107
|
+
|
108
|
+
should 'use consistent local keys' do
|
109
|
+
a = Foo.new
|
110
|
+
o = Object.new
|
111
|
+
a_hash = a.hash
|
112
|
+
o_hash = o.hash
|
113
|
+
|
114
|
+
5.times do
|
115
|
+
key = a.send(:cached_method, :bar, [{'a' => 3, 'b' => [5,6], 'c' => o}, [1,nil,{:o => o}]]).key
|
116
|
+
assert_equal "m|:bar|Foo-#{a_hash}|{'a'=3,'b'=[5,6],'c'=Object-#{o_hash}}|[1,nil,{:o=Object-#{o_hash}}]", key
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
should 'use consistent remote keys' do
|
121
|
+
a = Foo.new
|
122
|
+
o = Object.new
|
123
|
+
a_hash = Marshal.dump(a).hash
|
124
|
+
o_hash = Marshal.dump(o).hash
|
125
|
+
|
126
|
+
5.times do
|
127
|
+
key = a.send(:cached_method, :baz, [{:a => 3, :b => [5,6], :c => o}, [false,true,{:o => o}]]).key
|
128
|
+
assert_equal "m|:baz|Foo-#{a_hash}|{:a=3,:b=[5,6],:c=Object-#{o_hash}}|[false,true,{:o=Object-#{o_hash}}]", key
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
require 'mocha'
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
|
8
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + "/../../memcache/lib"
|
9
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + "/../../cache_version/lib"
|
10
|
+
require 'method_cache'
|
11
|
+
|
12
|
+
class Test::Unit::TestCase
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: method_cache
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Justin Balthrop
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-04-13 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: memcache
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.0.0
|
24
|
+
version:
|
25
|
+
description: Simple memcache-based memoization library for Ruby
|
26
|
+
email: code@justinbalthrop.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- LICENSE
|
33
|
+
- README.rdoc
|
34
|
+
files:
|
35
|
+
- LICENSE
|
36
|
+
- README.rdoc
|
37
|
+
- Rakefile
|
38
|
+
- VERSION.yml
|
39
|
+
- lib/method_cache.rb
|
40
|
+
- lib/method_cache/proxy.rb
|
41
|
+
- method_cache.gemspec
|
42
|
+
- test/method_cache_test.rb
|
43
|
+
- test/test_helper.rb
|
44
|
+
has_rdoc: true
|
45
|
+
homepage: http://github.com/ninjudd/method_cache
|
46
|
+
licenses: []
|
47
|
+
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options:
|
50
|
+
- --charset=UTF-8
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.3.5
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Simple memcache-based memoization library for Ruby
|
72
|
+
test_files:
|
73
|
+
- test/method_cache_test.rb
|
74
|
+
- test/test_helper.rb
|