Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
231 lines (159 sloc) 4.65 KB

!SLIDE

What is Sinatra

  • A rack-based DSL language for writing lightweight web-applications
  • Installed as a gem: gem install sinatra
  • Latest version released one year ago (April 2014), under active development

!SLIDE

Simple app

It does not get any simpler:

# myapp.rb
require 'sinatra'

get '/' do
  'Hello world!'
end

!SLIDE

Some features

  • Expressive language for routes:
    • parameters (get '/hello/:name')
    • regexps, …
  • Various templating engines (textile, liquid, haml, erb, …)
  • Templates
    • inline
    • named at the end of the file
    • in separate files
  • Extensions (e.g., integration with active record)

!SLIDE

Route Example

Respond according to format:

get "/:resource.?format?"
  case params["format"]
  when "html"
    ...
  when "json"
    ...
  end
end

!SLIDE

Some more features

  • Filters: do something before action
  • Helpers: be DRY
  • Sessions and redirections
  • Streaming responses (non-blocking HTTP)
  • Support for static files (public)
  • Send files (download):
send_file "./files/#{filename}", :filename => filename, :type => 'Application/octet-stream'

!SLIDE

Sinatra the good and the bad

The good:

  • Sinatra is very good at implementing microservices
  • Sinatra is a good replacement for a ruby GUI (some GUI bindings exist: Tck/Tk, Shoes, GTK, RubyCocoa, but they are eithre OS dependent or difficult to integrate with)
  • The introductory README has a bunch of information to get started

The bad:

  • Sinatra is not framework: you are in complete control of what happens
  • HTML forms and data mapping (not necessarily bad, though)

A good alternative for mobile development? (If you can bundle ruby and a local server)

!SLIDE

Sinatra and Rails

Working with Sinatra I realized how much you get with Rails:

  • File structure
  • Data binding and migrations (data mapper, active record)
  • Navigation (CRUD)
  • Validations
  • Connections between controllers and views (form_for)

!SLIDE

Structuring Development with Sinatra

  1. Define what the app does
  2. Sketch the navigation/routes (you will end up replicating Rails, imo)
  3. Decide how you will structure your code (gems, anyone?)
  4. Implement the persistence layer (using file, data-mapper, or active-record based)
  5. Test the persistence layer
  6. Implement the routes
  7. Test your application running:
rerun ruby app.rb
  1. Make it nice looking (optional)

!SLIDE

Rack and Sinatra

Two deployment options: classic vs. modular style

  • The classic style: write the application into a file
  • The modular style: wrap the app into a class
require 'sinatra/base'

class MyApp < Sinatra::Application
  get '/' do
    'Hello world!'
  end

  # start the server if this ruby file executed directly
  run! if app_file == $0
end

!SLIDE

A digression on Rack

  • Rack is a minimalistic interface between webservers and Ruby
  • To run an app in Rack, the app must respond to call and return an Array with:
    • The HTTP response code
    • A Hash of headers
    • The response body, which must respond to each

You can make it even simpler than Sinatra, if you want!

!SLIDE

Rack and Passenger

Passenger can run rack compliant applications with the following structure

/webapps/rackapp
  |
  +-- config.ru
  |
  +-- public/
  |
  +-- tmp/
$ cat config.ru
app = proc do |env|
    [200, { "Content-Type" => "text/html" }, ["hello <b>world</b>"]]
end
run app

Deploying a Rack-based application

!SLIDE

… Oh, the Micro Service stuff

Using Sinatra as Middleware

Not only is Sinatra able to use other Rack middleware, any Sinatra application can in turn be added in front of any Rack endpoint as middleware itself. This endpoint could be another Sinatra application, or any other Rack-based application (Rails/Ramaze/Camping/…):

require 'sinatra/base'

class LoginScreen < Sinatra::Base
  enable :sessions

  get('/login') { haml :login }

  post('/login') do
    if params['name'] == 'admin' && params['password'] == 'admin'
      session['user_name'] = params['name']
    else
      redirect '/login'
    end
  end
end

class MyApp < Sinatra::Base
  # middleware will run before filters
  use LoginScreen

  before do
    unless session['user_name']
      halt "Access denied, please <a href='/login'>login</a>."
    end
  end

  get('/') { "Hello #{session['user_name']}." }
end

!SLIDE

Demos

  • This presentation!
  • Counter (coffee, anyone?)
  • Data Mapper