Web Development
with Sinatra
What is Sinatra?
“Sinatra is a DSL for quickly
creating web applications in
Ruby with minimal effort.”
- sinatrarb.com/intro
It’s a LIBRARY not a
FRAMEWORK.
huh?
http://stackoverflow.com/questions/148747/what-is-the-difference-between-a-framework-and-a-library
http://www.quora.com/Software-Engineering/Whats-the-difference-between-a-library-and-a-framework
Martin Fowler
“A library is essentially a set of functions that you can
call... Each call does some work and returns control to
the client.”
“A framework embodies some abstract design, with
more behavior built in... you need to insert your
behavior into various places in the framework.”

http://martinfowler.com/bliki/InversionOfControl.html
Sinatra allows you to
structure your application
to fit the problem you’re
trying to solve instead of
the other way around.
Simplest Example
require 'sinatra'
get '/hi' do
"Hello World!"
end
$ gem install sinatra
$ ruby hi.rb
== Sinatra has taken the stage ..
>> Listening on 0.0.0.0:4567
Road Map

• Fundamentals
• “Advanced” Topics
• Use Cases
Fundamentals
Anatomy of a Route Handler
URL
HTTP Verb
get
post
put
delete
patch

Parameters

get '/hello/:name' do
"Hello, #{params[:name]}"
end
Behavior
Fundamentals
The First Sufficient Match Wins
get '/*' do
"NOM NOM NOM"
end
get '/specific' do
"I'll never be matched... you'll won't see me!"
end
Fundamentals
Halting a Request
get '/halt' do
"You will not see this output."
halt 500
end
Fundamentals
Redirecting a Request
Optional
get '/search' do
redirect 'http://www.google.com', 301
end
Fundamentals
Views: Inline Templates
require 'sinatra'
get '/index' do
erb :index
end
__END__

ERB by default, but any
templates supported by
Tilt will work

@@index
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Inline Template</title>
</head
<body>
<h1>It Worked!</h1>
</body>
</html>

Each inline template must
have a unique name
Fundamentals
Views: External Templates
Just place your templates in a /views
folder and Sinatra will pick them up;
you’re route handlers stay the same
Fundamentals
Views: Passing Data
get '/home' do
@name = 'John Doe'
erb :home
end
__END__
@@home
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Inline Template</title>
</head
<body>
<h1><%= @name %></h1>
</body>
</html>
Fundamentals
Filters
before do
content_type :json
end
after do
"After filter called"
end
Fundamentals
Helpers
helpers do
def link(name)
case :name
when :about then '/about'
when :index then '/index'
else "/page/#{name}"
end
end
# in your view template
<a href="<%= link :about %>">About</a>
# -- OR -# define helpers as methods in a module
module MyHelpers
# helper methods
end
helpers MyHelpers
Fundamentals
Configuration
configure :development do
set :db, Sequel.sqlite('db/development.sqlite')
end
configure :production do
set :db, Sequel.connect(ENV['DATABASE_URL'])
end
Fundamentals
Caching
get '/cache' do
expires 3600, :public, :must_revalidate
"This page rendered at #{Time.now}."
end

See http://www.mnot.net/cache_docs/ for an
explanation of HTTP caching options
Fundamentals
Sessions
configure do
enable :sessions
end
get '/set' do
session[:foo] = Time.now
"Session time was set."
end
get '/fetch' do
"Session value: #{session[:foo]}"
end
get '/unset' do
session.clear
redirect '/fetch'
end
Fundamentals
Attachments
before do
content_type :txt
end
get '/attachment' do
attachment 'path/to/my-attachment.txt'
end
Fundamentals
Testing with rack-test
require 'my_sinatra_app'
require 'test/unit'
require 'rack/test'
class MyAppTest < Test::Unit::TestCase
include Rack::Test::Methods
def app
Sinatra::Application
end
def test_my_default
get '/'
assert_equal 'Hello World!', last_response.body
end
def test_with_params
get '/meet', :name => 'Frank'
assert_equal 'Hello Frank!', last_response.body
end
def test_with_rack_env
get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
assert_equal "You're using Songbird!", last_response.body
end
end
Advanced Topics
Modular vs. “Classic”
“For some reason, it is a common misconception
that modular applications are superior to classic
applications, and that really advanced users only
use modular style... This is utter nonsense and no
one on the Sinatra core team shares this view.
Sinatra is all about simplicity and if you can use a
classic application, you should.”
-- Sinatra Up and Running
Advanced Topics
Reasons to Use Modular
you don’t want to pollute the Object
namespace (writing a Gem)
combining multiple Sinatra apps in a
single process
use Sinatra app as middleware
Advanced Topics
Simplest Modular Example
require 'sinatra/base'
class MyApp < Sinatra::Base
get '/hi' do
"Hello World!"
end
# Only start the server if the file
# has been executed directly
#
# $0 is the executed file
# __FILE__ is the current file
run! if __FILE__ == $0
end
Advanced Topics
Running with Rack: Rackup File
# In a file named my_app.rb
require 'sinatra/base'
class MyApp < Sinatra::Base
get '/hi' do
"Hello World!"
end
end
# in a separate file named config.ru
require './my_app'
run MyApp
# launch the server using
# rackup command or shotgun
Advanced Topics
Running with Rack: Middleware Chain
# In a file named my_app.rb
require 'sinatra/base'
class Foo < Sinatra::Base
get('/foo') { 'foo' }
end
class Bar < Sinatra::Base
get('/bar') { 'bar' }
use Foo
end
# config.ru
require 'my_app'
run Bar
# Or Foo and Bar can be in separate files
# remember... it's just Ruby!
Advanced Topics
Running with Rack: Cascade
require 'sinatra/base'
class Foo < Sinatra::Base
get('/foo') { 'foo' }
end
class Bar < Sinatra::Base
get('/bar') { 'bar' }
end
# config.ru
require 'my_app'
run Rack::Cascade, [Foo, Bar]
# Differences:
# * _slightly_ better performance, but only if you have a lot of endpoints
# * you can use any Rack app (like Rails)
Advanced Topics
Extensions: LinkedIn Example
Use Cases
Prototyping Web Apps
API Server for iOS / Android /
JavaScript Apps
HTML5 Mobile Apps
Resources
•
•
•
•

http://rubydoc.info/gems/sinatra/file/README.rdoc

•

http://www.quora.com/Software-Engineering/Whats-the-difference-between-alibrary-and-a-framework

•
•
•
•
•
•
•

http://martinfowler.com/bliki/InversionOfControl.html

http://www.sinatrarb.com/documentation
Sinatra: Up and Running (http://shop.oreilly.com/product/0636920019664.do)
http://stackoverflow.com/questions/148747/what-is-the-difference-between-aframework-and-a-library

http://www.mnot.net/cache_docs/
https://github.com/bnadlerjr/sidestep
https://github.com/bnadlerjr/leaflet
https://github.com/bnadlerjr/sinatra-linkedin
https://github.com/bnadlerjr/fuelyo
http://rubygems.org/gems/middleman
Questions?

Bob Nadler
@bnadlerjr
bnadler@cyrusinnovation.com

Web Development with Sinatra