Module: Memoizable

Defined in:
lib/standard/facets/memoizable.rb

Overview

Memoization is an optimization technique used primarily to speed up programs by having function calls avoid repeating the calculation of results for previously-processed inputs.

When you “memoize” a method/function using Memoizable its results are cached so that later calls return results from the cache instead of recalculating them.

class T
  include Memoizable

  def initialize(a)
    @a = a
  end

  def a
    "#{@a ^ 3 + 4}"
  end

  memoize :a
end

t = T.new(10)
(t.a.__id__ == t.a.__id__)  #=> true

This method can also be used at the instance level to cache singleton (qua class) methods by including it in the singleton class.

– TODO: It would be very cool if Memoizable could set-up default parameters via #[] method, e.g. `include

Defined Under Namespace

Modules: Copy

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.append_features(base) ⇒ Object


44
45
46
# File 'lib/standard/facets/memoizable.rb', line 44

def self.append_features(base)
  Module == base ? super(base) : base.extend(self)
end

.cacheObject


39
40
41
# File 'lib/standard/facets/memoizable.rb', line 39

def self.cache
  @cache
end

Instance Method Details

#memoize(*method_names) ⇒ Object

Directive for making your functions faster by trading space for time. When you “memoize” a method/function using #memoize its results are cached so that later calls with the same arguments return results from the cache instead of recalculating them.

The #memoize method also handles a few options to alter behavior of the memoization:

:class     => true      cache per-class not per-object
:freeze    => true      freeze the memoized return values
:arguments => false     do not index cache by arguments

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/standard/facets/memoizable.rb', line 60

def memoize(*method_names)
  options = Hash === method_names.last ? method_names.pop : {}

  options[:arguments] = true if options[:arguments].nil?  # default to true

  ref = options[:class]     ? 'self.class.name'       : 'self'
  frz = options[:freeze]    ? '.freeze'               : ''
  arg = options[:arguments] ? '[__a__, block_given?]' : 'nil'

  code = ""
  method_names.each do |m|
    code << <<-code
      alias_method '#{ m }:memo', '#{ m }'
      private '#{ m }:memo'
      def #{ m }(*__a__,&__b__)
        c = Memoizable.cache[#{ref}][:'#{ m }']
        k = #{arg}
        if c.has_key?(k)
          c[k]
        else
          c[k] = __send__('#{ m }:memo',*__a__,&__b__)#{frz}
        end
      end
    code
  end
  module_eval(code)
end

#rememoize(*method_names) ⇒ Object

Remove the memoized value from the memoization cache. The next time a memoized methos is called if will be remomoized.


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/standard/facets/memoizable.rb', line 91

def rememoize(*method_names)
  if Memoizable.cache[self]
    if method_names.empty?
      Memoizable.cache.delete(self)
    else
      method_names.each do |m|
        Memoizable.cache[self].delete(m.to_sym)
      end
    end
  end
  if Memoizable.cache[self.class.name]
    if method_names.empty?
      Memoizable.cache.delete(self.class.name)
    else
      method_names.each do |m|
        Memoizable.cache[self.class.name].delete(m.to_sym)
      end
    end
  end
end

#unmemoize(*method_names) ⇒ Object


113
114
115
116
117
118
# File 'lib/standard/facets/memoizable.rb', line 113

def unmemoize(*method_names)
  rememoize(*method_names)
  method_names.each do |m|
    alias_method name, "#{ m }:memo"
  end
end