@libpath = File.join(File.dirname(__FILE__), 'registry')
@format = format
load File.join(@libpath, @format+'.rb') if format
+ # The get_impl method will return all implementations of the
+ # abstract accessor interface, since we only ever load one
+ # (the configured one) accessor implementation, we can just assume
+ # it to be the correct accessor to use.
+ accessors = AbstractAccessor.get_impl
+ if accessors.length > 1
+ warning 'multiple accessor implementations loaded!'
+ end
+ @accessor_class = accessors.first
end
# Returns a list of supported registry database formats.
# Creates a new Accessor object for the specified database filename.
def create(path, filename)
- # The get_impl method will return a list of all the classes that
- # implement the accessor interface, since we only ever load one
- # (the configured one) accessor implementation, we can just assume
- # it to be the correct accessor to use.
- cls = AbstractAccessor.get_impl.first
- db = cls.new(File.join(path, 'registry_' + @format, filename.downcase))
+ db = @accessor_class.new(File.join(path, 'registry_' + @format, filename.downcase))
db.optimize
db
end
# Abstract database accessor (a hash-like interface).
class AbstractAccessor
+ attr_reader :filename
+
# lets the user define a recovery procedure in case the Marshal
# deserialization fails, it might be manually recover data.
# NOTE: weird legacy stuff, used by markov plugin (WTH?)
attr_accessor :recovery
def initialize(filename)
- debug 'init registry accessor for: ' + filename
+ debug "init registry accessor of #{self.class} for: #{filename}"
@filename = filename
@name = File.basename filename
@registry = nil
@default = nil
@recovery = nil
+ @sub_registries = {}
end
def sub_registry(prefix)
path = File.join(@filename.gsub(/\.[^\/\.]+$/,''), prefix.to_s)
- return self.class.new(path)
+ @sub_registries[path] ||= self.class.new(path)
end
# creates the registry / subregistry folders
# Forces flush/sync the database on disk.
def flush
return unless @registry
- @registry.flush
+ # if not supported by the database, close/reopen:
+ close
+ registry
end
- # Should optimize/vacuum the database.
+ # Should optimize/vacuum the database. (if supported)
def optimize
- return unless @registry
- @registry.optimize
end
# Closes the database.
# like Hash#each
def each(&block)
return nil unless dbexists?
- registry.each do |key|
- block.call(key, self[key])
+ registry.each do |key, value|
+ block.call(key, restore(value))
end
end
end
# delete a key from the registry
+ # returns the value in success, nil otherwise
def delete(key)
return default unless dbexists?
- return registry.delete(key.to_s)
+ value = registry.delete(key.to_s)
+ if value
+ restore(value)
+ end
end
# returns a list of your keys
return registry.keys
end
- # just like Hash#has_both?
- def has_both?(key, value)
- return false unless dbexists?
- registry.has_key?(key.to_s) and registry.has_value?(store(value))
- end
-
# Return an array of all associations [key, value] in your namespace
def to_a
return [] unless dbexists?
# Returns all classes from the namespace that implement this interface
def self.get_impl
- ObjectSpace.each_object(Class).select { |klass| klass < self }
+ ObjectSpace.each_object(Class).select { |klass| klass.ancestors[1] == self }
end
end