class Moneta::Expires

Adds expiration support to the underlying store

‘#store`, `#load` and `#key?` support the `:expires` option to set/update the expiration time.

@api public

Public Class Methods

new(adapter, options = {}) click to toggle source

@param [Moneta store] adapter The underlying store @param [Hash] options @option options [String] :expires Default expiration time

Calls superclass method
# File lib/moneta/expires.rb, line 14
def initialize(adapter, options = {})
  raise 'Store already supports feature :expires' if adapter.supports?(:expires)
  super
end

Public Instance Methods

create(key, value, options = {}) click to toggle source

(see Proxy#store)

Calls superclass method
# File lib/moneta/expires.rb, line 50
def create(key, value, options = {})
  return super if options.include?(:raw)
  expires = expires_at(options)
  @adapter.create(key, new_entry(value, expires), Utils.without(options, :expires))
end
delete(key, options = {}) click to toggle source

(see Proxy#delete)

Calls superclass method
# File lib/moneta/expires.rb, line 43
def delete(key, options = {})
  return super if options.include?(:raw)
  value, expires = super
  value if !expires || Time.now <= Time.at(expires)
end
fetch_values(*keys, **options) { |key| ... } click to toggle source

(see Defaults#fetch_values)

Calls superclass method
# File lib/moneta/expires.rb, line 74
def fetch_values(*keys, **options)
  return super if options.include?(:raw)
  new_expires = expires_at(options, nil)
  options = Utils.without(options, :expires)
  substituted = {}
  block = if block_given?
            lambda do |key|
              substituted[key] = true
              yield key
            end
          end

  with_updates(options) do |updates|
    keys.zip(@adapter.fetch_values(*keys, **options, &block)).map do |key, entry|
      next entry if substituted[key]
      entry = invalidate_entry(key, entry, new_expires) do |new_entry|
        updates[key] = new_entry
      end
      if entry == nil
        value = if block_given?
                  yield key
                end
      else
        value, = entry
      end
      value
    end
  end
end
key?(key, options = {}) click to toggle source

(see Proxy#key?)

Calls superclass method
# File lib/moneta/expires.rb, line 20
def key?(key, options = {})
  # Transformer might raise exception
  load_entry(key, options) != nil
rescue
  super(key, Utils.without(options, :expires))
end
load(key, options = {}) click to toggle source

(see Proxy#load)

Calls superclass method
# File lib/moneta/expires.rb, line 28
def load(key, options = {})
  return super if options.include?(:raw)
  value, = load_entry(key, options)
  value
end
merge!(pairs, options = {}) { |key, old_value, new_value| ... } click to toggle source

(see Defaults#merge!)

# File lib/moneta/expires.rb, line 123
def merge!(pairs, options = {})
  expires = expires_at(options)
  options = Utils.without(options, :expires)

  block = if block_given?
            lambda do |key, old_entry, entry|
              old_entry = invalidate_entry(key, old_entry)
              if old_entry == nil
                entry # behave as if no replace is happening
              else
                old_value, = old_entry
                new_value, = entry
                new_entry(yield(key, old_value, new_value), expires)
              end
            end
          end

  entry_pairs = pairs.map do |key, value|
    [key, new_entry(value, expires)]
  end
  @adapter.merge!(entry_pairs, options, &block)
  self
end
slice(*keys, **options) click to toggle source

(see Defaults#slice)

Calls superclass method
# File lib/moneta/expires.rb, line 105
def slice(*keys, **options)
  return super if options.include?(:raw)
  new_expires = expires_at(options, nil)
  options = Utils.without(options, :expires)

  with_updates(options) do |updates|
    @adapter.slice(*keys, **options).map do |key, entry|
      entry = invalidate_entry(key, entry, new_expires) do |new_entry|
        updates[key] = new_entry
      end
      next if entry == nil
      value, = entry
      [key, value]
    end.reject(&:nil?)
  end
end
store(key, value, options = {}) click to toggle source

(see Proxy#store)

Calls superclass method
# File lib/moneta/expires.rb, line 35
def store(key, value, options = {})
  return super if options.include?(:raw)
  expires = expires_at(options)
  super(key, new_entry(value, expires), Utils.without(options, :expires))
  value
end
values_at(*keys, **options) click to toggle source

(see Defaults#values_at)

Calls superclass method
# File lib/moneta/expires.rb, line 57
def values_at(*keys, **options)
  return super if options.include?(:raw)
  new_expires = expires_at(options, nil)
  options = Utils.without(options, :expires)
  with_updates(options) do |updates|
    keys.zip(@adapter.values_at(*keys, **options)).map do |key, entry|
      entry = invalidate_entry(key, entry, new_expires) do |new_entry|
        updates[key] = new_entry
      end
      next if entry == nil
      value, = entry
      value
    end
  end
end

Private Instance Methods

invalidate_entry(key, entry, new_expires = nil) { |new_entry(value, new_expires)| ... } click to toggle source
# File lib/moneta/expires.rb, line 158
def invalidate_entry(key, entry, new_expires = nil)
  if entry != nil
    value, expires = entry
    if expires && Time.now > Time.at(expires)
      delete(key)
      entry = nil
    elsif new_expires != nil
      yield new_entry(value, new_expires) if block_given?
    end
  end
  entry
end
load_entry(key, options) click to toggle source
# File lib/moneta/expires.rb, line 149
def load_entry(key, options)
  new_expires = expires_at(options, nil)
  options = Utils.without(options, :expires)
  entry = @adapter.load(key, options)
  invalidate_entry(key, entry, new_expires) do |new_entry|
    @adapter.store(key, new_entry, options)
  end
end
new_entry(value, expires) click to toggle source
# File lib/moneta/expires.rb, line 171
def new_entry(value, expires)
  if expires
    [value, expires.to_r]
  elsif Array === value || value == nil
    [value]
  else
    value
  end
end
with_updates(options) { |updates| ... } click to toggle source
# File lib/moneta/expires.rb, line 181
def with_updates(options)
  updates = {}
  yield(updates).tap do
    @adapter.merge!(updates, options) unless updates.empty?
  end
end