Created
January 29, 2012 15:07
-
-
Save fronx/1699200 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # | |
| # 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