GraalVM Ruby Basics
What You’ll Need
- GraalVM installed and bin directory in your PATH variable
- Text editor (VS Code, vi, etc)
- REST API client (cURL, Postman, etc)
- Using Ubuntu based distribution for this example, so some commands (e.g. apt) could be different for you.
What You’ll Get
Installation of Ruby on GraalVM (TruffleRuby), some installed gems, and a bare-bones REST API with Sinatra and SQLite3. According to TruffleRuby stats, your implementation should be significantly more performant than standard Ruby.
Install Ruby / TruffleRuby
Use the graal updater to install Ruby using the command below:
gu install ruby
WIth many of the gems I’ve tried to install, I was greeted with the error below.
ERROR: Loading command: install (RuntimeError)
you may need to install the system OpenSSL library libssl - see https://github.com/oracle/truffleruby/blob/master/doc/user/installing-libssl.md (libssl.so.10: cannot open shared object file: No such file or directory)
ERROR: While executing gem ... (NoMethodError)
undefined method `invoke_with_build_args' for nil:NilClass
To resolve this, you will need to install libssl-dev and then run a script provided in the TruffleRuby installation named postinstallhook.sh. These are instructions for Ubuntu based distros, but more details may be found here: https://github.com/oracle/truffleruby/blob/master/doc/user/installing-libssl.md
#Also take opportunity to install build-essential if you do not have, since it will be needed for the post_install_hook.sh:
sudo apt install libssl-dev build-essential
#Go into "<path to your graalvm parent>/graalvm/languages/ruby/lib/truffle
cd path_to_where_your_graalvm_dir_is/graalvm/languages/ruby/lib/truffle
./post_install_hook.sh
Install Some Gems
For our project, we’ll install sqlite3 and sinatra in order to create a very basic REST API.
#Go back to your home directory:
cd ~
#Install required sqlite packages
sudo apt install libsqlite3-dev
#Specify that no documentation should be added during gem installs. This will significantly reduce install times:
echo "gem: --no-document" >> .gemrc
#Install required Gems:
gem install sinatra sqlite3
Standalone Example - Connecting to Sqlite database
require 'sqlite3'
db = SQLite3::Database.new('myDb.db')
db.execute "CREATE TABLE IF NOT EXISTS beers(name VARCHAR(50))"
db.execute "INSERT INTO beers VALUES('Stella')"
rows = db.execute "SELECT * FROM beers"
puts rows
db.close
Standalone Example - Sinatra REST API
require 'sinatra'
get '/beers' do
content_type 'application/json'
beers = ['Stella', 'Jai Alai', 'Lagunitas']
beers.to_json
end
Put it All Together
require 'sinatra'
require 'sqlite3'
db = SQLite3::Database.new('myDb.db')
db.execute "CREATE TABLE IF NOT EXISTS beers(name VARCHAR(50))"
post '/beers' do
#Rewind body in case already read:
request.body.rewind
request_body = request.body.read.to_s
#Parse JSON body:
beer = JSON.parse request_body
#Insert record. Use prepared statement to bind varibles:
stmt = db.prepare "INSERT INTO beers VALUES(?)"
stmt.bind_params beer['name']
stmt.execute
end
get '/beers' do
content_type :json
#Query all beers:
result = db.execute "SELECT * FROM beers"
#Iterate records, convert to json compatible dict, and push to array:
beers = []
result.each do |row|
beers.push({:name => row[0]})
end
#Return array converted to JSON:
beers.to_json
end
Try posting a new beer using cURL:
curl -H "Content-Type: application/json" -d "{\"name\":\"Lagunitas\"}" -X POST http://localhost:4567/beers
curl -H "Content-Type: application/json" -d "{\"name\":\"Stella\"}" -X POST http://localhost:4567/beers
GET Records using cURL:
curl http://localhost:4567/beers
#Result:
[{"name":"Lagunitas"},{"name":"Stella"}]