Module: Memoize

Defined in:
lib/memoize.rb

Overview

Memoize is implementation Memoization for Ruby, this techinique to make functions faster.

Caveats:

  • Do not memoize a function whose behaviou depends on program state.

  • Do not memoize a function with side effects.

  • Do not memoize a function that returns a data structure that is modified by it’s caller.

See:

Memoization - en.wikipedia.org/wiki/Memoization

Defined Under Namespace

Modules: Expire Classes: MemoryStore, PStore, Storable

Constant Summary collapse

VERSION =
'0.1.0'
@@stores =
{}

Class Method Summary collapse

Class Method Details

._get_store(name) ⇒ Object

This method is public, but you don’t need call directly.



248
249
250
# File 'lib/memoize.rb', line 248

def _get_store(name)
  @@stores[name]
end

._set_store(name, store) ⇒ Object

This method is public, but you don’t need call directly.



243
244
245
# File 'lib/memoize.rb', line 243

def _set_store(name, store)
  @@stores[name] = store
end

.register(klass, name, options = {}) ⇒ Object

Make memoized function.

Parameters:

  • klass - You must surely specify ‘self’. This parameter used to overwrite Toplevell function and

    register as toplevel function. I need to think better the means ;)
    
  • name - an memorized function name.

  • options - an specify options. :as is memorized function name, default is the same second arguments value.

    <tt>:store</tt> is specify class which store memorized data.
    

Memoized function examples

def fib(n)
  return 1 if n < 2
  fib(n-1) + fib(n-2)
end

end
Memoize.register(self, 'fib')
fib(30) # => 1346269 fast
fib(30) # => 1346269 very fast

# Unmemorize
Memoize.unmemoize(self, 'fib')
fib(30) # => very slow

Memoized one Object methods

class Math2
  def self.fib(N)
    return 1 if n < 2
    fib(n-1) + fib(n-2)
  end
end

Memoize.memorize(self, 'Math2.fib')
Math.fib(30) # => fast
Math.fib(30) # => very fast
Memoize.unmemoize(self, 'Math2.fib')

Custom storage

You can use own memoized data storage, in doing so you must implementaion following method

Method/Arity:

  • initialize/1 - this is constructor

  • get/1 - an get the cache data with key

  • set/2 - an set the cache data with key and value

  • delete/1 - an delete the cache data with key

  • delete_all/0 - an delete all cache

Following class is MemCache storage sample.

# Memoized data storage using MemCache
require 'memcache'

class MemCacheStore < Memoize::Storable
  attr_accessor :cache, :keys
  def initialize(name)
    @keys   = []
    @cache  = MemCache.new 'localhost:11211', :namespace => 'rakuto.blogspot.com'
  end

  def get(key)
    @cache.get(key)
  end

  def set(key, value)
    @keys << key unless @keys.include?(key)
    @cache.set(key, value)
  end

  def delete(key)
    @cache.delete(key)
  end

  def delete_all
    @keys.each { |key| @cache.delete(key) }
  end
end

Memoize.register(self, 'fib', :store => MemCacheStore)
fib(30) # => fast
fib(30) # => fast


203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/memoize.rb', line 203

def register(klass, name, options={})
  ns = name.split(/::|\./)
  method, klass = ns.pop, (ns.empty? ? klass : Object.const_get(ns.join("::")))
  store     = options[:store].nil? ? PStore.new(name) : options[:store].new(name)
  as_method = options[:as] || method
  Memoize._set_store(name, store)
  (class<<klass;self;end).instance_eval do  # for Ruby1.9
    method_name           = "#{as_method}_without_memoize"
    memoized_method_name  = "#{as_method}_with_memoize"
    define_method(memoized_method_name) do |*args|
      store = Memoize._get_store(name)
      ret = store.get(args) 
      if ret.nil?
        ret = send(method_name, *args)
        store.set(args, ret)
      end
      ret
    end
    alias_method method_name, method 
    alias_method as_method, memoized_method_name
  end
end

.unmemoize(klass, name, delete_all = false) ⇒ Object

Specify unmemoize method. If you delete persistent cache when set delete_all true.

Example

Memoize.memoize(self, 'slow_func')
slow_func(arg)
Memoize.unmemoize(self, 'slow_func')


234
235
236
237
238
239
240
# File 'lib/memoize.rb', line 234

def unmemoize(klass, name, delete_all=false)
  (class<<klass;self;end).class_eval do 
    undef_method("#{name}_with_memoize")
    alias_method name, "#{name}_without_memoize"
  end
  delete_all && @store.delete_all
end