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.
- data/AUTHORS +16 -0
- data/COPYING +21 -0
- data/ChangeLog +418 -0
- data/INSTALL +8 -0
- data/README +44 -0
- data/REQUIREMENTS +34 -0
- data/TODO +5 -0
- data/Usage_en.txt +129 -0
- data/bin/rbot +81 -0
- data/data/rbot/contrib/plugins/figlet.rb +20 -0
- data/data/rbot/contrib/plugins/ri.rb +83 -0
- data/data/rbot/contrib/plugins/stats.rb +232 -0
- data/data/rbot/contrib/plugins/vandale.rb +49 -0
- data/data/rbot/languages/dutch.lang +73 -0
- data/data/rbot/languages/english.lang +75 -0
- data/data/rbot/languages/french.lang +39 -0
- data/data/rbot/languages/german.lang +67 -0
- data/data/rbot/plugins/autoop.rb +68 -0
- data/data/rbot/plugins/autorejoin.rb +16 -0
- data/data/rbot/plugins/cal.rb +15 -0
- data/data/rbot/plugins/dice.rb +81 -0
- data/data/rbot/plugins/eightball.rb +19 -0
- data/data/rbot/plugins/excuse.rb +470 -0
- data/data/rbot/plugins/fish.rb +61 -0
- data/data/rbot/plugins/fortune.rb +22 -0
- data/data/rbot/plugins/freshmeat.rb +98 -0
- data/data/rbot/plugins/google.rb +51 -0
- data/data/rbot/plugins/host.rb +14 -0
- data/data/rbot/plugins/httpd.rb.disabled +35 -0
- data/data/rbot/plugins/insult.rb +258 -0
- data/data/rbot/plugins/karma.rb +85 -0
- data/data/rbot/plugins/lart.rb +181 -0
- data/data/rbot/plugins/math.rb +122 -0
- data/data/rbot/plugins/nickserv.rb +89 -0
- data/data/rbot/plugins/nslookup.rb +43 -0
- data/data/rbot/plugins/opme.rb +19 -0
- data/data/rbot/plugins/quakeauth.rb +51 -0
- data/data/rbot/plugins/quotes.rb +321 -0
- data/data/rbot/plugins/remind.rb +228 -0
- data/data/rbot/plugins/roshambo.rb +54 -0
- data/data/rbot/plugins/rot13.rb +10 -0
- data/data/rbot/plugins/roulette.rb +147 -0
- data/data/rbot/plugins/rss.rb.disabled +414 -0
- data/data/rbot/plugins/seen.rb +89 -0
- data/data/rbot/plugins/slashdot.rb +94 -0
- data/data/rbot/plugins/spell.rb +36 -0
- data/data/rbot/plugins/tube.rb +71 -0
- data/data/rbot/plugins/url.rb +88 -0
- data/data/rbot/plugins/weather.rb +649 -0
- data/data/rbot/plugins/wserver.rb +71 -0
- data/data/rbot/plugins/xmlrpc.rb.disabled +52 -0
- data/data/rbot/templates/keywords.rbot +4 -0
- data/data/rbot/templates/lart/larts +98 -0
- data/data/rbot/templates/lart/praises +5 -0
- data/data/rbot/templates/levels.rbot +30 -0
- data/data/rbot/templates/users.rbot +1 -0
- data/lib/rbot/auth.rb +203 -0
- data/lib/rbot/channel.rb +54 -0
- data/lib/rbot/config.rb +363 -0
- data/lib/rbot/dbhash.rb +112 -0
- data/lib/rbot/httputil.rb +141 -0
- data/lib/rbot/ircbot.rb +808 -0
- data/lib/rbot/ircsocket.rb +185 -0
- data/lib/rbot/keywords.rb +433 -0
- data/lib/rbot/language.rb +69 -0
- data/lib/rbot/message.rb +256 -0
- data/lib/rbot/messagemapper.rb +262 -0
- data/lib/rbot/plugins.rb +291 -0
- data/lib/rbot/post-install.rb +8 -0
- data/lib/rbot/rbotconfig.rb +36 -0
- data/lib/rbot/registry.rb +271 -0
- data/lib/rbot/rfc2812.rb +1104 -0
- data/lib/rbot/timer.rb +201 -0
- data/lib/rbot/utils.rb +83 -0
- data/setup.rb +1360 -0
- metadata +129 -0
data/lib/rbot/plugins.rb
ADDED
@@ -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,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
|