method_cache 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
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,5 @@
1
+ ---
2
+ :build:
3
+ :patch: 3
4
+ :major: 0
5
+ :minor: 6
@@ -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
@@ -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
@@ -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