Simple memoization module

M

Marcin Raczkowski

If you ewer wanted to easilly cache memoizable functions (ones that
output depend ONLY on parameters given)- here's a way!

Implementation contains sweeping support for classes/modules and methods
inside those classes, ActiveRecord logger is used by memcache-client
library so I provide it becouse i'm to lazy to remove that dependency in
3rd party pugin.

If anyone shows interest i'll pack it as gem, and mayby add some stuff,
all requests are welcome

Marcin Raczkowski
www.softwarelab.eu

=========================================================================

module Memoization
# store keys for sweeping
def Memoization.add_key(key)
@keys ||= []
@keys |= [key]
end

# remove keys that belongs to given class/method
def Memoization.sweep(klass, method=nil)
reg = method ? Regexp.new("^#{klass}:#{method}") :
Regexp.new("^#{klass.to_s}")
@keys.select{|k| reg.match(k) }.each{|k| Cache.delete(k)}
end

# sugar that allows SomeClass.sweep
def sweep(method = nil)
Memoization.sweep(self, method)
end

# example usage in test case, takes names of methods to memoize
def memoize(*names)
return unless defined?(Cache)

names.each do |name|
name = name.to_s
new_name = "nc_"+name
alias_method(new_name, name)
define_method(name) do |*args|
key = "#{self.class.name}:#{name}(#{args.hash})"
Memoization.add_key(key)
Cache.get(key, 60) {
self.send(new_name.to_sym, *args)
}
end
end

end
end

# doing inclusion into module / class
class Class
include Memoization
end

class Module
include Memoization
end

# workaround for non-rails environment
unless defined?(ActiveRecord::Base)
module ActiveRecord; end
class ActiveRecord::Base;
def self.logger; Logger.new(STDOUT); end;
end
end

if __FILE__ == $0
# testcase require memcached server running on default port

require 'test/unit'
require 'rubygems'
require 'memcache'
CACHE = MemCache.new 'localhost:11211', :namespace => 'moization'
require 'memcache_util'
require 'logger'

class A
def normal(a); a; end
def random(); rand; end
memoize :normal, :random
end

class TC_MyTest < Test::Unit::TestCase
def test_behaviour
assert(A.new.normal:)a) == A.new.normal:)a))
assert(A.new.normal:)a) != A.new.normal:)b))
rnd = A.new.random
assert(A.new.random == A.new.random)
A.sweep
assert(A.new.random != rnd)
assert(A.new.random == A.new.random)
rnd = A.new.random
A.sweep:)random)
assert(A.new.random != rnd)
assert(A.new.random == A.new.random)
end
end
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,152
Members
46,698
Latest member
LydiaHalle

Latest Threads

Top