# Simple memoization module

**URL:** <https://www.ruby-forum.com/t/simple-memoization-module/140580>\
**Category:** Ruby\
**Created:** [June 16, 2008, 1:25pm UTC](https://www.ruby-forum.com/t/simple-memoization-module/140580 "2008-06-16T13:25:59Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![marcin\_r](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/e5b9ba/32.png) [@marcin\_r](https://www.ruby-forum.com/u/marcin_r)\
**Post date:** [June 16, 2008, 1:25pm UTC](https://www.ruby-forum.com/t/simple-memoization-module/140580/1 "2008-06-16T13:25:59Z")

</div>

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 R.  
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
