jashmenn-method_cache 0.7.1.0

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 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.
@@ -0,0 +1,40 @@
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
+ gem install method_cache
37
+
38
+ == License:
39
+
40
+ Copyright (c) 2010 Justin Balthrop, Geni.com; Published under The MIT License, see LICENSE
@@ -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 = "jashmenn-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', 'test']
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
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 7
4
+ :patch: 1
5
+ :build: 0
@@ -0,0 +1,186 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+ require 'method_cache/proxy'
3
+
4
+ module MethodCache
5
+ def cache_method(method_name, opts = {})
6
+ method_name = method_name.to_sym
7
+ proxy = opts.kind_of?(Proxy) ? opts : Proxy.new(method_name, opts)
8
+
9
+ if self.class == Class
10
+ return if instance_methods.include?(proxy.method_name_without_caching)
11
+
12
+ if cached_instance_methods.empty?
13
+ include(InvalidationMethods)
14
+ extend(MethodAdded)
15
+ end
16
+
17
+ cached_instance_methods[method_name] = nil
18
+ if method_defined?(method_name) or private_method_defined?(method_name)
19
+ if proxy.opts[:counter]
20
+ define_method "increment_#{method_name}", proxy.counter_method(:increment)
21
+ define_method "decrement_#{method_name}", proxy.counter_method(:decrement)
22
+ end
23
+
24
+ # Replace instance method.
25
+ alias_method proxy.method_name_without_caching, method_name
26
+ define_method method_name, proxy.method_with_caching
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
+ if class_method_defined?(method_name)
51
+ (class << self; self; end).module_eval do
52
+ if proxy.opts[:counter]
53
+ define_method "increment_#{method_name}", proxy.counter_method(:increment)
54
+ define_method "decrement_#{method_name}", proxy.counter_method(:decrement)
55
+ end
56
+
57
+ # Replace class method.
58
+ alias_method proxy.method_name_without_caching, method_name
59
+ define_method method_name, proxy.method_with_caching
60
+ end
61
+ end
62
+ cached_class_methods[method_name] = proxy
63
+ end
64
+
65
+ def class_method_defined?(method_name)
66
+ method(method_name)
67
+ true
68
+ rescue NameError
69
+ false
70
+ end
71
+
72
+ def self.default_cache
73
+ @default_cache ||= {}
74
+ end
75
+
76
+ def cached_instance_methods(method_name = nil)
77
+ if method_name
78
+ method_name = method_name.to_sym
79
+ ancestors.each do |klass|
80
+ next unless klass.kind_of?(MethodCache)
81
+ proxy = klass.cached_instance_methods[method_name]
82
+ return proxy if proxy
83
+ end
84
+ nil
85
+ else
86
+ @cached_instance_methods ||= {}
87
+ end
88
+ end
89
+
90
+ def cached_class_methods(method_name = nil)
91
+ if method_name
92
+ method_name = method_name.to_sym
93
+ ancestors.each do |klass|
94
+ next unless klass.kind_of?(MethodCache)
95
+ proxy = klass.cached_class_methods[method_name]
96
+ return proxy if proxy
97
+ end
98
+ nil
99
+ else
100
+ @cached_class_methods ||= {}
101
+ end
102
+ end
103
+
104
+ def cached_module_methods(method_name = nil)
105
+ if method_name
106
+ cached_module_methods[method_name.to_sym]
107
+ else
108
+ @cached_module_methods ||= {}
109
+ end
110
+ end
111
+
112
+ def self.disable(&block)
113
+ @disabled, old = true, @disabled
114
+ yield
115
+ ensure
116
+ @disabled = old
117
+ end
118
+
119
+ def self.disabled?
120
+ @disabled
121
+ end
122
+
123
+ module InvalidationMethods
124
+ def invalidate_cached_method(method_name, *args, &block)
125
+ cached_method(method_name, args).invalidate(&block)
126
+ end
127
+
128
+ def method_value_cached?(method_name, *args)
129
+ cached_method(method_name, args).cached?
130
+ end
131
+
132
+ def update_cached_method(method_name, *args, &block)
133
+ cached_method(method_name, args).update(&block)
134
+ end
135
+
136
+ def without_method_cache(&block)
137
+ MethodCache.disable(&block)
138
+ end
139
+
140
+ private
141
+
142
+ def cached_method(method_name, args)
143
+ if self.kind_of?(Class) or self.kind_of?(Module)
144
+ proxy = cached_class_methods(method_name)
145
+ else
146
+ proxy = self.class.send(:cached_instance_methods, method_name)
147
+ end
148
+ raise "method '#{method_name}' not cached" unless proxy
149
+ proxy.bind(self, args)
150
+ end
151
+ end
152
+
153
+ module MethodAdded
154
+ def method_added(method_name)
155
+ if proxy = cached_instance_methods(method_name)
156
+ cache_method(method_name, proxy)
157
+ end
158
+ super
159
+ end
160
+ end
161
+
162
+ module SingletonMethodAdded
163
+ def singleton_method_added(method_name)
164
+ if proxy = cached_class_methods(method_name)
165
+ cache_class_method(method_name, proxy)
166
+ end
167
+ super
168
+ end
169
+ end
170
+
171
+ module ModuleAdded
172
+ def extended(mod)
173
+ mod.extend(MethodCache)
174
+ cached_module_methods.each do |method_name, proxy|
175
+ mod.cache_class_method(method_name, proxy)
176
+ end
177
+ end
178
+
179
+ def included(mod)
180
+ mod.extend(MethodCache)
181
+ cached_module_methods.each do |method_name, proxy|
182
+ mod.cache_method(method_name, proxy)
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,220 @@
1
+ require 'digest/sha1'
2
+
3
+ class Object
4
+ def metaclass; class << self; self; end; end
5
+ end
6
+
7
+ module MethodCache
8
+ class Proxy
9
+ attr_reader :method_name, :opts, :args, :target
10
+ NULL = 'NULL'
11
+
12
+ def initialize(method_name, opts)
13
+ opts[:cache] ||= :counters if opts[:counter]
14
+ @method_name = method_name
15
+ @opts = opts
16
+ end
17
+
18
+ def bind(target, args)
19
+ self.clone.bind!(target, args)
20
+ end
21
+
22
+ def bind!(target, args)
23
+ @target = target
24
+ @args = args
25
+ @key = nil
26
+ self
27
+ end
28
+
29
+ def invalidate
30
+ if block_given?
31
+ # Only invalidate if the block returns true.
32
+ value = cache[key]
33
+ return if value and not yield(value)
34
+ end
35
+ cache.delete(key)
36
+ end
37
+
38
+ def context
39
+ opts[:context]
40
+ end
41
+
42
+ def version
43
+ dynamic_opt(:version)
44
+ end
45
+
46
+ def cached?
47
+ not cache[key].nil?
48
+ end
49
+
50
+ def update
51
+ value = block_given? ? yield(cache[key]) : target.send(method_name_without_caching, *args)
52
+ write_to_cache(key, value)
53
+ value
54
+ end
55
+
56
+ def value
57
+ value = opts[:counter] ? cache.count(key) : cache[key] unless MethodCache.disabled?
58
+ value = nil unless valid?(:load, value)
59
+
60
+ if value.nil?
61
+ value = target.send(method_name_without_caching, *args)
62
+ raise "non-integer value returned by counter method" if opts[:counter] and not value.kind_of?(Fixnum)
63
+ write_to_cache(key, value) if valid?(:save, value)
64
+ end
65
+
66
+ value = nil if value == NULL
67
+ if clone? and value
68
+ value.clone
69
+ else
70
+ value
71
+ end
72
+ end
73
+
74
+ def method_with_caching
75
+ proxy = self # Need access to the proxy in the closure.
76
+
77
+ lambda do |*args|
78
+ proxy.bind(self, args).value
79
+ end
80
+ end
81
+
82
+ def counter_method(method_name)
83
+ proxy = self # Need access to the proxy in the closure.
84
+
85
+ lambda do |*args|
86
+ if args.last.kind_of?(Hash) and args.last.keys == [:by]
87
+ amount = args.last[:by]
88
+ args.pop
89
+ end
90
+ proxy.bind(self, args).send(method_name, amount || 1)
91
+ end
92
+ end
93
+
94
+ def method_name_without_caching
95
+ @method_name_without_caching ||= begin
96
+ base_name, punctuation = method_name.to_s.sub(/([?!=])$/, ''), $1
97
+ "#{base_name}_without_caching#{punctuation}"
98
+ end
99
+ end
100
+
101
+ def cache
102
+ if @cache.nil?
103
+ @cache = opts[:cache] || MethodCache.default_cache
104
+ @cache = Memcache.pool[@cache] if @cache.kind_of?(Symbol)
105
+ if not @cache.respond_to?(:[]) and @cache.respond_to?(:get)
106
+ @cache.metaclass.module_eval do
107
+ define_method :[] do |key|
108
+ get(key)
109
+ end
110
+ end
111
+ end
112
+ end
113
+ @cache
114
+ end
115
+
116
+ def local?
117
+ cache.kind_of?(Hash)
118
+ end
119
+
120
+ def clone?
121
+ !!opts[:clone]
122
+ end
123
+
124
+ def key
125
+ if @key.nil?
126
+ arg_string = ([method_name, target] + args).collect do |arg|
127
+ object_key(arg)
128
+ end.join('|')
129
+ @key = ['m', version, arg_string].compact.join('|')
130
+ @key = "m|#{Digest::SHA1.hexdigest(@key)}" if @key.length > 250
131
+ end
132
+ @key
133
+ end
134
+
135
+ private
136
+
137
+ def expiry(value)
138
+ value = dynamic_opt(:expiry, value).to_i
139
+ if defined?(Memcache) and cache.kind_of?(Memcache)
140
+ {:expiry => value}
141
+ else
142
+ value
143
+ end
144
+ end
145
+
146
+ def valid?(type, value)
147
+ name = "#{type}_validation".to_sym
148
+ return true unless opts[name]
149
+ return unless value
150
+
151
+ dynamic_opt(name, value)
152
+ end
153
+
154
+ def dynamic_opt(name, value = nil)
155
+ if opts[name].kind_of?(Proc)
156
+ proc = opts[name].bind(target)
157
+ case proc.arity
158
+ when 0 then proc.call()
159
+ when 1 then proc.call(value)
160
+ else
161
+ proc.call(value, *args)
162
+ end
163
+ else
164
+ opts[name]
165
+ end
166
+ end
167
+
168
+ def write_to_cache(key, value)
169
+ unless opts[:counter]
170
+ value = value.nil? ? NULL : value
171
+ end
172
+ if cache.kind_of?(Hash)
173
+ raise 'expiry not permitted when cache is a Hash' if opts[:expiry]
174
+ raise 'counter cache not permitted when cache is a Hash' if opts[:counter]
175
+ cache[key] = value
176
+ elsif opts[:counter]
177
+ cache.write(key, value.to_s, expiry(value))
178
+ else
179
+ cache.set(key, value, expiry(value))
180
+ end
181
+ end
182
+
183
+ def increment(amount)
184
+ raise "cannot increment non-counter method" unless opts[:counter]
185
+ cache.incr(key, amount)
186
+ end
187
+
188
+ def decrement(amount)
189
+ raise "cannot decrement non-counter method" unless opts[:counter]
190
+ cache.decr(key, amount)
191
+ end
192
+
193
+ def object_key(arg)
194
+ return "#{class_key(arg.class)}-#{arg.string_hash}" if arg.respond_to?(:string_hash)
195
+
196
+ case arg
197
+ when NilClass then 'nil'
198
+ when TrueClass then 'true'
199
+ when FalseClass then 'false'
200
+ when Numeric then arg.to_s
201
+ when Symbol then ":#{arg}"
202
+ when String then "'#{arg}'"
203
+ when Class, Module then class_key(arg)
204
+ when Hash
205
+ '{' + arg.collect {|key, value| "#{object_key(key)}=#{object_key(value)}"}.sort.join(',') + '}'
206
+ when Array
207
+ '[' + arg.collect {|item| object_key(item)}.join(',') + ']'
208
+ when defined?(ActiveRecord::Base) && ActiveRecord::Base
209
+ "#{class_key(arg.class)}-#{arg.id}"
210
+ else
211
+ hash = local? ? arg.hash : Marshal.dump(arg).hash
212
+ "#{class_key(arg.class)}-#{hash}"
213
+ end
214
+ end
215
+
216
+ def class_key(klass)
217
+ klass.respond_to?(:version) ? "#{klass.name}_#{klass.version(context)}" : klass.name
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+ require 'dalli'
3
+
4
+ PORT = 19112
5
+ $client = Dalli::Client.new("localhost:#{PORT}")
6
+
7
+ class FooBar
8
+ extend MethodCache
9
+
10
+ cache_method :foo, :cache => $client
11
+ def foo
12
+ 'bar'
13
+ end
14
+ end
15
+
16
+ class MethodCacheRemoteTest < Test::Unit::TestCase
17
+
18
+ should 'work with dalli client' do
19
+ start_memcache(PORT)
20
+ $client.flush
21
+
22
+ f = FooBar.new
23
+ assert_equal 'bar', f.foo
24
+ end
25
+ end
@@ -0,0 +1,201 @@
1
+ require 'test_helper'
2
+ require 'memcache'
3
+
4
+ class Foo
5
+ extend MethodCache
6
+
7
+ def foo(i)
8
+ @i ||= 0
9
+ @i += i
10
+ end
11
+ cache_method :foo
12
+
13
+ cache_method :bar
14
+ def bar
15
+ @i ||= 0
16
+ @i += 1
17
+ end
18
+
19
+ @@i = 0
20
+ def baz(i)
21
+ @@i += i
22
+ end
23
+ cache_method :baz, :cache => :remote
24
+
25
+ cache_class_method :bap
26
+ def self.bap(i)
27
+ @i ||= 0
28
+ @i += i
29
+ end
30
+
31
+ cache_class_method :zap, :counter => true
32
+ def self.zap
33
+ 0
34
+ end
35
+
36
+ attr_accessor :z
37
+ def zang
38
+ self.z ||= 1
39
+ self.z += 1
40
+ nil
41
+ end
42
+ cache_method :zang
43
+ end
44
+
45
+ module Bar
46
+ extend MethodCache
47
+
48
+ cache_method :foo
49
+ def foo(i)
50
+ @i ||= 0
51
+ @i += i
52
+ end
53
+
54
+ cache_method :foo_count, :counter => true, :cache => :default
55
+ def foo_count(key)
56
+ 100
57
+ end
58
+ end
59
+
60
+ class Baz
61
+ include Bar
62
+ extend Bar
63
+ end
64
+
65
+ class TestMethodCache < Test::Unit::TestCase
66
+ should 'cache methods locally' do
67
+ a = Foo.new
68
+ f1 = a.foo(1)
69
+ f2 = a.foo(2)
70
+
71
+ assert_equal 1, f1
72
+ assert_equal 3, f2
73
+
74
+ assert f1 == a.foo(1)
75
+ assert f1 != f2
76
+ assert f2 == a.foo(2)
77
+
78
+ b = a.bar
79
+ assert b == a.bar
80
+ assert b == a.bar
81
+ end
82
+
83
+ should 'disable method_cache' do
84
+ a = Foo.new
85
+ f1 = a.foo(1)
86
+
87
+ f2 = a.without_method_cache do
88
+ a.foo(1)
89
+ end
90
+
91
+ f3 = MethodCache.disable do
92
+ a.foo(1)
93
+ end
94
+
95
+ assert f1 != f2
96
+ assert f1 != f3
97
+ assert f2 != f3
98
+ end
99
+
100
+ should 'cache methods remotely' do
101
+ a = Foo.new
102
+ b1 = a.baz(1)
103
+ b2 = a.baz(2)
104
+
105
+ assert_equal 1, b1
106
+ assert_equal 3, b2
107
+
108
+ assert b1 == a.baz(1)
109
+ assert b1 != b2
110
+ assert b2 == a.baz(2)
111
+ end
112
+
113
+ should 'cache class methods' do
114
+ assert_equal 10, Foo.bap(10)
115
+ assert_equal 23, Foo.bap(13)
116
+ assert_equal 10, Foo.bap(10)
117
+ assert_equal 23, Foo.bap(13)
118
+ end
119
+
120
+ should 'cache methods for mixins' do
121
+ a = Baz.new
122
+
123
+ assert_equal 1, a.foo(1)
124
+ assert_equal 1, a.foo(1)
125
+ assert_equal 3, a.foo(2)
126
+ assert_equal 3, a.foo(2)
127
+ end
128
+
129
+ should 'cache class methods for mixins' do
130
+ assert_equal 1, Baz.foo(1)
131
+ assert_equal 1, Baz.foo(1)
132
+ assert_equal 3, Baz.foo(2)
133
+ assert_equal 3, Baz.foo(2)
134
+ end
135
+
136
+ should 'invalidate cached method' do
137
+ a = Foo.new
138
+
139
+ assert_equal 1, a.foo(1)
140
+ assert_equal 3, a.foo(2)
141
+
142
+ a.invalidate_cached_method(:foo, 1)
143
+
144
+ assert_equal 4, a.foo(1)
145
+ assert_equal 3, a.foo(2)
146
+ end
147
+
148
+ should 'cache counters' do
149
+ b = Baz.new
150
+
151
+ assert_equal 100, b.foo_count(:bar)
152
+ b.increment_foo_count(:bar, :by => 42)
153
+ assert_equal 142, b.foo_count(:bar)
154
+ b.decrement_foo_count(:bar, :by => 99)
155
+ assert_equal 43, b.foo_count(:bar)
156
+ b.increment_foo_count(:bar)
157
+ assert_equal 44, b.foo_count(:bar)
158
+
159
+ assert_equal 100, b.foo_count(:baz)
160
+ b.increment_foo_count(:baz)
161
+ assert_equal 101, b.foo_count(:baz)
162
+ assert_equal 44, b.foo_count(:bar) # make sure :bar wasn't affected
163
+
164
+ assert_equal 0, Foo.zap
165
+ Foo.increment_zap(:by => 3)
166
+ assert_equal 3, Foo.zap
167
+ Foo.decrement_zap
168
+ assert_equal 2, Foo.zap
169
+ end
170
+
171
+ should 'use consistent local keys' do
172
+ a = Foo.new
173
+ o = Object.new
174
+ a_hash = a.hash
175
+ o_hash = o.hash
176
+
177
+ 5.times do
178
+ key = a.send(:cached_method, :bar, [{'a' => 3, 'b' => [5,6], 'c' => o}, [1,nil,{:o => o}]]).key
179
+ assert_equal "m|:bar|Foo-#{a_hash}|{'a'=3,'b'=[5,6],'c'=Object-#{o_hash}}|[1,nil,{:o=Object-#{o_hash}}]", key
180
+ end
181
+ end
182
+
183
+ should 'use consistent remote keys' do
184
+ a = Foo.new
185
+ o = Object.new
186
+ a_hash = Marshal.dump(a).hash
187
+ o_hash = Marshal.dump(o).hash
188
+
189
+ 5.times do
190
+ key = a.send(:cached_method, :baz, [{:a => 3, :b => [5,6], :c => o}, [false,true,{:o => o}]]).key
191
+ assert_equal "m|:baz|Foo-#{a_hash}|{:a=3,:b=[5,6],:c=Object-#{o_hash}}|[false,true,{:o=Object-#{o_hash}}]", key
192
+ end
193
+ end
194
+
195
+ should 'cache nil locally' do
196
+ a = Foo.new
197
+ a.zang
198
+ a.zang
199
+ assert_equal 2, a.z
200
+ end
201
+ end
@@ -0,0 +1,18 @@
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
+ def start_memcache(port)
14
+ system("memcached -p #{port} -U 0 -d -P /tmp/memcached_#{port}.pid")
15
+ sleep 1
16
+ File.read("/tmp/memcached_#{port}.pid")
17
+ end
18
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jashmenn-method_cache
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Justin Balthrop
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-17 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: Simple memcache-based memoization library for Ruby
15
+ email: code@justinbalthrop.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files:
19
+ - LICENSE
20
+ - README.rdoc
21
+ files:
22
+ - LICENSE
23
+ - README.rdoc
24
+ - Rakefile
25
+ - VERSION.yml
26
+ - lib/method_cache.rb
27
+ - lib/method_cache/proxy.rb
28
+ - test/method_cache_remote_test.rb
29
+ - test/method_cache_test.rb
30
+ - test/test_helper.rb
31
+ homepage: http://github.com/ninjudd/method_cache
32
+ licenses: []
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 1.8.6
52
+ signing_key:
53
+ specification_version: 3
54
+ summary: Simple memcache-based memoization library for Ruby
55
+ test_files: []