Create a gist now

Instantly share code, notes, and snippets.

@mweppler /cache.rb
Last active Dec 17, 2015

What would you like to do?
Ruby implementation of the python Cache class from Box CRE "The 'One' Thing" by Peter Potrebic
#!/usr/bin/env ruby
# Ruby implementation of the python Cache class from Box CRE "The 'One' Thing" by Peter Potrebic
$store = {}
$namespace = 'rcache'
class Cache < Object
def initialize(cache_name)
registration_table_key = "#{$namespace}.registration_table"
registration_table = $store[registration_table_key]
cache_info = registration_table[cache_name]
@_cache_name = cache_name
@_version, @_data_type, @_timeout = cache_info
end
def self.register(cache_name, data_type, timeout)
if (data_type != Fixnum && data_type != Float && data_type != Bignum && data_type != String && data_type != Complex)
raise TypeError, 'Unsupported type'
end
registration_table_key = "#{$namespace}.registration_table"
if $store.has_key? registration_table_key
registration_table = $store.fetch(registration_table_key)
else
$store.default = {}
registration_table = $store[registration_table_key]
end
unless registration_table.has_key?(cache_name)
cache_info = [1, data_type, timeout] # should this be a struct
registration_table[cache_name] = cache_info
end
Cache.new(cache_name)
end
def timeout
@_timeout
end
def cache_name
@_cache_name
end
def version
@_version
end
def bump_version
registration_table_key = "#{$namespace}.registration_table"
registration_table = $store[registration_table_key]
version, _, _ = registration_table[@_cache_name] # the _, _ is just a throw away of elements 1 & 2 (0 is the version)
@_version = version + 1
registration_table[@_cache_name] = [@_version, @_data_type, @_timeout]
end
def write(key, datum)
unless datum.class == @_data_type
raise TypeError
end
full_key = "#{$namespace}.#{@_cache_name}.#{@_version}.#{key}"
ttl = Time.now() + @_timeout
$store[full_key] = { :datum => datum, :ttl => ttl }
end
def write_collection(key, datum_collection)
# To maintain 'memcache' like semantics, make a copy of collection
collection = datum_collection.collect { |datum| datum }
collection.each { |datum| raise TypeError unless datum.class == @_data_type }
full_key = "#{$namespace}.#{@_cache_name}.#{@_version}.#{key}"
ttl = Time.now() + @_timeout
$store[full_key] = { :collection => collection, :ttl => ttl }
end
def read(key)
full_key = "#{$namespace}.#{@_cache_name}.#{@_version}.#{key}"
datum, ttl = $store[full_key][:datum], $store[full_key][:ttl]
if ttl < Time.now() # simplistic expiration logic
$store[full_key] = nil
raise KeyError
end
raise TypeError unless datum.class == @_data_type
ttl = Time.now() + @_timeout
$store[full_key] = { :datum => datum, :ttl => ttl }
datum
end
def read_collection(key)
full_key = "#{$namespace}.#{@_cache_name}.#{@_version}.#{key}"
collection, ttl = store[full_key][:collection], store[full_key][:ttl]
if ttl < Time.now() # simplistic expiration logic
$store[full_key] = nil
raise KeyError
end
collection.each { |datum| raise TypeError unless datum.class == @_data_type }
ttl = Time.now() + @_timeout
$store[full_key] = { :collection => collection, :ttl => ttl }
collection
end
end
require 'rspec'
describe Cache do
let(:cache) { Cache.register('test', String, 60) }
it "registers a new cache" do
expect(cache.class).to eq Cache
end
it "writes to the cache" do
result = cache.write 'test', 'this is a test'
expect(result[:datum]).to eq 'this is a test'
end
it "reads a cache" do
expect(cache.read 'test').to eq 'this is a test'
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment