Playing with Hubot and CoffeeScript
At work we do really important things, like write commands so our hubot will post photos and gifs that we find amusing. This is probably the most important part of my job. Seriously.
But in all seriousness, I did just write my first few hubot scripts this month so that when certain phrases are ‘heard’, specific strings will be printed as a response.
What is hubot? Basically hubot is a helper bot written by the good folks at GitHub. You can install a hubot on a variety of applications (in our case, Slack) and automate all sorts of things. These things can range from totally helpful things, like automating builds, to less helpful things like showing rageful gifs when you get frustrated.
So what did I decide to do with hubot? Well, let’s look at the code to see.
module.exports = (robot) ->
robot.hear /world domination/i, (msg) ->
msg.send "One day .. the robots will rise up."
If you’re thinking to yourself…‘hm, Carmen, that JavaScript looks a little weird,’ – well I agree with you. That’s actually CoffeeScript. CoffeeScript transpiles into JavaScript. Hubot was written in CoffeeScript, although you can use plain JavaScript files to write your hubot commands.
I don’t love CoffeeScript, to be honest. The lack of brackets and semicolons really throws me off. But I used it because that’s what all of the other files were written in, and it was an interesting experience. Also the CoffeeScript site has really great docs, so if you’re interested in CoffeeScript, you should start there.
Basically the code above ‘listens’ for the string ‘world domination’. When hubot ‘hears’ that string, hubot responds with, ‘One day .. the robots will rise up.’
The robot
being passed in is our hubot, and the msg
passed in a few lines later is an object full of useful things – including the message that was originally sent. You may notice the simple little /world domination/
regex. That’s important because that’s how hubot knows what to listen for. Let’s check out another example.
giveEmTheBoot = (msg, user) ->
msg.send "I'm going to have to ask you to leave, @#{user}. :punch:"
module.exports = (robot) ->
robot.respond /(eject|remove|boot|bounce)[ ]?(.*)?/i, (msg) ->
users = msg.match[2] or null
if users?
giveEmTheBoot msg, user for user in users.split ' '
else
msg.reply "Sorry, I wasn't paying attention. Who am I escorting out of here?"
This example is a little bit more complicated. First, there’s an external function: giveEmTheBoot
. When we look at this function we see two parameters are passed in, msg
and user
. This is the function that actually sends the message.
In the next function, we see hubot being passed in again, but this time we robot.respond
instead of robot.hear
. When you use hear, hubot is ‘listening’, in a sense. Anytime your string appears, hubot will return the designated response.
However, when you use respond, you must specifically call your robot. So, in order to use this specific function, you would have to type something like, ‘hubot eject carmalou’. (Trust me, that gets typed a lot at work.)
Let’s look a little closer at that regex. You can see that it is listening for specific words, ‘eject, remove, boot, or bounce’. But what is the second half of it doing? Well, the second half is capturing the rest of the message after the word it is looking for. This ends up getting split into an array.
So ‘hubot eject carmalou’ becomes
[
'hubot eject carmalou',
'eject',
'carmalou',
index: 0,
input: 'hubot eject carmalou'
]
This works very well if someone decides to eject multiple users. ‘hubot eject bob sue anne elliot mark’ becomes
['hubot eject bob sue anne elliot mark',
'eject',
'bob sue anne elliot mark',
index: 0,
input: 'hubot eject bob sue anne elliot mark'
]
Next our function tests if we have any users at all. If there are users, you can see the CoffeeScript equivalent of a for loop. User is split by space, and each name is sent individually until there are no more names left in the user variable. If you think that for loop looks super weird – you’re not alone. I don’t like it at all.
But what if there aren’t any names in the user variable? What if someone typed ‘hubot eject’ and forgot who they were getting rid of? Well there’s an answer for that too in our else block. Then hubot prints ‘Sorry, I wasn’t paying attention. Who am I escorting out of here?’
There you have it! Those are the two super important hubot scripts I wrote. Let me know what you think!
Also wanted to note that I had loads of help writing these from Rick Yoesting, who also helped me edit this blog post for accuracy. Thank you, sir!