Skip to content

Instantly share code, notes, and snippets.

@fronx
Created January 29, 2012 15:07
Show Gist options
  • Select an option

  • Save fronx/1699200 to your computer and use it in GitHub Desktop.

Select an option

Save fronx/1699200 to your computer and use it in GitHub Desktop.
#
# Demo for how to
# - use memoization with any cache
# - set up invalidation rules
#
class Cache
def initialize
@data = {}
end
def read(key)
if value = @data[key]
value.dup
end
end
def write(key)
value = yield
value = value.dup unless Symbol === value
@data[key] = value
end
def delete(key)
@data.delete(key)
end
end
$cache = Cache.new
module Everycache
def cache_class_method(name)
overwrite(name) do |name, old_method, *args|
cache.read(key(name, args)) ||
old_method.call(*args).tap do |value|
cache.write(key(name, args)) { value }
end
end
end
def invalidate(name, trigger, &relevant_args)
overwrite(trigger) do |trigger, old_method, *args|
old_method.call(*args).tap do |result|
cache.delete(key(name, relevant_args.call(*args)))
end
end
end
def key(name, args)
[ self.to_s.to_sym, name, Array(args) ]
end
def cache
raise "cache is not initialized"
end
private
def overwrite(name, &block)
old_method = method(name)
metaclass.instance_eval do
define_method(name) do |*args|
block.call(name, old_method, *args)
end
end
end
def metaclass
class << self; self; end
end
end
class Recursion
def self.fib(n)
puts "# fib(#{n})"
case n
when 1..3
[ 0, 1, 1 ][0...n]
else
result = fib(n - 1)
result << (result[-2] + result[-1])
end
end
private
extend Everycache
cache_class_method(:fib)
def self.cache
$cache
end
end
class Invalidation
@objects = {
1 => "a",
2 => :b,
}
def self.find(id)
puts "# find(#{id})"
@objects[id]
end
def self.save(id, value)
puts "# save(#{id}, #{value.inspect})"
@objects[id] = value
end
private
extend Everycache
cache_class_method(:find)
invalidate(:find, :save) { |id, value| id }
def self.cache
$cache
end
end
puts "# ------ recusion -------------- "
puts Recursion.fib(7).inspect
puts Recursion.fib(5).inspect
puts Recursion.fib(8).inspect
puts Recursion.fib(7).inspect
puts "# ------ invalidation ---------- "
puts Invalidation.find(1).inspect
puts Invalidation.find(1).inspect
Invalidation.save(1, "new value for 1")
puts Invalidation.find(1).inspect
Invalidation.save(2, "new value for 2")
puts Invalidation.find(2).inspect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment