class LRUCache

Not thread-safe!

Constants

VERSION

Attributes

default[R]
max_size[R]
retry_delay[R]
soft_ttl[R]
ttl[R]

Public Class Methods

new(opts={}) click to toggle source
# File lib/lrucache.rb, line 9
def initialize(opts={})
  @max_size = Integer(opts[:max_size] || 100)
  @default = opts[:default]
  @eviction_handler = opts[:eviction_handler]
  @ttl = Float(opts[:ttl] || 0)
  @soft_ttl = Float(opts[:soft_ttl] || 0)
  @retry_delay = Float(opts[:retry_delay] || 0)
  raise "max_size must not be negative" if @max_size < 0
  raise "ttl must not be negative" if @ttl < 0
  raise "soft_ttl must not be negative" if @soft_ttl < 0
  raise "retry_delay must not be negative" if @retry_delay < 0

  @pqueue = PriorityQueue.new
  @data = {}
  @counter = 0
end

Public Instance Methods

[](key, args={})
Alias for: fetch
[]=(key, value, args={})
Alias for: store
clear() click to toggle source
# File lib/lrucache.rb, line 26
def clear
  @data.clear
  @pqueue.delete_min until @pqueue.empty?
  @counter = 0 #might as well
end
delete(key) click to toggle source
# File lib/lrucache.rb, line 105
def delete(key)
  @pqueue.delete(key)
  datum = @data.delete(key)
  datum.value unless datum.nil?
end
empty?() click to toggle source
# File lib/lrucache.rb, line 93
def empty?
  size == 0
end
fetch(key, args={}) { || ... } click to toggle source
# File lib/lrucache.rb, line 56
def fetch(key, args={})
  datum = @data[key]
  if datum.nil?
    if block_given?
      store(key, value = yield, args)
    else
      @default
    end
  elsif datum.expired?
    delete(key)
    if block_given?
      store(key, value = yield, args)
    else
      @default
    end
  elsif datum.soft_expired?
    if block_given?
      begin
        store(key, value = yield, args)
      rescue RuntimeError => e
        access(key)
        ttl, soft_ttl, retry_delay = extract_arguments(args)
        datum.soft_expiration = (Time.now + retry_delay) if retry_delay > 0
        datum.value
      end
    else
      access(key)
      datum.value
    end
  else
    access(key)
    datum.value
  end
end
Also aliased as: []
include?(key) click to toggle source
# File lib/lrucache.rb, line 32
def include?(key)
  datum = @data[key]
  return false if datum.nil?
  if datum.expired?
    delete(key)
    false
  else
    access(key)
    true
  end
end
keys() click to toggle source
# File lib/lrucache.rb, line 101
def keys
  @data.keys
end
size() click to toggle source
# File lib/lrucache.rb, line 97
def size
  @data.size
end
store(key, value, args={}) click to toggle source
# File lib/lrucache.rb, line 44
def store(key, value, args={})
  evict_lru! unless @data.include?(key) || @data.size < max_size
  ttl, soft_ttl, retry_delay = extract_arguments(args)
  expiration = expiration_date(ttl)
  soft_expiration = expiration_date(soft_ttl)
  @data[key] = Datum.new(value, expiration, soft_expiration)
  access(key)
  value
end
Also aliased as: []=

Private Instance Methods

access(key) click to toggle source
# File lib/lrucache.rb, line 161
def access(key)
  @pqueue.change_priority(key, @counter += 1)
end
evict_lru!() click to toggle source
# File lib/lrucache.rb, line 153
def evict_lru!
  key, priority = @pqueue.delete_min
  unless priority.nil?
    datum = @data.delete(key)
    @eviction_handler.call(datum.value) if @eviction_handler && datum
  end
end
expiration_date(ttl) click to toggle source
# File lib/lrucache.rb, line 131
def expiration_date(ttl)
  if ttl.is_a?(Time)
    ttl
  else
    ttl = Float(ttl)
    (ttl > 0) ? (Time.now + ttl) : nil
  end
end
extract_arguments(args) click to toggle source
# File lib/lrucache.rb, line 140
def extract_arguments(args)
  if args.is_a?(Hash)
    ttl = args[:ttl] || @ttl
    soft_ttl = args[:soft_ttl] || @soft_ttl
    retry_delay = args[:retry_delay] || @retry_delay
    [ttl, soft_ttl, retry_delay]
  else
    # legacy arg
    ttl = args || @ttl
    [ttl, @soft_ttl, @retry_delay]
  end
end