class Expires

Constants

KEYS
SCHEMA
VERSION

Public Class Methods

database() click to toggle source
# File lib/expires.rb, line 21
def self.database
  @@database
end
database=(path) click to toggle source
# File lib/expires.rb, line 17
def self.database=(path)
  @@database = path
end
db(namespace) click to toggle source
# File lib/expires.rb, line 25
def self.db(namespace)
  @@dbs[namespace]
end
escape_sqlite3(string, **hash) click to toggle source
# File lib/expires.rb, line 229
def self.escape_sqlite3(string, **hash)
  hash.each do |key, value|
    value.gsub!(/'/,"''") if value.is_a?(String)
    value = "null" if value.nil?
    string.gsub!(":#{key}", "'#{value}'")
  end
  return string
end
get_source_str(source) click to toggle source
# File lib/expires.rb, line 218
def self.get_source_str source
  source.gsub!(/\n/,"$n")
  source.gsub!(/\A.*?(-> +\(.*\)|lambda) +?(do|\{)( +)?(\|.*?\|)?/, "")
  source.gsub!(/\A.*?closer.*?(do|\{)( +)?(\|.*?\|)?/, "")
  source.reverse!
  source.gsub!(/\A(.*?)(dne|\})/, "")
  source.reverse!
  source.gsub!("$n","\n")
  return source
end
new(namespace: namespace, expire: 5, hotload: true) click to toggle source
# File lib/expires.rb, line 29
def initialize namespace: namespace, expire: 5, hotload: true
  @@db        = SQLite3::Database.new(@@database) unless @@db
  @namespace  = namespace
  @connected  = false
  @expire     = expire
  @hotload    = hotload
  @body       = Hash.new
  @remind     = Hash.new

  connect(namespace)
  sync if @hotload
end
new(namespace: namespace, expire: 5, hotload: true) click to toggle source
Calls superclass method
# File lib/expires.rb, line 239
def Expires.new namespace: namespace, expire: 5, hotload: true
  raise "namespace is nil." if namespace.nil? or namespace == ""
  return Expires.db(namespace) || super
end

Public Instance Methods

[](key) click to toggle source
# File lib/expires.rb, line 165
def [](key)
  get key
end
[]=(key,value) click to toggle source
# File lib/expires.rb, line 123
def []=(key,value)
  set(key,value)
end
clean() click to toggle source
# File lib/expires.rb, line 127
def clean
  @@db.execute("delete from #{@namespace};")
  @@db.execute("VACUUM;")
end
closer(key, procedure=nil, remind: nil, &block) click to toggle source
# File lib/expires.rb, line 199
def closer key, procedure=nil, remind: nil, &block
  if block_given?
    obj = Object.new
    obj.define_singleton_method(:_, &block)
    procedure = obj.method(:_).to_proc
  end

  source = Expires.get_source_str(procedure.source).gsub(/\n/,"$n")
  if get key
    sql = updates key, {:on_expire=>source.to_s, :remind=>JSON.generate(remind||{})}
  else
    #procedure.call
    return
  end

  kill_expired
  @@io.puts sql
end
connect(namespace) click to toggle source
# File lib/expires.rb, line 89
def connect(namespace)
  unless @@dbs[namespace]
    create(namespace)
    @body = Hash.new
    @@dbs.store(namespace, self)
    @connected = true
  end
end
create(namespace) click to toggle source
# File lib/expires.rb, line 55
def create(namespace)
  begin
    @@db.execute(sql = schema(namespace))
    @@io.puts sql
  rescue SQLite3::SQLException => e
    raise e unless e.message =~ /table .* already exists/
  end
  return namespace
end
disconnect() click to toggle source
# File lib/expires.rb, line 98
def disconnect
  if @connected
    @@dbs.delete @namespace
    @body = nil
    @connected = false
  end
end
flash(key) click to toggle source
# File lib/expires.rb, line 144
def flash key
  if value = select(key, :remind)
    begin
      @remind = JSON.parse value.first
    rescue
      STDERR.puts "Invalid JSON value."
    end
  end
end
forget(key) click to toggle source
# File lib/expires.rb, line 138
def forget key
  raise "Remind your value as Hash." unless hash.is_a?(Hash)
  update key, :remind, "{}" if get key
  @remind[key.to_sym] = {}
end
get(key) click to toggle source
# File lib/expires.rb, line 159
def get key
  return select(key, :value).first
rescue => e
  return nil
end
kill_expired() click to toggle source
# File lib/expires.rb, line 65
def kill_expired
  @killing = true
  now = Time.new.to_i
  expires = @@db.execute(sql = "select on_expire, key, value from #{@namespace} where (updated_at+expire) < #{now};")
  expires.each do |values|
    if values[0]
      begin
        @key = values[1]
        @value = values[2]
        flash(@key) 
        @self = self
        eval values[0].gsub("$n","\n")
      rescue =>e
        STDERR.puts e
        STDERR.puts e.backtrace
      end
    end
  end

  @@db.execute(sql = "delete from #{@namespace} where (updated_at+expire) < #{now};")
  @@io.puts sql
  @killing = nil
end
remind(key, hash) click to toggle source
# File lib/expires.rb, line 132
def remind key, hash
  raise "Remind your value as Hash." unless hash.is_a?(Hash)
  update key, :remind, JSON.generate(hash) if get key
  @remind[key.to_sym] = hash
end
schema(namespace) click to toggle source
# File lib/expires.rb, line 51
def schema namespace
  return SCHEMA.gsub("NAMESPACE",namespace)
end
select(key, *columns) click to toggle source
# File lib/expires.rb, line 154
def select key, *columns
  kill_expired unless @killing
  return @body[key.to_sym] = @@db.execute("select #{columns.join(", ")} from #{@namespace} where key = '#{key}' limit 1;").first
end
set(key, value, expire = @expire) click to toggle source
# File lib/expires.rb, line 106
def set key, value, expire = @expire
  @body[key] = value
  record = select(key, :created_at)
  
  if record
    created_at = record[0]
    updated_at = Time.new.to_i
  else
    updated_at = created_at = Time.new.to_i
  end
  
  @@db.execute(sql="insert or replace into #{@namespace} (key,value,created_at,updated_at,expire)"+
               " values ('#{key}','#{value}','#{created_at}','#{updated_at}','#{expire}'#{});")
  @@io.puts sql
  #TODO: syncedで状態管理
end
sync(async: false) click to toggle source
# File lib/expires.rb, line 42
def sync(async: false)
  raise "Database not connected" unless @connected
  kill_expired
  @@db.execute("select key,value from #{@namespace};").each do |array|
    @body[array[0]] = array[1]
  end
  @synced = true
end
update(key, column, value) click to toggle source
# File lib/expires.rb, line 169
def update key, column, value
  sql = Expires.escape_sqlite3("update :_namespace_ set #{column} = (:#{column}) where key = (:key);",
                               column=>value,
                               :key=>key, 
                               :_namespace_=>@namespace)
  @@db.execute(sql)
  sql
end
updates(key, hash) click to toggle source
# File lib/expires.rb, line 178
def updates key, hash
  sql = "update :_namespace_ set "
  first = true
  hash.each do |k, v|
    if first
      first = false
    else
      sql << ','
    end
    sql << "#{k} = :#{k} "
  end
  sql << "where key = (:key);"

  sql = Expires.escape_sqlite3(sql,
                               :key=>key, 
                               :_namespace_=>@namespace,
                               **hash)
  @@db.execute(sql)
  sql
end