4 # Daybreak is a simple and very fast key value store for ruby.
5 # http://propublica.github.io/daybreak/
15 # This class provides persistent storage for plugins via a hash interface.
16 # The default mode is an object store, so you can store ruby objects and
17 # reference them with hash keys. This is because the default store/restore
18 # methods of the plugins' RegistryAccessor are calls to Marshal.dump and
23 # @registry[:blah] = blah
24 # then, even after the bot is shut down and disconnected, on the next run you
25 # can access the blah object as it was, with:
26 # blah = @registry[:blah]
27 # The registry can of course be used to store simple strings, fixnums, etc as
28 # well, and should be useful to store or cache plugin data or dynamic plugin
32 # in object store mode, don't make the mistake of treating it like a live
33 # object, e.g. (using the example above)
34 # @registry[:blah][:foo] = "flump"
35 # will NOT modify the object in the registry - remember that Registry#[]
36 # returns a Marshal.restore'd object, the object you just modified in place
37 # will disappear. You would need to:
38 # blah = @registry[:blah]
39 # blah[:foo] = "flump"
40 # @registry[:blah] = blah
42 # If you don't need to store objects, and strictly want a persistant hash of
43 # strings, you can override the store/restore methods to suit your needs, for
44 # example (in your plugin):
55 # Your plugins section of the registry is private, it has its own namespace
56 # (derived from the plugin's class name, so change it and lose your data).
57 # Calls to registry.each etc, will only iterate over your namespace.
60 attr_accessor :recovery
62 # plugins don't call this - a Registry::Accessor is created for them and
63 # is accessible via @registry.
64 def initialize(bot, name)
67 @filename = @bot.path 'registry_daybreak', @name+'.db'
68 dirs = File.dirname(@filename).split("/")
69 dirs.length.times { |i|
70 dir = dirs[0,i+1].join("/")+"/"
71 unless File.exist?(dir)
72 debug "creating subregistry directory #{dir}"
79 # debug "initializing registry accessor with name #{@name}"
83 @registry ||= Daybreak::DB.new(@filename)
87 return unless @registry
92 return unless @registry
97 # convert value to string form for storing in the registry
98 # defaults to Marshal.dump(val) but you can override this in your module's
99 # registry object to use any method you like.
100 # For example, if you always just handle strings use:
108 # restores object from string form, restore(store(val)) must return val.
109 # If you override store, you should override restore to reverse the
111 # For example, if you always just handle strings use:
118 rescue Exception => e
119 error _("failed to restore marshal data for #{val.inspect}, attempting recovery or fallback to default")
121 if defined? @recovery and @recovery
123 return @recovery.call(val)
124 rescue Exception => ee
125 error _("marshal recovery failed, trying default")
133 # lookup a key in the registry
135 if registry.has_key?(key.to_s)
136 return restore(registry[key.to_s])
142 # set a key in the registry
144 registry[key.to_s] = store(value)
147 # set the default value for registry lookups, if the key sought is not
148 # found, the default will be returned. The default default (har) is nil.
149 def set_default (default)
154 @default && (@default.dup rescue @default)
159 registry.each do |key|
160 block.call(key, self[key])
168 registry.each do |key|
173 # like Hash#each_value
174 def each_value(&block)
175 registry.each do |key|
176 block.call(self[key])
180 # just like Hash#has_key?
182 return registry.has_key?(key.to_s)
185 alias include? has_key?
186 alias member? has_key?
189 # just like Hash#has_both?
190 def has_both?(key, value)
191 registry.has_key?(key.to_s) and registry.has_value?(store(value))
194 # just like Hash#has_value?
195 def has_value?(value)
196 return registry.has_value?(store(value))
199 # just like Hash#index?
202 return k if v == value
207 # delete a key from the registry
209 return registry.delete(key.to_s)
212 # returns a list of your keys
217 # Return an array of all associations [key, value] in your namespace
220 registry.each {|key, value|
221 ret << [key, restore(value)]
226 # Return an hash of all associations {key => value} in your namespace
229 registry.each {|key, value|
230 ret[key] = restore(value)
235 # empties the registry (restricted to your namespace)
241 # returns an array of the values in your namespace of the registry
250 def sub_registry(prefix)
251 return Accessor.new(@bot, @name + "/" + prefix.to_s)
254 # returns the number of keys in your registry namespace