Getting Started with Ruby

This document provides a guide for getting started using Ruby with SmallD. It walks through the steps for setting up a bot that will respond with "pong" when a user sends "++ping".

Before starting you should have a token created for your bot account and invited it to a server. The fine folks of discord.py have a write up on how to do that on their site

The complete code from this guide can be found on GitHub

JRuby

To make use of SmallD from Ruby we need to be running as version of JRuby. Installation instructions can be found on their site or you can make use of a ruby environment manager such as (my favorite) rbenv or rvm.

Plumbing

Before starting on the code we'll setup the plumbing for our project. This will be Bundler and Rake.

Bundler will manage our dependencies for us, and Rake will make life easier for us when wanting to run our bot.

Gemspec

We start with our gemspec file. We define some information about our project, such as its name and author. The platform is restricted to java as we'll need a JVM for SmallD.

The requirements we add are:

  • SmallD as that's what we'll be using for our Bot
  • slf4j-simple to have slf4j log to standard output
  • jar-dependencies is needed for JRuby to be able to resolve jar dependencies
  • rake that we will use to make it easier for us to run our Bot
Gem::Specification.new do |s|
  s.name = 'smalld-gettingstarted-ruby'
  s.authors = ['Princess Lana']
  s.version = '0.0.0'
  s.summary = 'Getting started with SmallD and JRuby'

  s.platform = 'java'

  s.requirements << 'jar com.github.princesslana, smalld, 0.2.5'
  s.requirements << 'jar org.slf4j, slf4j-simple, 1.7.25'

  s.add_development_dependency 'jar-dependencies', '0.4.0'
  s.add_development_dependency 'rake', '12.3.2'
end

Gemfile

Gemfile follows trivially since we specify out dependencies in the gemspec.

source 'https://rubygems.org'

gemspec

Rakefile

We define two tasks in our Rakefile.

  • install_jars This is needed our integration between JRUby and Java. It will download and setup our jar dependencies.
  • run:pingbot This will run our bot.

In the run:pingbot task we pass an extra parameter through to JRuby. The -J means to pass this parameter to Java, and the -D is the option for setting a Java system property. The property we set turns up the logging level so that we have a better understanding of what's going on.

require 'jars/installer'

task :install_jars do
  Jars::Installer.vendor_jars!
end

namespace :run do
  task :pingbot do
    ruby "-J-Dorg.slf4j.simpleLogger.defaultLogLevel=debug lib/pingbot.rb"
  end
end

At this point in time we should be able to fetch and install our dependencies.

$ bundle install
$ bundle exec rake install_jars

The first command will fetch and install our ruby dependencies, the second will do it for our jar dependencies.

Connecting

Now, we can start to code our Bot. The first thing we'll do is make sure we can connect to Discord using SmallD. This makes sure we can use all our requirements before we start working on our logic.

In lib/pingbot.rb:

require_relative 'smalld-gettingstarted-ruby_jars'
java_import com.github.princesslana.smalld.SmallD

SmallD.run(ENV['SMALLD_TOKEN']) do |smalld|
  # Our logic will go here
end

Now we can run this as follows:

$ SMALLD_TOKEN=<your token here> bundle exec rake run:pingbot

You should seem some log messages, and you should see your bot come online in the server you had invited it to. You will need to quit running the bot with <Ctrl-C>.

Responding

Now that we can connect to Discord, we can listen for message created events and respond to those that are ping messages. To do this we need to understand the message create event and the create message resource.

The logic we add works as follows:

  • Attach a listener for events from the Discord Gateway using onGatewayPayload.
  • Upon receiving a payload we:
    • Parse it as JSON,
    • Check if it is a message create event
    • Check if the message content is ++ping
    • Respond to the message with pong
require_relative 'smalld-gettingstarted-ruby_jars'
java_import com.github.princesslana.smalld.SmallD
require 'json'

SmallD.run(ENV['SMALLD_TOKEN']) do |smalld|
  smalld.onGatewayPayload do |p_str|
    p_json = JSON.parse p_str

    if is_message_create?(p_json) && message_content(p_json) == '++ping'
      channel_id = p_json['d']['channel_id']

      smalld.post "/channels/#{channel_id}/messages", { content: 'pong' }.to_json 
    end
  end
end

But, this code isn't complete yet, as we need to implement the is_message_create? and message_content methods. By consulting the Discord docs we can find out what fields we need to use to do so, and implement these methods as follows:

def is_message_create?(json)
  json['op'] == 0 && json['t'] == 'MESSAGE_CREATE'
end

def message_content(json)
  json['d']['content']
end

Finally

Now our ping bot is complete. We can run it with the command:

$ SMALLD_TOKEN=<your token here> bundle exec rake run:pingbot

If it does not work as you expecte take a check of the GitHub repo to compare it to your code, and if that doesn't work feel free to get in touch via the details here.

Happy Coding!