rbot 0.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. data/AUTHORS +16 -0
  2. data/COPYING +21 -0
  3. data/ChangeLog +418 -0
  4. data/INSTALL +8 -0
  5. data/README +44 -0
  6. data/REQUIREMENTS +34 -0
  7. data/TODO +5 -0
  8. data/Usage_en.txt +129 -0
  9. data/bin/rbot +81 -0
  10. data/data/rbot/contrib/plugins/figlet.rb +20 -0
  11. data/data/rbot/contrib/plugins/ri.rb +83 -0
  12. data/data/rbot/contrib/plugins/stats.rb +232 -0
  13. data/data/rbot/contrib/plugins/vandale.rb +49 -0
  14. data/data/rbot/languages/dutch.lang +73 -0
  15. data/data/rbot/languages/english.lang +75 -0
  16. data/data/rbot/languages/french.lang +39 -0
  17. data/data/rbot/languages/german.lang +67 -0
  18. data/data/rbot/plugins/autoop.rb +68 -0
  19. data/data/rbot/plugins/autorejoin.rb +16 -0
  20. data/data/rbot/plugins/cal.rb +15 -0
  21. data/data/rbot/plugins/dice.rb +81 -0
  22. data/data/rbot/plugins/eightball.rb +19 -0
  23. data/data/rbot/plugins/excuse.rb +470 -0
  24. data/data/rbot/plugins/fish.rb +61 -0
  25. data/data/rbot/plugins/fortune.rb +22 -0
  26. data/data/rbot/plugins/freshmeat.rb +98 -0
  27. data/data/rbot/plugins/google.rb +51 -0
  28. data/data/rbot/plugins/host.rb +14 -0
  29. data/data/rbot/plugins/httpd.rb.disabled +35 -0
  30. data/data/rbot/plugins/insult.rb +258 -0
  31. data/data/rbot/plugins/karma.rb +85 -0
  32. data/data/rbot/plugins/lart.rb +181 -0
  33. data/data/rbot/plugins/math.rb +122 -0
  34. data/data/rbot/plugins/nickserv.rb +89 -0
  35. data/data/rbot/plugins/nslookup.rb +43 -0
  36. data/data/rbot/plugins/opme.rb +19 -0
  37. data/data/rbot/plugins/quakeauth.rb +51 -0
  38. data/data/rbot/plugins/quotes.rb +321 -0
  39. data/data/rbot/plugins/remind.rb +228 -0
  40. data/data/rbot/plugins/roshambo.rb +54 -0
  41. data/data/rbot/plugins/rot13.rb +10 -0
  42. data/data/rbot/plugins/roulette.rb +147 -0
  43. data/data/rbot/plugins/rss.rb.disabled +414 -0
  44. data/data/rbot/plugins/seen.rb +89 -0
  45. data/data/rbot/plugins/slashdot.rb +94 -0
  46. data/data/rbot/plugins/spell.rb +36 -0
  47. data/data/rbot/plugins/tube.rb +71 -0
  48. data/data/rbot/plugins/url.rb +88 -0
  49. data/data/rbot/plugins/weather.rb +649 -0
  50. data/data/rbot/plugins/wserver.rb +71 -0
  51. data/data/rbot/plugins/xmlrpc.rb.disabled +52 -0
  52. data/data/rbot/templates/keywords.rbot +4 -0
  53. data/data/rbot/templates/lart/larts +98 -0
  54. data/data/rbot/templates/lart/praises +5 -0
  55. data/data/rbot/templates/levels.rbot +30 -0
  56. data/data/rbot/templates/users.rbot +1 -0
  57. data/lib/rbot/auth.rb +203 -0
  58. data/lib/rbot/channel.rb +54 -0
  59. data/lib/rbot/config.rb +363 -0
  60. data/lib/rbot/dbhash.rb +112 -0
  61. data/lib/rbot/httputil.rb +141 -0
  62. data/lib/rbot/ircbot.rb +808 -0
  63. data/lib/rbot/ircsocket.rb +185 -0
  64. data/lib/rbot/keywords.rb +433 -0
  65. data/lib/rbot/language.rb +69 -0
  66. data/lib/rbot/message.rb +256 -0
  67. data/lib/rbot/messagemapper.rb +262 -0
  68. data/lib/rbot/plugins.rb +291 -0
  69. data/lib/rbot/post-install.rb +8 -0
  70. data/lib/rbot/rbotconfig.rb +36 -0
  71. data/lib/rbot/registry.rb +271 -0
  72. data/lib/rbot/rfc2812.rb +1104 -0
  73. data/lib/rbot/timer.rb +201 -0
  74. data/lib/rbot/utils.rb +83 -0
  75. data/setup.rb +1360 -0
  76. metadata +129 -0
@@ -0,0 +1,291 @@
1
+ module Irc
2
+ module Plugins
3
+ require 'rbot/messagemapper'
4
+
5
+ # base class for all rbot plugins
6
+ # certain methods will be called if they are provided, if you define one of
7
+ # the following methods, it will be called as appropriate:
8
+ #
9
+ # map(template, options)::
10
+ # map is the new, cleaner way to respond to specific message formats
11
+ # without littering your plugin code with regexps. examples:
12
+ #
13
+ # plugin.map 'karmastats', :action => 'karma_stats'
14
+ #
15
+ # # while in the plugin...
16
+ # def karma_stats(m, params)
17
+ # m.reply "..."
18
+ # end
19
+ #
20
+ # # the default action is the first component
21
+ # plugin.map 'karma'
22
+ #
23
+ # # attributes can be pulled out of the match string
24
+ # plugin.map 'karma for :key'
25
+ # plugin.map 'karma :key'
26
+ #
27
+ # # while in the plugin...
28
+ # def karma(m, params)
29
+ # item = params[:key]
30
+ # m.reply 'karma for #{item}'
31
+ # end
32
+ #
33
+ # # you can setup defaults, to make parameters optional
34
+ # plugin.map 'karma :key', :defaults => {:key => 'defaultvalue'}
35
+ #
36
+ # # the default auth check is also against the first component
37
+ # # but that can be changed
38
+ # plugin.map 'karmastats', :auth => 'karma'
39
+ #
40
+ # # maps can be restricted to public or private message:
41
+ # plugin.map 'karmastats', :private false,
42
+ # plugin.map 'karmastats', :public false,
43
+ # end
44
+ #
45
+ # To activate your maps, you simply register them
46
+ # plugin.register_maps
47
+ # This also sets the privmsg handler to use the map lookups for
48
+ # handling messages. You can still use listen(), kick() etc methods
49
+ #
50
+ # listen(UserMessage)::
51
+ # Called for all messages of any type. To
52
+ # differentiate them, use message.kind_of? It'll be
53
+ # either a PrivMessage, NoticeMessage, KickMessage,
54
+ # QuitMessage, PartMessage, JoinMessage, NickMessage,
55
+ # etc.
56
+ #
57
+ # privmsg(PrivMessage)::
58
+ # called for a PRIVMSG if the first word matches one
59
+ # the plugin register()d for. Use m.plugin to get
60
+ # that word and m.params for the rest of the message,
61
+ # if applicable.
62
+ #
63
+ # kick(KickMessage)::
64
+ # Called when a user (or the bot) is kicked from a
65
+ # channel the bot is in.
66
+ #
67
+ # join(JoinMessage)::
68
+ # Called when a user (or the bot) joins a channel
69
+ #
70
+ # part(PartMessage)::
71
+ # Called when a user (or the bot) parts a channel
72
+ #
73
+ # quit(QuitMessage)::
74
+ # Called when a user (or the bot) quits IRC
75
+ #
76
+ # nick(NickMessage)::
77
+ # Called when a user (or the bot) changes Nick
78
+ # topic(TopicMessage)::
79
+ # Called when a user (or the bot) changes a channel
80
+ # topic
81
+ #
82
+ # connect():: Called when a server is joined successfully, but
83
+ # before autojoin channels are joined (no params)
84
+ #
85
+ # save:: Called when you are required to save your plugin's
86
+ # state, if you maintain data between sessions
87
+ #
88
+ # cleanup:: called before your plugin is "unloaded", prior to a
89
+ # plugin reload or bot quit - close any open
90
+ # files/connections or flush caches here
91
+ class Plugin
92
+ attr_reader :bot # the associated bot
93
+ # initialise your plugin. Always call super if you override this method,
94
+ # as important variables are set up for you
95
+ def initialize
96
+ @bot = Plugins.bot
97
+ @names = Array.new
98
+ @handler = MessageMapper.new(self)
99
+ @registry = BotRegistryAccessor.new(@bot, self.class.to_s.gsub(/^.*::/, ""))
100
+ end
101
+
102
+ def map(*args)
103
+ @handler.map(*args)
104
+ # register this map
105
+ name = @handler.last.items[0]
106
+ self.register name
107
+ unless self.respond_to?('privmsg')
108
+ def self.privmsg(m)
109
+ @handler.handle(m)
110
+ end
111
+ end
112
+ end
113
+
114
+ # return an identifier for this plugin, defaults to a list of the message
115
+ # prefixes handled (used for error messages etc)
116
+ def name
117
+ @names.join("|")
118
+ end
119
+
120
+ # return a help string for your module. for complex modules, you may wish
121
+ # to break your help into topics, and return a list of available topics if
122
+ # +topic+ is nil. +plugin+ is passed containing the matching prefix for
123
+ # this message - if your plugin handles multiple prefixes, make sure your
124
+ # return the correct help for the prefix requested
125
+ def help(plugin, topic)
126
+ "no help"
127
+ end
128
+
129
+ # register the plugin as a handler for messages prefixed +name+
130
+ # this can be called multiple times for a plugin to handle multiple
131
+ # message prefixes
132
+ def register(name)
133
+ return if Plugins.plugins.has_key?(name)
134
+ Plugins.plugins[name] = self
135
+ @names << name
136
+ end
137
+
138
+ # default usage method provided as a utility for simple plugins. The
139
+ # MessageMapper uses 'usage' as its default fallback method.
140
+ def usage(m, params = {})
141
+ m.reply "incorrect usage, ask for help using '#{@bot.nick}: help #{m.plugin}'"
142
+ end
143
+
144
+ end
145
+
146
+ # class to manage multiple plugins and delegate messages to them for
147
+ # handling
148
+ class Plugins
149
+ # hash of registered message prefixes and associated plugins
150
+ @@plugins = Hash.new
151
+ # associated IrcBot class
152
+ @@bot = nil
153
+
154
+ # bot:: associated IrcBot class
155
+ # dirlist:: array of directories to scan (in order) for plugins
156
+ #
157
+ # create a new plugin handler, scanning for plugins in +dirlist+
158
+ def initialize(bot, dirlist)
159
+ @@bot = bot
160
+ @dirs = dirlist
161
+ scan
162
+ end
163
+
164
+ # access to associated bot
165
+ def Plugins.bot
166
+ @@bot
167
+ end
168
+
169
+ # access to list of plugins
170
+ def Plugins.plugins
171
+ @@plugins
172
+ end
173
+
174
+ # load plugins from pre-assigned list of directories
175
+ def scan
176
+ dirs = Array.new
177
+ dirs << Config::datadir + "/plugins"
178
+ dirs += @dirs
179
+ dirs.each {|dir|
180
+ if(FileTest.directory?(dir))
181
+ d = Dir.new(dir)
182
+ d.sort.each {|file|
183
+ next if(file =~ /^\./)
184
+ next unless(file =~ /\.rb$/)
185
+ tmpfilename = "#{dir}/#{file}"
186
+
187
+ # create a new, anonymous module to "house" the plugin
188
+ # the idea here is to prevent namespace pollution. perhaps there
189
+ # is another way?
190
+ plugin_module = Module.new
191
+
192
+ begin
193
+ plugin_string = IO.readlines(tmpfilename).join("")
194
+ debug "loading plugin #{tmpfilename}"
195
+ plugin_module.module_eval(plugin_string)
196
+ rescue TimeoutError, StandardError, NameError, LoadError, SyntaxError => err
197
+ puts "warning: plugin #{tmpfilename} load failed: " + err
198
+ puts err.backtrace.join("\n")
199
+ end
200
+ }
201
+ end
202
+ }
203
+ end
204
+
205
+ # call the save method for each active plugin
206
+ def save
207
+ delegate 'save'
208
+ end
209
+
210
+ # call the cleanup method for each active plugin
211
+ def cleanup
212
+ delegate 'cleanup'
213
+ end
214
+
215
+ # drop all plugins and rescan plugins on disk
216
+ # calls save and cleanup for each plugin before dropping them
217
+ def rescan
218
+ save
219
+ cleanup
220
+ @@plugins = Hash.new
221
+ scan
222
+ end
223
+
224
+ # return list of help topics (plugin names)
225
+ def helptopics
226
+ if(@@plugins.length > 0)
227
+ # return " [plugins: " + @@plugins.keys.sort.join(", ") + "]"
228
+ return " [#{length} plugins: " + @@plugins.values.uniq.collect{|p| p.name}.sort.join(", ") + "]"
229
+ else
230
+ return " [no plugins active]"
231
+ end
232
+ end
233
+
234
+ def length
235
+ @@plugins.values.uniq.length
236
+ end
237
+
238
+ # return help for +topic+ (call associated plugin's help method)
239
+ def help(topic="")
240
+ if(topic =~ /^(\S+)\s*(.*)$/)
241
+ key = $1
242
+ params = $2
243
+ if(@@plugins.has_key?(key))
244
+ begin
245
+ return @@plugins[key].help(key, params)
246
+ rescue TimeoutError, StandardError, NameError, SyntaxError => err
247
+ puts "plugin #{@@plugins[key].name} help() failed: " + err
248
+ puts err.backtrace.join("\n")
249
+ end
250
+ else
251
+ return false
252
+ end
253
+ end
254
+ end
255
+
256
+ # see if each plugin handles +method+, and if so, call it, passing
257
+ # +message+ as a parameter
258
+ def delegate(method, *args)
259
+ @@plugins.values.uniq.each {|p|
260
+ if(p.respond_to? method)
261
+ begin
262
+ p.send method, *args
263
+ rescue TimeoutError, StandardError, NameError, SyntaxError => err
264
+ puts "plugin #{p.name} #{method}() failed: " + err
265
+ puts err.backtrace.join("\n")
266
+ end
267
+ end
268
+ }
269
+ end
270
+
271
+ # see if we have a plugin that wants to handle this message, if so, pass
272
+ # it to the plugin and return true, otherwise false
273
+ def privmsg(m)
274
+ return unless(m.plugin)
275
+ if (@@plugins.has_key?(m.plugin) &&
276
+ @@plugins[m.plugin].respond_to?("privmsg") &&
277
+ @@bot.auth.allow?(m.plugin, m.source, m.replyto))
278
+ begin
279
+ @@plugins[m.plugin].privmsg(m)
280
+ rescue TimeoutError, StandardError, NameError, SyntaxError => err
281
+ puts "plugin #{@@plugins[m.plugin].name} privmsg() failed: " + err
282
+ puts err.backtrace.join("\n")
283
+ end
284
+ return true
285
+ end
286
+ return false
287
+ end
288
+ end
289
+
290
+ end
291
+ end
@@ -0,0 +1,8 @@
1
+ # write out our datadir so we can reference it at runtime
2
+ File.open("#{config('rbdir')}/rbot/pkgconfig.rb", "w") {|f|
3
+ f.puts "module Irc"
4
+ f.puts " module PKGConfig"
5
+ f.puts " DATADIR = '#{config('datadir')}/rbot'"
6
+ f.puts " end"
7
+ f.puts "end"
8
+ }
@@ -0,0 +1,36 @@
1
+ module Irc
2
+ module Config
3
+ @@datadir = nil
4
+ # setup pkg-based configuration - i.e. where were we installed to, where
5
+ # are our data files, etc.
6
+ begin
7
+ debug "trying to load rubygems"
8
+ require 'rubygems'
9
+ debug "loaded rubygems, looking for rbot-#$version"
10
+ gemname, gem = Gem.source_index.find{|name, spec| spec.name == 'rbot' && spec.version.version == $version}
11
+ debug "got gem #{gem}"
12
+ if gem && path = gem.full_gem_path
13
+ debug "installed via rubygems to #{path}"
14
+ @@datadir = "#{path}/data/rbot"
15
+ else
16
+ debug "not installed via rubygems"
17
+ end
18
+ rescue LoadError
19
+ debug "no rubygems installed"
20
+ end
21
+
22
+ if @@datadir.nil?
23
+ begin
24
+ require 'rbot/pkgconfig'
25
+ @@datadir = PKGConfig::DATADIR
26
+ rescue LoadError
27
+ puts "fatal - no way to determine data dir"
28
+ exit 2
29
+ end
30
+ end
31
+
32
+ def Config.datadir
33
+ @@datadir
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,271 @@
1
+ require 'rbot/dbhash'
2
+
3
+ module Irc
4
+
5
+ # this is the backend of the RegistryAccessor class, which ties it to a
6
+ # DBHash object called plugin_registry(.db). All methods are delegated to
7
+ # the DBHash.
8
+ class BotRegistry
9
+ def initialize(bot)
10
+ @bot = bot
11
+ upgrade_data
12
+ @db = DBTree.new @bot, "plugin_registry"
13
+ end
14
+
15
+ # delegation hack
16
+ def method_missing(method, *args, &block)
17
+ @db.send(method, *args, &block)
18
+ end
19
+
20
+ # check for older versions of rbot with data formats that require updating
21
+ # NB this function is called _early_ in init(), pretty much all you have to
22
+ # work with is @bot.botclass.
23
+ def upgrade_data
24
+ if File.exist?("#{@bot.botclass}/registry.db")
25
+ puts "upgrading old-style (rbot 0.9.5 or earlier) plugin registry to new format"
26
+ old = BDB::Hash.open "#{@bot.botclass}/registry.db", nil,
27
+ "r+", 0600, "set_pagesize" => 1024,
28
+ "set_cachesize" => [0, 32 * 1024, 0]
29
+ new = BDB::CIBtree.open "#{@bot.botclass}/plugin_registry.db", nil,
30
+ BDB::CREATE | BDB::EXCL | BDB::TRUNCATE,
31
+ 0600, "set_pagesize" => 1024,
32
+ "set_cachesize" => [0, 32 * 1024, 0]
33
+ old.each {|k,v|
34
+ new[k] = v
35
+ }
36
+ old.close
37
+ new.close
38
+ File.delete("#{@bot.botclass}/registry.db")
39
+ end
40
+ end
41
+ end
42
+
43
+ # This class provides persistent storage for plugins via a hash interface.
44
+ # The default mode is an object store, so you can store ruby objects and
45
+ # reference them with hash keys. This is because the default store/restore
46
+ # methods of the plugins' RegistryAccessor are calls to Marshal.dump and
47
+ # Marshal.restore,
48
+ # for example:
49
+ # blah = Hash.new
50
+ # blah[:foo] = "fum"
51
+ # @registry[:blah] = blah
52
+ # then, even after the bot is shut down and disconnected, on the next run you
53
+ # can access the blah object as it was, with:
54
+ # blah = @registry[:blah]
55
+ # The registry can of course be used to store simple strings, fixnums, etc as
56
+ # well, and should be useful to store or cache plugin data or dynamic plugin
57
+ # configuration.
58
+ #
59
+ # WARNING:
60
+ # in object store mode, don't make the mistake of treating it like a live
61
+ # object, e.g. (using the example above)
62
+ # @registry[:blah][:foo] = "flump"
63
+ # will NOT modify the object in the registry - remember that BotRegistry#[]
64
+ # returns a Marshal.restore'd object, the object you just modified in place
65
+ # will disappear. You would need to:
66
+ # blah = @registry[:blah]
67
+ # blah[:foo] = "flump"
68
+ # @registry[:blah] = blah
69
+
70
+ # If you don't need to store objects, and strictly want a persistant hash of
71
+ # strings, you can override the store/restore methods to suit your needs, for
72
+ # example (in your plugin):
73
+ # def initialize
74
+ # class << @registry
75
+ # def store(val)
76
+ # val
77
+ # end
78
+ # def restore(val)
79
+ # val
80
+ # end
81
+ # end
82
+ # end
83
+ # Your plugins section of the registry is private, it has its own namespace
84
+ # (derived from the plugin's class name, so change it and lose your data).
85
+ # Calls to registry.each etc, will only iterate over your namespace.
86
+ class BotRegistryAccessor
87
+ # plugins don't call this - a BotRegistryAccessor is created for them and
88
+ # is accessible via @registry.
89
+ def initialize(bot, prefix)
90
+ @bot = bot
91
+ @registry = @bot.registry
92
+ @orig_prefix = prefix
93
+ @prefix = prefix + "/"
94
+ @default = nil
95
+ # debug "initializing registry accessor with prefix #{@prefix}"
96
+ end
97
+
98
+ # use this to chop up your namespace into bits, so you can keep and
99
+ # reference separate object stores under the same registry
100
+ def sub_registry(prefix)
101
+ return BotRegistryAccessor.new(@bot, @orig_prefix + "+" + prefix)
102
+ end
103
+
104
+ # convert value to string form for storing in the registry
105
+ # defaults to Marshal.dump(val) but you can override this in your module's
106
+ # registry object to use any method you like.
107
+ # For example, if you always just handle strings use:
108
+ # def store(val)
109
+ # val
110
+ # end
111
+ def store(val)
112
+ Marshal.dump(val)
113
+ end
114
+
115
+ # restores object from string form, restore(store(val)) must return val.
116
+ # If you override store, you should override restore to reverse the
117
+ # action.
118
+ # For example, if you always just handle strings use:
119
+ # def restore(val)
120
+ # val
121
+ # end
122
+ def restore(val)
123
+ Marshal.restore(val)
124
+ end
125
+
126
+ # lookup a key in the registry
127
+ def [](key)
128
+ if @registry.has_key?(@prefix + key)
129
+ return restore(@registry[@prefix + key])
130
+ elsif @default != nil
131
+ return restore(@default)
132
+ else
133
+ return nil
134
+ end
135
+ end
136
+
137
+ # set a key in the registry
138
+ def []=(key,value)
139
+ @registry[@prefix + key] = store(value)
140
+ end
141
+
142
+ # set the default value for registry lookups, if the key sought is not
143
+ # found, the default will be returned. The default default (har) is nil.
144
+ def set_default (default)
145
+ @default = store(default)
146
+ end
147
+
148
+ # just like Hash#each
149
+ def each(&block)
150
+ @registry.each {|key,value|
151
+ if key.gsub!(/^#{Regexp.escape(@prefix)}/, "")
152
+ block.call(key, restore(value))
153
+ end
154
+ }
155
+ end
156
+
157
+ # just like Hash#each_key
158
+ def each_key(&block)
159
+ @registry.each {|key, value|
160
+ if key.gsub!(/^#{Regexp.escape(@prefix)}/, "")
161
+ block.call(key)
162
+ end
163
+ }
164
+ end
165
+
166
+ # just like Hash#each_value
167
+ def each_value(&block)
168
+ @registry.each {|key, value|
169
+ if key =~ /^#{Regexp.escape(@prefix)}/
170
+ block.call(restore(value))
171
+ end
172
+ }
173
+ end
174
+
175
+ # just like Hash#has_key?
176
+ def has_key?(key)
177
+ return @registry.has_key?(@prefix + key)
178
+ end
179
+ alias include? has_key?
180
+ alias member? has_key?
181
+
182
+ # just like Hash#has_both?
183
+ def has_both?(key, value)
184
+ return @registry.has_both?(@prefix + key, store(value))
185
+ end
186
+
187
+ # just like Hash#has_value?
188
+ def has_value?(value)
189
+ return @registry.has_value?(store(value))
190
+ end
191
+
192
+ # just like Hash#index?
193
+ def index(value)
194
+ ind = @registry.index(store(value))
195
+ if ind && ind.gsub!(/^#{Regexp.escape(@prefix)}/, "")
196
+ return ind
197
+ else
198
+ return nil
199
+ end
200
+ end
201
+
202
+ # delete a key from the registry
203
+ def delete(key)
204
+ return @registry.delete(@prefix + key)
205
+ end
206
+
207
+ # returns a list of your keys
208
+ def keys
209
+ return @registry.keys.collect {|key|
210
+ if key.gsub!(/^#{Regexp.escape(@prefix)}/, "")
211
+ key
212
+ else
213
+ nil
214
+ end
215
+ }.compact
216
+ end
217
+
218
+ # Return an array of all associations [key, value] in your namespace
219
+ def to_a
220
+ ret = Array.new
221
+ @registry.each {|key, value|
222
+ if key.gsub!(/^#{Regexp.escape(@prefix)}/, "")
223
+ ret << [key, restore(value)]
224
+ end
225
+ }
226
+ return ret
227
+ end
228
+
229
+ # Return an hash of all associations {key => value} in your namespace
230
+ def to_hash
231
+ ret = Hash.new
232
+ @registry.each {|key, value|
233
+ if key.gsub!(/^#{Regexp.escape(@prefix)}/, "")
234
+ ret[key] = restore(value)
235
+ end
236
+ }
237
+ return ret
238
+ end
239
+
240
+ # empties the registry (restricted to your namespace)
241
+ def clear
242
+ @registry.each_key {|key|
243
+ if key =~ /^#{Regexp.escape(@prefix)}/
244
+ @registry.delete(key)
245
+ end
246
+ }
247
+ end
248
+ alias truncate clear
249
+
250
+ # returns an array of the values in your namespace of the registry
251
+ def values
252
+ ret = Array.new
253
+ self.each {|k,v|
254
+ ret << restore(v)
255
+ }
256
+ return ret
257
+ end
258
+
259
+ # returns the number of keys in your registry namespace
260
+ def length
261
+ self.keys.length
262
+ end
263
+ alias size length
264
+
265
+ def flush
266
+ @registry.flush
267
+ end
268
+
269
+ end
270
+
271
+ end