Auto 4.0.0.alpha.1-x86-mingw32

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 (65) hide show
  1. data/.yardopts +7 -0
  2. data/Gemfile +19 -0
  3. data/LICENSE.md +31 -0
  4. data/README.md +109 -0
  5. data/Rakefile +41 -0
  6. data/bin/auto +110 -0
  7. data/bin/auto-conf +45 -0
  8. data/conf/example.json +100 -0
  9. data/conf/example.yml +125 -0
  10. data/docs/Contributing.md +77 -0
  11. data/docs/Events.md +103 -0
  12. data/docs/Todo.md +21 -0
  13. data/docs/Upgrade.md +16 -0
  14. data/ext/dsl_base.c +49 -0
  15. data/ext/libauto/auto.h +20 -0
  16. data/ext/libauto/extconf.rb +16 -0
  17. data/ext/libauto/libauto.c +29 -0
  18. data/ext/libauto/libauto.h +28 -0
  19. data/ext/libauto/logger.c +177 -0
  20. data/ext/libauto/logger.h +44 -0
  21. data/lib/auto.rb +43 -0
  22. data/lib/auto/api.rb +7 -0
  23. data/lib/auto/api/events.rb +166 -0
  24. data/lib/auto/api/object.rb +29 -0
  25. data/lib/auto/api/plugin.rb +155 -0
  26. data/lib/auto/api/timers.rb +93 -0
  27. data/lib/auto/bot.rb +338 -0
  28. data/lib/auto/config.rb +181 -0
  29. data/lib/auto/configure.rb +410 -0
  30. data/lib/auto/configure/shell.rb +154 -0
  31. data/lib/auto/dsl/base.rb +74 -0
  32. data/lib/auto/dsl/irc.rb +13 -0
  33. data/lib/auto/irc.rb +8 -0
  34. data/lib/auto/irc/common.rb +63 -0
  35. data/lib/auto/irc/library.rb +89 -0
  36. data/lib/auto/irc/object/channel.rb +21 -0
  37. data/lib/auto/irc/object/entity.rb +90 -0
  38. data/lib/auto/irc/object/message.rb +99 -0
  39. data/lib/auto/irc/object/user.rb +139 -0
  40. data/lib/auto/irc/protocol.rb +164 -0
  41. data/lib/auto/irc/protocol/numerics.rb +60 -0
  42. data/lib/auto/irc/sasl/diffie_hellman.rb +36 -0
  43. data/lib/auto/irc/sasl/mech.rb +15 -0
  44. data/lib/auto/irc/sasl/mech/dh_blowfish.rb +83 -0
  45. data/lib/auto/irc/sasl/mech/plain.rb +39 -0
  46. data/lib/auto/irc/server.rb +301 -0
  47. data/lib/auto/irc/state/channel_manager.rb +6 -0
  48. data/lib/auto/irc/state/support.rb +142 -0
  49. data/lib/auto/irc/state/user_manager.rb +6 -0
  50. data/lib/auto/irc/std/commands.rb +99 -0
  51. data/lib/auto/irc/std/numerics.rb +216 -0
  52. data/lib/auto/rubyext/integer.rb +25 -0
  53. data/lib/auto/rubyext/string.rb +10 -0
  54. data/lib/auto/version.rb +18 -0
  55. data/lib/libauto.so +0 -0
  56. data/spec/api_events_spec.rb +68 -0
  57. data/spec/config_json_spec.rb +116 -0
  58. data/spec/config_other_spec.rb +29 -0
  59. data/spec/config_yaml_spec.rb +136 -0
  60. data/spec/helper.rb +19 -0
  61. data/spec/irc_object_entity_spec.rb +51 -0
  62. data/spec/logger_spec.rb +30 -0
  63. data/spec/plugin_base_spec.rb +35 -0
  64. data/spec/timers_spec.rb +42 -0
  65. metadata +238 -0
@@ -0,0 +1,29 @@
1
+ # Copyright (c) 2013, Autumn Perrault, et al. All rights reserved.
2
+ # This free software is distributed under the FreeBSD license (LICENSE.md).
3
+
4
+ # Namespace: Auto
5
+ module Auto
6
+
7
+ # Namespace: API
8
+ module API
9
+
10
+ # A superclass for {Auto::API::Timers} and {Auto::API::Events}.
11
+ class Object
12
+
13
+ private
14
+
15
+ # Get a random character.
16
+ #
17
+ # @return [String] A random character.
18
+ def get_rand_char
19
+ chrs = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".split(//)
20
+ chrs[rand(chrs.length)]
21
+ end
22
+
23
+ end # class Object
24
+
25
+ end # module API
26
+
27
+ end # module Auto
28
+
29
+ # vim: set ts=4 sts=2 sw=2 et:
@@ -0,0 +1,155 @@
1
+ # Copyright (c) 2013, Autumn Perrault, et al. All rights reserved.
2
+ # This free software is distributed under the FreeBSD license (LICENSE.md).
3
+
4
+ require 'ostruct'
5
+ require 'libauto'
6
+ require 'auto/bot'
7
+
8
+ module Auto
9
+
10
+ module API
11
+
12
+ # A basic superclass for plugins.
13
+ #
14
+ # @api Auto
15
+ # @since 4.0.0
16
+ # @author noxgirl
17
+ # @author swarley
18
+ #
19
+ # @!attribute [r] name
20
+ # @return [String] Name of the plugin.
21
+ #
22
+ # @!attribute [r] summary
23
+ # @return [String] Summary of the plugin.
24
+ #
25
+ # @!attribute [r] version
26
+ # @return [String] Version of the plugin.
27
+ #
28
+ # @!attribute [r] library
29
+ # @return [String] The library upon which the plugin is based.
30
+ #
31
+ # @!attribute [r] author
32
+ # @return [String] Author of the plugin.
33
+ #
34
+ # @!attribute [r] auto
35
+ # @return [String] Version of Auto required by the plugin.
36
+ class Plugin
37
+
38
+ attr_reader :name, :summary, :version, :library, :author, :auto
39
+
40
+ # Configure the plugin.
41
+ #
42
+ # @yieldparam [OpenStruct] conf Configuration structure.
43
+ #
44
+ # - +conf.name+: Name of the plugin (String).
45
+ # - +conf.summary+: Summary of the plugin (String).
46
+ # - +conf.version+: Version of the plugin (String).
47
+ # - +conf.library+: Library upon which the plugin is based. (String).
48
+ # - +conf.author+: Author of the plugin (String).
49
+ # - +conf.auto+: Required version of Auto (String). Should be in the format of
50
+ # +'~> version'+ or +'>= version'+. +~>+ means at least +version+ but no later
51
+ # than the minor version (e.g. +'~> 4.0'+ will allow +4.0.2+ but not +4.1.0+).
52
+ # +>=+ means at at least +version+.
53
+ #
54
+ # Additionally, it should be noted that +conf.library+ should be either of the
55
+ # core libraries, *or* 'multi' if it uses multiple libraries.
56
+ #
57
+ # @example
58
+ # configure do |c|
59
+ # c.name = 'MagicPlugin'
60
+ # c.summary = 'A magical extension.'
61
+ # c.version = '1.00'
62
+ # c.library = 'irc'
63
+ # c.author = 'noxgirl'
64
+ # c.auto = '~> 4.0'
65
+ # end
66
+ def configure
67
+
68
+ # Prepare an open structure.
69
+ conf = OpenStruct.new
70
+
71
+ # Yield it to the configuration block.
72
+ yield conf if block_given?
73
+
74
+ # Check for sufficient configuration.
75
+ [:name,:summary,:version,:library,:author,:auto].each do |s|
76
+ if conf.send(s).nil?
77
+ raise PluginError, "Plugin #{self.inspect} provided insufficient configuration (#{s} is nil)."
78
+ end
79
+ end
80
+
81
+ @name = conf.name
82
+ @summary = conf.summary
83
+ @version = conf.version
84
+ @library = conf.library
85
+ @author = conf.author
86
+
87
+ # Check for compatibility.
88
+ if conf.auto =~ /^(~>\s*)((?:[\dabcr])(?:\.[\dabcr]))+$/ # ~>
89
+
90
+ ver = $2
91
+ if Gem::Version.new(ver.dup) >= Gem::Version.new(Auto::VERSION.dup) # must be later than or equal to current
92
+
93
+ # Split current version and plugin-demanded version by '.'.
94
+ verarr = Auto::VERSION.split(/\./)
95
+ pverarr = ver.split(/\./)
96
+
97
+ # Must be no later than the current minor version
98
+ unless verarr[1] <= pverarr[1]
99
+ raise PluginError, "Plugin #@name v#@version demands Auto #{conf.auto}; current version is #{Auto::VERSION}. Incompatible! Aborting load!"
100
+ end
101
+
102
+ @auto = conf.auto
103
+
104
+ else
105
+ raise PluginError, "Plugin #@name v#@version demands Auto #{conf.auto}; current version is #{Auto::VERSION}. Incompatible! Aborting load!"
106
+ end # if ver >=
107
+
108
+ elsif conf.auto =~ /^(>=\s*)((?:[\dabcr])(?:\.[\dabcr]))+$/ # >=
109
+
110
+ ver = $2
111
+ unless ver >= Auto::VERSION # must be later than or equal to current
112
+ raise PluginError, "Plugin #@name v#@version demands Auto #{conf.auto}; current version is #{Auto::VERSION}. Incompatible! Aborting load!"
113
+ end
114
+
115
+ @auto = conf.auto
116
+
117
+ else
118
+ raise PluginError, "Plugin #@name v#@version cannot be checked for compatibility. Aborting load!"
119
+ end # compat check
120
+
121
+ # If we've made it this far, it's sufficiently compatible with the API.
122
+ # Now, we need to extend this plugin with our domain-specific language (DSL).
123
+ self.extend Auto::DSL::Base # this is the base
124
+ case @library
125
+
126
+ when 'irc'
127
+ self.extend Auto::DSL::IRC
128
+ when 'multi'
129
+ # the specifications for multilib DSL functionality are yet undecided
130
+ else
131
+ # If it's a library we don't comprehend, exception time, it is.
132
+ raise PluginError, "Plugin #@name v#@version demands '#{@library}' library, which I do not understand. Aborting load!"
133
+
134
+ end
135
+
136
+ end # def configure
137
+
138
+ #########
139
+ protected
140
+ #########
141
+
142
+ # Inheritance event.
143
+ #
144
+ # @param [Class] subklass The subclass which has inherited {self}.
145
+ def self.inherited(subklass)
146
+ $m.debug("[plugin] Auto::API::Plugin inherited by #{subklass}")
147
+ end
148
+
149
+ end # class Plugin
150
+
151
+ end # module API
152
+
153
+ end # module Auto
154
+
155
+ # vim: set ts=4 sts=2 sw=2 et:
@@ -0,0 +1,93 @@
1
+ # Copyright (c) 2013, Autumn Perrault, et al. All rights reserved.
2
+ # This free software is distributed under the FreeBSD license (LICENSE.md).
3
+
4
+ require 'thread'
5
+
6
+ # Entering namespace: Auto
7
+ module Auto
8
+
9
+ # Entering namespace: API
10
+ module API
11
+
12
+ # A simple class which provides the API a fundamental timer system, based on
13
+ # threading.
14
+ #
15
+ # @api Auto
16
+ # @since 4.0.0
17
+ # @author noxgirl
18
+ #
19
+ # @!attribute [r] timers
20
+ # @return [Hash{String => Thread}] List of threads.
21
+ #
22
+ # @see Auto::API::Helper::Timers
23
+ class Timers < Auto::API::Object
24
+
25
+ attr_reader :timers
26
+
27
+ # Create a new instance of Auto::API::Timers.
28
+ def initialize
29
+ @timers = {}
30
+ end
31
+
32
+ # Spawn a new timer.
33
+ #
34
+ # @param [Integer] time Number of seconds before this is executed, or in between executions.
35
+ # @param [Symbol] type Either +:once+ to execute a timer once and destroy it, or +:every+
36
+ # to repeat.
37
+ # @param [Array<>] args An array of arguments which to pass to the block when executed. (splat)
38
+ #
39
+ # @yield [...] The arguments which were provided in the timer's creation.
40
+ #
41
+ # @return [String] A unique identification string representing the timer. Useful if you wish
42
+ # to terminate it in the future.
43
+ #
44
+ # @example
45
+ # => timer = timers.spawn(15, :once, 'cow') { |animal| puts animal }
46
+ # # after 15 seconds...
47
+ # 'cow'
48
+ #
49
+ # @see Auto::API::Helper::Timers#clock_do
50
+ def spawn(time, type, *args, &cb)
51
+
52
+ # Generate a unique ID for this timer.
53
+ id = ''
54
+ 10.times { id += get_rand_char }
55
+ while @timers.has_key? id
56
+ id = ''
57
+ 10.times { id += get_rand_char }
58
+ end
59
+
60
+ # Create a new thread containing the timer.
61
+ if type == :once
62
+ @timers[id] = Thread.new { sleep time; cb.call(*args) }
63
+ elsif type == :every
64
+ @timers[id] = Thread.new { loop { sleep time; cb.call(*args) } }
65
+ else
66
+ return
67
+ end
68
+
69
+ id
70
+
71
+ end
72
+
73
+ # Delete a timer.
74
+ #
75
+ # @param [String] id The unique identification string of the timer, as provided
76
+ # by {#spawn}.
77
+ #
78
+ # @see Auto::API::Helper::Timers#clock_stop
79
+ def del(id)
80
+ # Does the timer exist?
81
+ if @timers.has_key? id
82
+ @timers[id].kill
83
+ @timers.delete id
84
+ end
85
+ end
86
+
87
+ end # class Timers
88
+
89
+ end # module API
90
+
91
+ end # module Auto
92
+
93
+ # vim: set ts=4 sts=2 sw=2 et:
@@ -0,0 +1,338 @@
1
+ # Copyright (c) 2013, Autumn Perrault, et al. All rights reserved.
2
+ # This free software is distributed under the FreeBSD license (LICENSE.md).
3
+
4
+ require 'colored'
5
+ require 'sequel'
6
+
7
+ require 'auto/config'
8
+
9
+ require 'auto/api'
10
+
11
+ # Namespace: Auto
12
+ module Auto
13
+
14
+ # This is the central class of Auto, providing all core functionality.
15
+ #
16
+ # It should be additionally noted that for each loaded core library, a readable
17
+ # instance attribute of the library's name will exist, typically pointing to
18
+ # an instance of its respective Library class. (e.g. @irc = <Auto::IRC::Library>)
19
+ #
20
+ # @!attribute [r] opts
21
+ # @return [Slop] The options object.
22
+ #
23
+ #
24
+ # @!attribute [r] log
25
+ # @return [Auto::Logger] The logging instance.
26
+ #
27
+ # @!attribute [r] conf
28
+ # @return [Auto::Config] The configuration instance.
29
+ #
30
+ # @!attribute [r] events
31
+ # @return [Auto::API::Events] The event system instance.
32
+ #
33
+ # @!attribute [r] clock
34
+ # @return [Auto::API::Timers] The timer system instance.
35
+ #
36
+ # @!attribute [r] db
37
+ # @return [Sequel::SQLite::Database] If the database is SQLite (note: all
38
+ # adapted databases are subclasses of Sequel::Database).
39
+ # @return [Sequel::MySQL::Database] If the database is MySQL (note: all
40
+ # adapted databases are subclasses of Sequel::Database).
41
+ # @return [Sequel::Postgres::Database] If the database is PostgreSQL (note: all
42
+ # adapted databases are subclasses of Sequel::Database).
43
+ #
44
+ # @!attribute [r] libs
45
+ # @return [Array<String>] List of loaded core libraries.
46
+ #
47
+ # @!attribute [r] netloop
48
+ # @return [Thread] The thread in which #main_loop is running.
49
+ #
50
+ # @!attribute [r] sockets
51
+ # @return [Array<Object>] A list of socket objects.
52
+ class Bot
53
+
54
+ attr_reader :opts, :log, :conf, :events, :clock, :db, :libs, :netloop, :sockets
55
+
56
+ # Create a new instance of Auto.
57
+ #
58
+ # @param [Hash{String => Object}] opts A hash of options.
59
+ def initialize opts
60
+ # Save options.
61
+ @opts = opts
62
+
63
+ # Move to ~/.config/autobot if we're a gem.
64
+ if Auto.gem?
65
+ Dir.mkdir File.join(Dir.home, '.config') if !Dir.exists? File.join(Dir.home, '.config')
66
+ Dir.mkdir File.join(Dir.home, '.config', 'autobot') if !Dir.exists? File.join(Dir.home, '.config', 'autobot')
67
+ Dir.chdir File.join(Dir.home, '.config', 'autobot')
68
+ end
69
+ end
70
+
71
+ # Initialize this instance.
72
+ def init
73
+
74
+ # Before anything else, start logging.
75
+ puts '* Starting logging...'.bold
76
+ @log = Auto::Logger.new
77
+ @log.info("Logging started at #{Time.now}")
78
+
79
+ # Load configuration
80
+ load_config
81
+
82
+ # Initialize the central event system
83
+ puts '* Starting the central event system...'.bold
84
+ @log.info("Starting the central event system...")
85
+ @events = Auto::API::Events.new
86
+
87
+ # Start the timer system.
88
+ puts '* Starting the timer system...'.bold
89
+ @log.info("Starting the timer system...")
90
+ @clock = Auto::API::Timers.new
91
+
92
+ # Prepare for sockets.
93
+ @sockets = []
94
+
95
+ # Initialize the database
96
+ load_database
97
+
98
+ # Load core libraries.
99
+ load_libraries
100
+
101
+ true
102
+ end
103
+
104
+ # Start the bot.
105
+ def start
106
+
107
+ # Call the start event.
108
+ @events.call :start
109
+
110
+ # Throw the program into the main loop.
111
+ @events.threads.each { |thr| thr.join } # block until we're ready to go
112
+ debug("Producing a thread and entering the main loop...") if @opts.verbose?
113
+ @netloop = Thread.new { main_loop }
114
+ @netloop.join
115
+
116
+ end
117
+
118
+ # Main loop.
119
+ def main_loop
120
+ loop do
121
+ # Build a list of sockets.
122
+ sockets = []
123
+ assoc_objects = {}
124
+ @sockets.each do |o|
125
+ unless o.socket.nil? or o.socket.closed?
126
+ sockets << o.socket
127
+ assoc_objects[o.socket] = o
128
+ end
129
+ end
130
+ next if sockets.empty?
131
+
132
+ # Call #select.
133
+ ready_read, _, _ = IO.select(sockets, [], [], nil)
134
+
135
+ # Iterate through sockets ready for reading.
136
+ ready_read.each do |socket|
137
+ @events.call :net_receive, assoc_objects[socket]
138
+ end
139
+ end
140
+ end
141
+
142
+ # Produce an error message.
143
+ #
144
+ # @param [String] msg The message.
145
+ # @param [true, false] fatal Whether this error is fatal (will kill the program).
146
+ # @param [Array<String>] bt Backtrace.
147
+ def error msg, fatal = false, bt = nil
148
+ # Print it to STDERR.
149
+ STDERR.puts "ERROR: #{msg}".red
150
+ unless bt.nil?
151
+ STDERR.puts "Backtrace:"
152
+ STDERR.puts bt
153
+ end
154
+
155
+ # Log it.
156
+ @log.error(msg)
157
+
158
+ if fatal
159
+ #@netloop.kill if @netloop.active
160
+ exit 1
161
+ end
162
+ end
163
+
164
+ # Produce a warning message.
165
+ #
166
+ # @param [String] msg The message.
167
+ def warn msg
168
+ # Log it.
169
+ @log.warning(msg)
170
+
171
+ # Foreground it.
172
+ foreground("Warning: #{msg}".red, false)
173
+ end
174
+
175
+ # Produce information.
176
+ #
177
+ # @param [String] msg The message.
178
+ def info msg
179
+ @log.info(msg)
180
+ foreground(">>> #{msg}".green, false)
181
+ end
182
+
183
+ # Produce a message for foreground mode.
184
+ #
185
+ # @param [String] msg The message.
186
+ # @param [true, false] log Whether to log it as well as print to STDOUT.
187
+ def foreground msg, log = true
188
+ if @opts.foreground?
189
+ puts "[F] #{msg}"
190
+ @log.info("[F] #{msg}") if log
191
+ else
192
+ if @opts.debug?
193
+ debug(msg, log)
194
+ end
195
+ end
196
+ end
197
+
198
+ # Produce a debug message.
199
+ #
200
+ # @param [String] msg The message.
201
+ # @param [true, false] log Whether to log it as well as print to STDOUT.
202
+ def debug msg, log = false
203
+ if @opts.debug?
204
+ puts "[D] #{msg}".blue
205
+ @log.debug(msg) if log
206
+ end
207
+ end
208
+
209
+ # Terminate the bot.
210
+ #
211
+ # @param [String] reason The reason for termination.
212
+ def terminate reason = 'Terminating'
213
+ info("Auto is terminating owing to thus: #{reason}")
214
+
215
+ # Call :die
216
+ @events.call :die, reason
217
+
218
+ # Close the database.
219
+ @db.disconnect
220
+
221
+ # When dying, allow about three seconds for hooks to execute before
222
+ # fully terminating.
223
+ sleep 3
224
+
225
+ # Delete auto.pid
226
+ unless @opts.debug? or @opts.foreground?
227
+ File.delete('auto.pid')
228
+ end
229
+
230
+ exit 0
231
+ end
232
+
233
+ #######
234
+ private
235
+ #######
236
+
237
+ # Load the configuration.
238
+ def load_config
239
+
240
+ # Try to find the file
241
+ # conf/ is given precedence over ~/.config/autobot/
242
+ # unless we're installed as a gem, in which case conf/ is ignored
243
+ confpath = nil
244
+ if @opts.json?
245
+ if File.exists? File.join(%w[conf auto.json]) and !Auto.gem?
246
+ confpath = File.join(%w[conf auto.json])
247
+ elsif File.exists? File.join(Dir.home, '.config', 'autobot', 'auto.json')
248
+ confpath = File.join(Dir.home, '.config', 'autobot', 'auto.json')
249
+ end
250
+ else
251
+ if File.exists? File.join(%w[conf auto.yml]) and !Auto.gem?
252
+ confpath = File.join(%w[conf auto.yml])
253
+ elsif File.exists? File.join(Dir.home, '.config', 'autobot', 'auto.yml')
254
+ confpath = File.join(Dir.home, '.config', 'autobot', 'auto.yml')
255
+ end
256
+ end
257
+ confpath = @opts[:conf] if @opts.conf? # --conf=FILE has supreme precedence
258
+ error('Could not find a configuration file', true) if confpath.nil?
259
+
260
+ # Process it.
261
+ puts "* Reading the configuration file #{confpath}...".bold
262
+ @log.info("Reading the configuration file #{confpath}...")
263
+ @conf = Auto::Config.new(File.expand_path(confpath))
264
+
265
+ end
266
+
267
+ # Load Auto libraries.
268
+ def load_libraries
269
+
270
+ puts '* Loading core libraries..'.bold
271
+ @log.info("Loading core libraries...")
272
+ @libs = []
273
+
274
+ # Iterate through each configured library.
275
+ @conf['libraries'].each do |lib|
276
+ lib.dc!
277
+
278
+ if @libs.include? lib
279
+ # Don't load a library more than once!
280
+ error("Cannot load library twice (#{lib})! Please fix your configuration.")
281
+ next
282
+ end
283
+
284
+ begin
285
+ # here is where magic occurs to load a library
286
+ require "auto/#{lib}"
287
+ instance_variable_set "@#{lib}".to_sym, Object.const_get("LIBRARY_#{lib.uc}")
288
+ define_singleton_method(lib.to_sym) { self.instance_variable_get("@#{__method__}".to_sym) }
289
+ @libs.push lib
290
+ rescue => e
291
+ error "Failed to load core library '#{lib}': #{e}", true, e.backtrace
292
+ end
293
+
294
+ end
295
+
296
+ end
297
+
298
+ # Load database.
299
+ def load_database
300
+
301
+ puts '* Initializing database...'.bold
302
+ @log.info('Initializing database...')
303
+ @db = nil
304
+
305
+ case @conf['database']['type'] # check the database type in the config
306
+
307
+ when 'sqlite' # it's SQLite
308
+
309
+ name = @conf['database']['name'] || 'auto.db'
310
+ @db = Sequel.sqlite(name)
311
+
312
+ when 'mysql', 'postgres' # for MySQL and Postgres
313
+
314
+ %[username password hostname name].each do |d|
315
+ unless @conf['database'].include? d
316
+ raise DatabaseError, "Insufficient configuration. For MySQL and PostgreSQL, we need the username, password, hostname, and name directives."
317
+ end
318
+ end
319
+
320
+ adapter = @conf['database']['type'].to_sym
321
+
322
+ @db = Sequel.connect(:adapter => adapter,
323
+ :host => @conf['database']['hostname'],
324
+ :database => @conf['database']['name'],
325
+ :user => @conf['database']['username'],
326
+ :password => @conf['database']['passname'])
327
+
328
+ else
329
+ raise DatabaseError, "Unrecognized database type: #{@conf['database']['type']}"
330
+ end
331
+
332
+ end
333
+
334
+ end # class Bot
335
+
336
+ end # module Auto
337
+
338
+ # vim: set ts=4 sts=2 sw=2 et: