memoize
memoize(*symbols)No documentation available.
# File activesupport/lib/active_support/memoizable.rb, line 44
def memoize(*symbols)
symbols.each do |symbol|
original_method = "_unmemoized_#{symbol}""_unmemoized_#{symbol}"
memoized_ivar = MEMOIZED_IVAR.call(symbol)
class_eval "include Freezable\n\nraise \"Already memoized \#{symbol}\" if method_defined?(:\#{original_method})\nalias \#{original_method} \#{symbol}\n\nif instance_method(:\#{symbol}).arity == 0\ndef \#{symbol}(reload = false)\nif reload || !defined?(\#{memoized_ivar}) || \#{memoized_ivar}.empty?\n\#{memoized_ivar} = [\#{original_method}.freeze]\nend\n\#{memoized_ivar}[0]\nend\nelse\ndef \#{symbol}(*args)\n\#{memoized_ivar} ||= {} unless frozen?\nreload = args.pop if args.last == true || args.last == :reload\n\nif defined?(\#{memoized_ivar}) && \#{memoized_ivar}\nif !reload && \#{memoized_ivar}.has_key?(args)\n\#{memoized_ivar}[args]\nelsif \#{memoized_ivar}\n\#{memoized_ivar}[args] = \#{original_method}(*args).freeze\nend\nelse\n\#{original_method}(*args)\nend\nend\nend\n", __FILE__, __LINE__
end
end 6Notes
Differences between normal or-assign operator
Differences between this method and normal memoization with ||=:
- memoize works with false/nil values
- Potential arguments are memoized
Take the following example: def allowed? @allowed ||= begin # Big calculation puts "Worked" false end end
allowed? # Outputs "Worked"
allowed? # Outputs "Worked" again
Since @allowed is set to false (this is also applicable with +nil+), the ||= operator will move on the the next statement and will not be short-circuited.
When you use memoize you will not have this problem. def allowed? # Big calculation puts "Worked" false end memoize :allowed?
allowed? # Outputs "Worked"
allowed? # No output
Now, look at the case where we have parameters: def random(max=10) @random ||= rand(max) end
random # => 4
random # => 4 -- Yay!
random(20) # => 4 -- Oops!
Better use memoize again! def random(max=10) rand(max) end memoize :random
random # => 6
random # => 6 -- Yay!
random(20) # => 12 -- Double-Yay!
random # => 6 -- Head a'splode
Reloading memoized values
Memoize is used to cache the result of a method. It's roughly equivalent of having:
def memoized_method(*args)
@result[args] ||= (
# do calculation here
)
end
However, the result is cached so that it's not calculated for every request.
To recalculate cached value use either obj.memoized_method(:reload) or obj.memoized_method(true)
Remember to mixin the ActiveSupport::Memoizable module
To use memoize in your model you need to extend the model class with the module, like this:
class Person < ActiveRecord::Base
# Mixin the module
extend ActiveSupport::Memoizable
def expensive_method
# do something that is worth remembering
end
memoize :expensive_method
end
If you use memoizable in most of your models you could consider mixing the module into all ActiveRecord models by doing this in an initializer:
ActiveRecord::Base.extend(ActiveSupport::Memoizable)
Further To: Memoize will not cache singleton methods
er...it will:
==== Code example
class PersonType < ActiveRecord::Base
class << self
# Add the mixin here:
extend ActiveSupport::Memoizable
def mister
find_by_name('Mister')
end
memoize :mister
end
end
Current version
See ActiveSupport::Memoizable for un-deprecated version.
Memoize will not cache singleton methods
The following does not work: class PersonType < ActiveRecord::Base extend ActiveSupport::Memoizable class << self def mister find_by_name('Mister') end memoize :mister end
I guess one could extend the superclass, Class, with Memoizable support, but that seems Evil.