Jim Lawless' Blog


Choose your own Adventure with Sinatra

Originally published on: Thu, 25 Mar 2010 02:15:20 +0000

I saw a news item this week about the 1.0 release of the Ruby Sinatra webapp library:

Sinatra 1.0 Released: Major Milestone for Ruby's Best Webapp DSL

I had heard of Sinatra, but I had been under the impression that it was a framework analagous to Ruby on Rails or the Django framework for Python. What caught my eye in the title was the reference to a "Webapp DSL". I was curious to find out if Sinatra did indeed expose a Domain-Specific Language that would allow one to quickly write web applications.

After reading the article, I was amazed to find that Sinatra applications are defined by using Ruby extensions. I didn't see any reference to any YAML or XML or anything like that.

First, I needed to download and install the Sinatra gem. I have been pretty happy with JRuby so far, so I tried to install the gem under JRuby instead of the native MRI for Windows.


C:\>gem install sinatra
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://jruby.kenai.com/pages/JRuby_Builtin_OpenSSL
Successfully installed rack-1.1.0
Successfully installed sinatra-1.0
2 gems installed
Installing ri documentation for rack-1.1.0...
Installing ri documentation for sinatra-1.0...
Installing RDoc documentation for rack-1.1.0...
Installing RDoc documentation for sinatra-1.0...

It installed without any issues.

I then wrote a small Sinatra application that displays an HTML page with a link to this blog:

sinatra_test.rb


# Simple Sinatra test
#
# License: MIT / X11
# Copyright (c) 2010 by James K. Lawless
# jimbo@radiks.net http://www.radiks.net/~jimbo
# http://www.mailsend-online.com
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.

require 'rubygems'
require 'sinatra'

def htmlstart()
   return "<html><head /><body>"
end

def htmlend()
   return "</body></html>"
end

def makelink(text,link)
   return '<a href="' + link + '">' + text + '</a>'
end

get '/test' do
   htmlstart() +
   "Testing<p>" +
   makelink( "Click here to visit Jim's Blog",
      "http://www.mailsend-online.com/blog") +
   htmlend()
end

The invocation of the Sinatra get function looks like it pairs a URI with a Ruby block that yields text that is returned to the client browser. I wrote a few helper functions that generate some HTML markup around the text I intend to use.

By calling get with '/test' as the URI, the request for http://localhost:4567/test is routed to a handler that passes back the text from the block specified above.

I had to start the application before I could test this theory. A Sinatra application can be run just like any conventional Ruby script. It then provides its own web server to host itself as a web application:


C:\>jruby sinatra_test.rb
== Sinatra/1.0 has taken the stage on 4567 for development with backup from WEBrick
[2010-03-24 20:49:31] INFO WEBrick 1.3.1
[2010-03-24 20:49:31] INFO ruby 1.8.7 (2009-11-02) [java]
[2010-03-24 20:49:31] INFO WEBrick::HTTPServer#start: pid=2836 port=4567

I navigated to http://localhost:4567/test and saw my web page with a link to this blog:

Since the definition of a page was set up in just a handful of lines of Ruby code via a call to get, I reasoned that one could house many different pages in a single script. To try out this idea, I decided to put together a small web game consisting of a few static web pages and links to each. This game is akin to the "choose your own adventure" games usually found in the form of paperback books in the early 1980's.

cyoa.rb


# Choose Your Own Adventure
# Using JRuby and Sinatra
#
# License: MIT / X11
# Copyright (c) 2010 by James K. Lawless
# jimbo@radiks.net http://www.radiks.net/~jimbo
# http://www.mailsend-online.com
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.

require 'rubygems'
require 'sinatra'

def htmlstart()
   return "<html><head /><body>"
end

def htmlend()
   return "</body></html>"
end

def makelink(text,link)
    return '<a href="' + link + '">' + text + '</a>'
end

get '/' do
   htmlstart() +
   "You awaken in a cave. A cyclops holding a large club is standing over you.<p>" +
   "What would you like to do?<p>" +
   makelink( "Run for it!","/run") +
     "<p>" +
   makelink("Sing the cyclops a lullaby.","/lullaby") +
   htmlend()
end

get '/run' do
   htmlstart() +
   "You manage to make it out of the cave, but you fall " +
   "down a hill and end up kneeling before a small lake." +
   "What would you like to do?<p>" +
   makelink( "Drink some water.","/drink") +
     "<p>" +
   makelink("Go for a swim.","/swim") +
   htmlend()
end

get '/lullaby' do
   htmlstart() +
   "The cyclops says <strong>'Me no like Brahms!'</strong>. " +
   "He then hits you with his club. You lose consciousness." +
   "<p>" +
   makelink("Click here to play again","/") +
   htmlend()
end

get '/drink' do
   htmlstart() +
   "The water feels tingly on your tongue. The land around you starts to blur." +
   "You lose consciousness." +
   "<p>" +
   makelink("Click here to play again","/") +
   htmlend()
end

get '/swim' do
   htmlstart() +
   "As you dive into the water, you see a shimmering circular object." +
   "When you peer into the object, you can see your living room on the other side." +
   "<p><strong>The object is a trans-dimensional portal!</strong>" +
   "<p>You swim through the portal and end up safely at home." +
   "<p>" +
   "Thanks for playing!" +
   htmlend()
end

To play the game, you must first run the cyoa.rb script. After the web-server starts up, you should navigate to localhost:4567/. That first page says:

You awaken in a cave. A cyclops holding a large club is standing over you.

What would you like to do?

Run for it! Sing the cyclops a lullaby.

If you click Sing the cyclops a lullaby your browser will navigate to localhost:4567/lullaby. That page says: The cyclops says 'Me no like Brahms!'. He then hits you with his club. You lose consciousness.

Click here to play again

There are only a few pages in the adventure. If you click Run for it! from the first page and then click Go for a swim. after that, your character will end up safely at his home. All other paths lead to unconsciousness.

I have only used a very simple Sinatra function to make this skeletal game. I intend to delve into the library more deeply.

I suspect that this application will run with no changes under MRI Ruby, but I haven't tried that, yet.

Unless otherwise noted, all code and text entries are Copyright 2010 by James K. Lawless



Views expressed in this blog are those of the author and do not necessary reflect those of the author's employer. Views expressed in the comments are those of the responding individual.

stumbleupon Save to StumbleUpon
digg Digg it
reddit Save to Reddit
facebook Share on Facebook
twitter Share on Twitter
aolfav More bookmarks


Previous post: Setting Windows Console Text Colors in C
Next post:CP/M Days


About Jim ...


Follow me on Twitter

http://twitter.com/lawlessGuy


My GitHub Repository

https://github.com/jimlawless


Recent Posts

Compiling C from the Command Line with Pelles C

A Forthcoming Marvel Movie Villain

Uninstalling Problematic Windows Software

Don't be Hatin'

A JavaScript REPL for Android Devices

MailSend is Free

My Blog Engine

The October 10th Bug


Random Posts

Throwaway Software: HangUp

We've Moved!

CP/M Days

A Command Line Scheduler

Tracing XSLT with a Tiny Java Web Server

BBS Fun in the Eighties

Setting Text Color in a Batch File

Flirting with Forth

A Scrolling Banner using Canvas and JavaScript

BSave and BLoad for the Commodore 64


Full List of Posts

http://www.mailsend-online.com/bloglist.htm


Recent Posts from my Other Blog / GitHub

A Simple (but useful) TCP Client Written in Go

Yet Another Seven Languages in Seven Weeks

Happy 50th Birthday, BASIC

Extending Commodore 64 BASIC

Hide the HTTP-Referer using HTML and JS

RSS Feed Processing in Python

A Chromecast Slideshow using Python

A Simple Perl REPL

Linux Mint on a Toshiba Netbook

Find and View All Images on a HD with Perl

Pretty-Printing an s-expression in Go

My Personal Text to HTML Utility

1985 Computing : Atari and Commodore

My Mac has Mono

Yet Another Config File Reader for Go (Golang)

Filling a Slice Using Command-line Flags in Go (Golang)

An RPN Interpreter in Go (Golang)

Simulating Try-Catch in Go (Golang)

Sending GMail with Go (Golang)

Variant Types in Golang

My First C64 Interrupt Program

The Triangles Puzzle

Happy 25th, Perl !

My Favorite BASIC One-Liner

Playing with OS/X Text to Speech

The Villain at the end of Marvel's Avengers Move is...

Chicken! Fight like a Robot!

Processing GMail items with Ruby

The Squares Puzzle

Happy 30th Birthday, Commodore 64

Scripting Safari

MailWrench CSharp Command Line Mailer for Windows is now Free Software

Welcome Back, M.U.L.E. !

Rainy Day Fun with the HTML DOM

Building a World War II Foxhole Radio

Prototerp Unleashing a JavaScript REPL via the Mobile Browser

Steal This Bookmarklet

Happy Birthday, Miles