"...the number of BeerBot installations has grown to 1, with more expected..." -- BeerBot Labs
BeerBot is an irc bot written in ruby 2.0 and some bits of thread.
- Uses ruby 2.0
- includes IRC
- Structured to be independent of IRC, the bot itself is agnostic
- you know, if you want to make BeerBot do xmpp, please do so and let me know :D
- Uses pry as a repl for administering the bot while running
- Contains a scheduler based on
CronR
gem; this should make it easy to get BeerBot to do recurring tasks like reminders
I wrote it partly in frustration with another ruby irc bot and partly for an internal irc server.
- Started building this in the last week of 27-Nov-2013 .
- Be careful about using this on a public network.
BeerBot will run and connect to an irc server out of the box but not much else.
A bunch of useful modules can be found here:
- https://github.com/danielbush/beerbot-modules and follow the instructions.
- And there's a slightly dodgey tutorial below as well
This version of beerbot is 0.2.x and should work with similarly versioned bot modules. Look for similar/matching tags/branches in the beerbot-modules git repo :).
lib/
contains the core bot codeconf/
example configuration file here; some settings are mandatory, take a look at itbin/
containsbeerbot-run-irc.rb
Install the gem
gem install 'beerbot'
type beerbot-run-irc.rb
# => beerbot-run-irc.rb is hashed (/home/danb/.rvm/gems/ruby-2.0.0-p247/bin/beerbot-run-irc.rb)
Or, if you want the code...
Git clone this code (using your git-fu).
Then do bundle install
.
First, take a look at the example configuration file in conf/
.
Hopefully that is mostly self-explanatory.
You want something like this:
cd somewhere
mkdir beerbot
mkdir beerbot/conf
mkdir beerbot/code
mkdir beerbot/data
mkdir beerbot/modules
where...
- conf/
- Put your conf file(s) in here
- code/
- Bot code can go here (if you're cloning from here, not using the gem)
- modules/
- This is the
moduledir
in conf. - Your 'modules' config should point to zero or more modules in this dir. Get your own set of bot modules: git clone https://github.com/danielbush/beerbot-modules.git modules
- This is the
- data/
- This is the
datadir
in conf. - It can be used to store data generated by your modules,
see
BeerBot::Config#module_data
.
- This is the
If you installed the gem, with a bit of luck, all you need to do (once you've done the above preparatory stuff) is...
beerbot-run-irc.rb path/to/conf.json
Your path/to/conf.json
should be a json file that specifies
things like a moduledir
and a datadir
and some other
things - see conf/
for example.
If you're working with the code (not a gem), then you'll probably want to do something like this:
ruby -Ip/t/b/lib p/t/b/bin/beerbot-run-irc.rb path/to/conf.json
where p/t/b = path/to/beerbot
The -I will force 'require' used in the modules and possibly elsewhere to use the code-based beerbot and not the gem if you installed it. (If you don't, you may get "constant already defined" errors.
You should see some irc lines whizz by on your terminal.
Amongst these you should see some some scary numbers like 001
(that means the irc server likes the cut of our gib), and 353
/
366
... you'll get those if you specified any channels in your
conf
that beerbot will have joined.
Yeh, repl is cool. Way cool. If you got beerbot running, you already have one once those lines go whizzing by. Hit enter a couple of times and you should see the pry repl prompt
pry>
Before you go too much further, it's a bit of a pain, using the repl when every now and then a bunch of stuff gets logged into there too. So do this:
pry> echo
=> false # suppress other logging
pry> echo
=> true # unsuppress
Pry is running inside the BeerBot::Kernel class in lib/kernel.rb . There are some convenience methods in this class for making the bot do things.
pry> join '#chan1'
pry> say '#chan1','howdy!'
pry> action '#chan1','departs the channel hastily'
pry> leave '#chan1'
You get the idea.
Try typing:
pry> @scheduler
pry> @bot
pry> @config
pry> @conn
pry> @conn.connection.closed?
Note, that @bot
is just an array of bot modules. Neat.
Those are the bot modules that beerbot will run when responding
to commands, overhearing messages / actions or receiving events.
@scheduler
is an instance of CronR::Cron
which is also an array. You can add jobs to it from this repl if you feel so inclined. See the CronR
gem.
pry> @scheduler.time
... will give you the current time for the configured timezone you have. See the CronR documentation.
On irc, the cmd_prefix
you specified in your conf
can be used as a shortcut to address the bot.
You can say:
beerbot: help
or just
,help
where ,
is the cmd_prefix
.
If you do this on a channel, beerbot will tell you that it is messaging you directly with help.
pry> @bot
should give you access to the core of the bot.
It's an array of BeerBot::BotModule instances which are just hashes (h). h[:mod] should reference the actual bot module.
Ok, so to give you a taste, try this:
pry> mod = Object.new
pry> def mod.cmd msg,**kargs; [to:kargs[:to],msg:"yo"]; end
pry> @bot.push({mod:mod,status:true})
Now, say something to the bot in irc:
irc> ,yo
beerbot> yo
Or on the repl:
pry> @bot.cmd 'hey!'
pry> [{:to=>nil, :msg=>"yo"}]
No irc here. None whatsoever.
Cool no?
Ordinarily, modules are loaded from files using a particular format, but here we just dynamically put one in.
You'll be wanting to be head over to
https://github.com/danielbush/beerbot-modules .
There you will learn the gentle art of beerbot.
There are several different bot methods you'll need to know about
besides cmd
eg hear
, event
etc
Alright. Advanced topic here. Because we just showed you how to create a rudimentary bot mod on the fly in the above section, we're gonna show you how to suppress that.
pry> @bot.set_cmd{nil}
Now try talking to the bot.
To get it back:
pry> @bot.set_cmd
So what's the point of that?
Well, if you want to suppress beerbot's normal set of responses as dictated by the modules loaded in @bot, then, well, this is what you want to do.
What you're really doing is setting another module.
pry> mod2 = Object.new
pry> def mod2.cmd msg,**kargs; [to:kargs[:to],msg:"yarp!"]; end
pry> @bot.set_cmd{|msg,**kargs|mod2.cmd(msg,**kargs)}
pry> @bot.set_cmd # to revert to normal functioning
See?
Or how about, suppress normal beerbot function, and then get him to do something else:
pry> @bot.set_cmd {nil}
pry> ann = lambda {
@config.out << [to:'#chan1',msg:"This is an announcement..."]
sleep 1.5
@config.out << [to:'#chan1',action:"starts drum roll ..."]
sleep 2.5
@config.out << [to:'#chan1',msg:"I'm not sentient!"]
}
pry> ann.call
pry> @bot.set_cmd
The bit after the '<<' is what we'll call a botmsg
.
We could have also said:
@config.out << {to:'#chan1',msg:"This is an announcement..."}
A botmsg is a hash, usually with to
and msg
keys.
But it can be an array of these, and arrays allow us to
return several lines.
Also, it can be a Proc
that returns either of the above.
Actually, since we're in the pry repl, we have access to BeerBot's writeq as well, so we could have said this:
@conn.writeq << IRC.encode([to:'#chan1',msg:"This is an announcement..."])
or even
@conn.writeq << IRC.msg('#chan1',"This is an announcement...")
But you wouldn't want to or be able to do that in modules loaded normally.
Bit weird isn't it, the whole @config.out
thing?
Well, think of @config
as something we will be injecting into
things like bot modules. It's the config, so it may contain
information your modules might want to know about, and because we're a
bit cheap, we threw in an out-queue in there too.
Modules like mod
and mod2
above often don't have to worry
about queues or even the config, they just need to return a generic
message (called a botmsg) when responding to something coming over the
wire.
But in the event that you want to say something that is not triggered
by an input from the irc server, you'll need the out queue. Your
mod
should receive kargs[:config]
with this config
instance for that purpose.
https://github.com/danielbush/beerbot-modules for more exciting details.
Actually bot modules can return in another more general format:
[bool, botmsg]
where bool is true
or false
and botmsg is a botmsg (array,
hash).
If bool is false, this is interpreted by the bot as meaning "don't process any more bot modules after this one".
See the Bot class
which is essentially an array of bot modules
that are run in order.
You can grab the CronR
scheduler in a more official way like this:
scheduler = BeerBot::Scheduler.instance
# Cron parameters: 5 = 'friday', 0,16 = 4pm
cronargs = [0,16,true,true,5]
# Add a job...
scheduler.suspend {|arr|
arr << CronR::CronJob.new('timesheet',*cronargs) {
[to:'#chan',msg:"OMG! it's like 4pm friday..."]
}
}
Tests are in spec/ .
The tests should do a require_relative for the lib/ directory.
So you should be able to run them like: rspec Or rspec spec You could also do rspec -Ilib spec to ensure you're using the checked out code.
Broadly speaking:
Kernel
- instantiated with an instance of Config
- TODO: this is essentially the kernel and should be reusable (if we did xmpp). So we should inject objects like BeerBot::IRCConnection and BeerBot::Codecs::IRC .
- sets up and knows about all the other parts
- irc connection
- dispatcher
- scheduler
- the bot and its modules
IRCConnection
- connects, receives and sends out irc messages
IRC codec
- encodes and decodes irc messages
- TODO: I'd probably rename this to encode/decode => returns generic format: [event, *args]
Dispatcher#receive(event, args)
- has an instance of Bot
- may call Bot#cmd|hear|action|event
- which will call instances of BotModule => returns a botmsg