SlideShare una empresa de Scribd logo
1 de 138
Descargar para leer sin conexión
Introduction à

Sinatra
Rémi Prévost — ConFoo 2011
Rémi Prévost
 Développeur Web

@remi + http://remiprevost.com
Sinatra




 •   Présentation
 •   Installation
 •   Utilisation
 •   Déploiement
Historique
 et possibilités
Historique




             2008
 Blake Mizerany & Adam Wiggins
Historique




             Problème
             Services Web légers
Historique




             Solution
             Un micro-framework
Historique




        Possibilités
             infinies
Historique




        Prototypes
             d’applications Web
Historique




    Applications
             Web complètes
Historique




             APIs
             « RESTful »
Avantages
 Les bons côtés
Avantages




        Installation
            rapide
$ gem install sinatra
=> Successfully installed rack-1.2.1
   Successfully installed tilt-1.2.2
   Successfully installed sinatra-1.2.0
Avantages




  Développement
            minimaliste
# contenu de hello.rb
require "sinatra"

get "/" do
  "Hello world."
end




$ ruby -rubygems hello.rb
=> == Sinatra/1.2 has taken the stage on 4567…

$ curl http://localhost:4567/
=> Hello world.
$ rails new blogue
=> create README
   create Rakefile
   create config.ru
   create .gitignore
   create Gemfile
   create app
   …

$ du -hd0
=> 428K .
Avantages




   Déploiement
            facile
Désavantages
 Les moins bons côtés
Désavantages




 •   Fonctionnalités réduites
 •   Expansion moins guidée
 •   Documentation moins large
Rack
Interface HTTP
Rack




       Framework
        pour frameworks
# contenu de config.ru
class RackApp
  def call(env)
	 [200, { "Content-type" => "text/html" }, "Hello world."]
  end
end

run RackApp.new




$ rackup --env development
=> INFO WEBrick::HTTPServer#start: pid=37743 port=9292

$ curl http://localhost:9292/
=> Hello world.
# contenu de blogue.rb
require "sinatra"

class Blogue < Sinatra::Base
  # Code l’application Sinatra
end




# contenu de config.ru
require "blogue"

run Blogue.new
# contenu de blogue.rb
require "sinatra"

# Code l’application Sinatra au premier niveau




# contenu de config.ru
require "blogue"

run Sinatra::Application
Routes
Les directions
Routes




           REST
   Basées sur les méthodes HTTP
Routes




 •   GET
 •   POST
 •   PUT
 •   DELETE
methode_http(route) { reponse }
methode_http(route) { reponse }

get("/") { "Hello world." }
Routes




         Statiques
           Routes fixes
get "/" do
  "Page principale du blogue"
end

post "/admin/article" do
  "Création d’un nouvel article"
end
Routes




         Paramètres
           Routes variables
get "/auteur/:username" do
  "Les billets de #{params[:username]}"
end

delete "/articles/:id" do
  "Suppression de l’article #{params[:id]}"
end

put "/articles/:id" do |id|
  "Modification de l’article #{id}"
end
Routes




               Splat
         Routes avec « wildcards »
get "/fichiers/*.*" do
  # GET /fichiers/images/2011/03/foo.jpg
  # params[:splat] => ["/images/2011/03/foo", ".jpg"]
end

get "/*" do
  # GET /url/inconnu
  # params[:splat] => ["url/inconnu"]
end
Routes




             Regex
         Routes avec expressions
get /^/(d{4})$/ do |annee|
  "Les articles de l’année #{annee}"
  # params["captures"] => [annee]
end

get %r{^(d{4})/(d{2})$} do |annee, mois|
  "Les articles du mois #{mois} de #{annee}"
  # params["captures"] => [annee, mois]
end

# seulement ruby 1.9
get %r{^(?<annee>d{4})/(?<mois>d{2})$} do
  "Les articles du mois #{params[:mois]} de #{params[:annee]}"
end
Routes




         Conditions
         Routes conditionnelles
get "/", :agent => /msie [w.]+/i do
  "Page d’accueil pour Internet Explorer"
end

get "/" do
  "Page d’accueil pour les autres user-agents"
end
set(:secret) do |value|
  condition { params.include?(:secret) == value }
end

get "/", :secret => true do
  "Page d’accueil secrète!"
end

get "/" do
  "Page d’accueil régulière."
end
Routes




 •   methode_http(route) { reponse }
 •   Paramètres (réguliers, regex, splat)
 •   Conditions
Exécution
Passer, arrêter ou filtrer
Exécution




                Passer
            d’une route à la suivante
get "/admin/dashboard" do
  pass unless authenticate!
  "Le tableau de bord secret"
end

get "/admin/*" do
  "Vous semblez ne pas être identifié."
end
Exécution




            Arrêter
            l’exécution du code
get "/admin/dashboard" do
  halt(401, "Vous voulez hacker ce blogue?") unless authenticate!
  "Le tableau de bord secret"
end
Exécution




            Filtrer
            avant et après
Exécution




            before
            Avant la route
before "/admin/*" do
  halt(401, "Vous voulez hacker ce blogue?") unless authenticate!
end

get "/admin/dashboard" do
  "Tableau de bord de quelqu’un d’authentifié"
end

post "/admin/billets" do
  "Création d’un billet par quelqu’un d’authentifié"
end
before "/compte/*" do
  @user = User.find(session[:user_id])
end

get "/compte/photo" do
  "Formulaire de modification de la photo de #{@user}"
end

get "/compte/motdepasse" do
  "Formulaire de modification du mot de passe de #{@user}"
end
before :agent => /msie 6.0/i do
  @message = "Vous utilisez un navigateur dépassé…"
end
Exécution




             after
            Après la route
after "*" do
  headers "X-Secret-Data" => "LOL"
end
Templates
  Les vues
Templates




            Réponses
            compatibles avec Rack
get "/" do
  "Page principale du blogue"
end
get "/" do
  [200, "Page principale du blogue"]
end

get "/api/articles.json" do
  [200, { "Content-type": "application/json" }, "[]"]
end
Templates




                   Tilt
            Templates à la demande
get "/" do
  haml :index
end

get "/css/screen.css" do
  sass :screen
end

get "/api/articles.xml" do
  nokogiri :"api/articles"
end

get "/api/articles.json" do
  coffee :"api/articles"
end
Templates




            Options
            pour chaque engin
get "/" do
  haml :index, :format => :html4
end

get "/css/screen.css" do
  scss :screen, :style => :compressed
end
set :haml, :format => :html5, :ugly => true
set :scss, :style => :compressed
Templates




            Internes
        Stockés dans le code Ruby
enable :inline_templates

get "/" do
  haml :index
end

__END__

@@ layout
!!!
%html
  %body
    =yield

@@ index
%h1 Bienvenue sur mon blogue.
template :layout do
  "!!!n%htmln%bodyn=yieldn"
end

template :index do
  "%h1 Bienvenue sur mon blogue."
end

get "/" do
  haml :index
end
get "/" do
  haml "!!!n%body Bienvenue sur mon blogue."
end
Templates




            Externes
       Stockés en tant que fichiers
get "/" do
  haml :index # /views/index.haml
end

get "/css/screen.css" do
  sass :screen # /views/screen.sass
end

get "/api/articles.xml" do
  builder :"api/articles"# /views/api/articles.builder
end

get "/api/articles.json" do
  coffee :"api/articles" # /views/api/articles.coffee
end
set :views, Proc.new { File.join(root, "templates") }
Templates




            Layout
            Template commun
get "/" do
  haml :index
  # template: views/index.haml
  # layout:   views/layout.haml
end

get "/article/:id" do
  @article = Article.find(params[:id])
  markdown :article, :layout_engine => :haml
  # template: views/article.markdown
  # layout:   views/layout.haml
end

get "/ajax/article/:id.html" do
  @article = Article.find(params[:id])
  haml :article, :layout => false
  # template: views/article.haml
  # layout:   n/a
end
Templates




            Données
    Les utiliser dans les templates
get "/" do
  @articles = Article.all
  haml :index
end




-# contenu de index.haml
.hfeed
  - @articles.each do |article|
    .entry
       %h1= article.titre
       .entry-content
         = markdown(article.contenu)
get "/" do
  articles = Article.all
  haml :index, :locals => { :articles => articles }
end




-# contenu de index.haml
.hfeed
  - articles.each do |article|
    .entry
       %h1= article.titre
       .entry-content
         = markdown(article.contenu)
get "/" do
  @articles = Article.all
  haml :index
end




-# contenu de index.haml
.hfeed
  - @articles.each do |article|
    .entry
       = haml :article, :locals => { :article => article }




-# contenu de article.haml
.entry
  %h1= article.titre
  .entry-content
    = markdown(article.contenu)
Templates




            Helpers
     Utilitaires disponibles partout
helpers do
  def heading(level, text)
    "<h#{level}>#{text}</h#{level}>"
  end
end




%h1 Derniers articles
%ul.articles
  - @articles.each do |article|
    %li
      =heading(2, article.title)
helpers do
  def link_to(path, text)
    path = "#{request.host}#{path}" if request.xhr?
    "<a href="#{path}">#{text}</a>"
  end
end

def other_link_to(path, text)
  # n’a pas accès à `request`
  "<a href="#{path}">#{text}</a>"
end




%h1 Bienvenue
%p= link_to "/", "Accueil"
%p= other_link_to "/", "Accueil encore"
Templates




 •   Tilt
 •   Options
 •   Internes + Externes
 •   Données
 •   Helpers
Configuration
  et environnements
Configuration




                Globale
         à tous les environnements
configure do
  DataMapper.setup :default, ENV["DATABASE_URL"]
  DataMapper::Pagination.defaults[:per_page] = 20
  DataMapper::Logger.new $stdout, :debug
end

get "/" do
  @articles = Article.all
  haml :index
end
Configuration




          Spécifique
                à un environnement
$ rackup --env development
=> INFO WEBrick::HTTPServer#start: pid=37743 port=9292

$ rackup --env production
=> INFO WEBrick::HTTPServer#start: pid=37743 port=9292




$ shotgun --env development
== Shotgun/WEBrick on http://127.0.0.1:9393/

$ thin start --env production
>> Thin web server (v1.2.8 codename Black Keys)
>> Listening on 0.0.0.0:3000, CTRL+C to stop
configure :development do
  set :scss, :style => :expanded
  set :haml, :ugly => false
end

configure :production do
  set :scss, :style => :compressed
  set :haml, :ugly => true
end
configure :development, :test do
  set :s3, { :bucket => "blogue-dev", :key => "efg456" }
end

configure :production do
  set :s3, { :bucket => "blogue", :key => "abc123" }
end

get "/" do
  "La valeur de s3/bucket est de #{settings.s3[:bucket]}"
end
Erreurs
gérées comme des routes
Erreurs




          Routes
          introuvables
not_found do
  "Cette page n’a pu être trouvée"
end
not_found do
  haml :erreur
end
Erreurs




                HTTP
          Codes d’erreurs standards
error 403 do
  haml :"erreurs/interdit"
end

error 405..500 do
  haml :"erreurs/autre"
end
Erreurs




          Exceptions
            personnalisées
error UnauthenticatedUser do
  haml :"erreurs/non_authentifie"
end

before "/admin/*" do
  raise UnauthenticatedUser unless authenticate!
end
Fichiers
et téléchargements
Fichiers




           Fichiers
             publics
$ tree   .
=> "##   blogue.rb
   "##   config.ru
   "##   public
         "## css
         %   &## screen.css
         &## js
             &## global.js




$ curl http://localhost:9292/css/screen.css
=> …

$ curl http://localhost:9292/js/global.js
=> …
set :public, Proc.new { File.join(root, "fichiers/statiques") }
Fichiers




Téléchargements
           de fichiers
get "/live/report.txt" do
  # Construction dynamique du fichier /tmp/report.txt
  # …
  send_file "/tmp/report.txt", :type => :attachment
end
Sessions
 et cookies
Sessions




           Sessions
Données temporaires encryptées
enable :sessions

before "/admin/*" do
  unless session[:admin]
    halt "Vous devez être <a href="/login">connecté</a>."
  end
end

get "/login" do
  haml :login
end

post "/login" do
  if params[:username] == "foo" and params[:password] == "bar"
    session[:admin] = true
    redirect "/admin"
  end
end
Sessions




            Cookies
           Données persistantes
before do
  unless request.cookies.include?("deja_venu_ici")
    response.set_cookies("deja_venu_ici", {
       :value => true,
       :expires => Time.now + (60*60*24*365)
    })
    @nouveau_visiteur = true
  end
end

get "/" do
  haml :index # peut utiliser @nouveau_visiteur
end
Tests
Vérifier le fonctionnement
Sessions




           Rack::Test
      Tests pour applications Rack
$ gem install rack-test
=> Successfully installed rack-test-0.5.7
require "blogue"
require "test/unit"
require "rack/test"

class BlogueTest < Test::Unit::TestCase
  include Rack::Test::Methods

  def app; Blogue; end

  def test_page_accueil
    get "/"
    assert_equal "Page d’accueil du blogue", last_response.body
  end

end
require "blogue"
require "test/unit"
require "rack/test"

class BlogueTest < Test::Unit::TestCase
  include Rack::Test::Methods

  def app; Blogue; end

  def test_redirection_mauvais_acces_au_tableau_de_bord
    get "/admin/dashboard"
    assert_equal "/admin/login", last_request.url
    assert last_response.ok?
  end

  def test_redirection_connexion_au_tableau_de_bord
    post "/admin/login", :username => "foo", :password => "bar"
    assert_equal "/admin/dashboard", last_request.url
    assert last_response.ok?
  end

end
$ ruby test.rb
=> Loaded suite test
   Started
   ..
   Finished in 0.009936 seconds.

   2 tests, 2 assertions, 0 failures, 0 errors
Déploiement
 d’une application
Déploiement




               Bundler
              Gestionnaire de gems
Déploiement




              Sans
              Bundler
# Contenu de config.ru
require "rubygems"
require "sinatra"
require "haml"
require "dm-core"

require "blogue"

run Blogue.new
$ gem install sinatra dm-core haml
=> Successfully installed rack 1.2.1
   Successfully installed tilt-1.2.2
   Successfully installed sinatra-1.1.3
   Successfully installed extlib-0.9.15
   Successfully installed dm-core-1.0.2
   Successfully installed haml-3.0.25
Déploiement




              Avec
              Bundler
$ gem install bundler
=> Successfully installed bundler-1.0.10
# Contenu du fichier Gemfile
source "http://rubygems.org"

gem "sinatra"
gem "haml"
gem "dm-core", "~> 1.0"
$ bundle install --path .bundle/gems
=> Fetching source index for http://rubygems.org/
   Installing addressable (2.2.4)
   Installing extlib (0.9.15)
   Installing dm-core (1.0.2)
   Installing haml (3.0.25)
   Installing rack (1.2.1)
   Installing tilt (1.2.2)
   Installing sinatra (1.1.3)
   Using bundler (1.0.10)
   Your bundle is complete! It was installed into ./bundle/gems
# Contenu de config.ru
require "bundler"
Bundler.require

require "blogue"

run Blogue.new
$ bundle exec rackup
=> INFO WEBrick::HTTPServer#start: pid=22866 port=9292
Déploiement




              Heroku
       Plateforme de déploiement
$ gem install heroku
=> Successfully installed configuration-1.2.0
   Successfully installed launchy-0.3.7
   Successfully installed heroku-1.17.16
   3 gems installed
$ git init
=> Initialized empty Git repository in /Code/blogue/.git/

$ echo ".bundle" > .gitignore
$ heroku create blogue
=> Creating blogue.... done
   http://blogue.heroku.com/ | git@heroku.com:blogue.git
   Git remote heroku added
$ git add .
$ git commit -m "Initial commit"
$ git push heroku master
=> Counting objects: 14, done.
   Delta compression using up to 2 threads.
   Compressing objects: 100% (10/10), done.
   Writing objects: 100% (14/14), 1.81 KiB, done.
   Total 14 (delta 0), reused 0 (delta 0)

   -----> Heroku receiving push
   -----> Sinatra app detected
   -----> Gemfile detected, running Bundler version 1.0.7
          Unresolved dependencies detected; Installing...
          …
          Your bundle is complete!
          Compiled slug size is 924K
   -----> Launching... done
          http://blogue.heroku.com deployed to Heroku

   To git@heroku.com:blogue.git
    * [new branch]      master -> master
Résumé
Sinatra en bref
Résumé




               Rack
         Compatible avec tout (!)
Résumé




  Développement
         minimaliste
Résumé




         Routes
         orientées « REST »
Résumé




         Templates
           flexibles
Résumé




           Sessions,
         cookies, tests, filtres, etc.
Résumé




  Déploiement
         facile avec Bundler
Résumé
Sinatra en bref
Ressources




 •   sinatrarb.com
 •   sinatra-book.gittr.com/
 •   peepcode.com/products/sinatra
 •   irc.freenode.net/sinatra (IRC)
 •   github.com/remiprev/nid (exemple)
Questions?
 Commentaires?
     @remi

Más contenido relacionado

La actualidad más candente

Beautiful CSS : Structurer, documenter, maintenir
Beautiful CSS : Structurer, documenter, maintenirBeautiful CSS : Structurer, documenter, maintenir
Beautiful CSS : Structurer, documenter, maintenirYves Van Goethem
 
PHP (Partie II) Par Mahdi Ben Alaya
PHP (Partie II) Par Mahdi Ben AlayaPHP (Partie II) Par Mahdi Ben Alaya
PHP (Partie II) Par Mahdi Ben AlayaMahdi Ben Alaya
 
Les blocs Drupal de drop.org à Drupal 8
Les blocs Drupal de drop.org à Drupal 8Les blocs Drupal de drop.org à Drupal 8
Les blocs Drupal de drop.org à Drupal 8OSInet
 
Panels, une autre façon de construire. DrupalCamp Paris 2013
Panels, une autre façon de construire. DrupalCamp Paris 2013Panels, une autre façon de construire. DrupalCamp Paris 2013
Panels, une autre façon de construire. DrupalCamp Paris 2013bellesmanieres
 
Cours php & Mysql - 1ére partie
Cours php & Mysql - 1ére partieCours php & Mysql - 1ére partie
Cours php & Mysql - 1ére partiekadzaki
 
Good governance by gov. yuvienco
Good governance by gov. yuviencoGood governance by gov. yuvienco
Good governance by gov. yuviencoRBAPAT54
 

La actualidad más candente (7)

HTML
HTMLHTML
HTML
 
Beautiful CSS : Structurer, documenter, maintenir
Beautiful CSS : Structurer, documenter, maintenirBeautiful CSS : Structurer, documenter, maintenir
Beautiful CSS : Structurer, documenter, maintenir
 
PHP (Partie II) Par Mahdi Ben Alaya
PHP (Partie II) Par Mahdi Ben AlayaPHP (Partie II) Par Mahdi Ben Alaya
PHP (Partie II) Par Mahdi Ben Alaya
 
Les blocs Drupal de drop.org à Drupal 8
Les blocs Drupal de drop.org à Drupal 8Les blocs Drupal de drop.org à Drupal 8
Les blocs Drupal de drop.org à Drupal 8
 
Panels, une autre façon de construire. DrupalCamp Paris 2013
Panels, une autre façon de construire. DrupalCamp Paris 2013Panels, une autre façon de construire. DrupalCamp Paris 2013
Panels, une autre façon de construire. DrupalCamp Paris 2013
 
Cours php & Mysql - 1ére partie
Cours php & Mysql - 1ére partieCours php & Mysql - 1ére partie
Cours php & Mysql - 1ére partie
 
Good governance by gov. yuvienco
Good governance by gov. yuviencoGood governance by gov. yuvienco
Good governance by gov. yuvienco
 

Destacado

Powering your website with realtime data
Powering your website with realtime dataPowering your website with realtime data
Powering your website with realtime databecoded
 
Open Source Communities (PHP Benelux Keynote)
Open Source Communities (PHP Benelux Keynote)Open Source Communities (PHP Benelux Keynote)
Open Source Communities (PHP Benelux Keynote)enaramore
 
Aloha editor contenteditable useable
Aloha editor contenteditable useableAloha editor contenteditable useable
Aloha editor contenteditable useableHaymo Meran
 
Confoo 2012-03-01 - Building mobile experiences that don't suck
Confoo 2012-03-01 - Building mobile experiences that don't suckConfoo 2012-03-01 - Building mobile experiences that don't suck
Confoo 2012-03-01 - Building mobile experiences that don't suckFrédéric Harper
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenchesLukas Smith
 

Destacado (6)

Powering your website with realtime data
Powering your website with realtime dataPowering your website with realtime data
Powering your website with realtime data
 
Open Source Communities (PHP Benelux Keynote)
Open Source Communities (PHP Benelux Keynote)Open Source Communities (PHP Benelux Keynote)
Open Source Communities (PHP Benelux Keynote)
 
Aloha editor contenteditable useable
Aloha editor contenteditable useableAloha editor contenteditable useable
Aloha editor contenteditable useable
 
Confoo 2012-03-01 - Building mobile experiences that don't suck
Confoo 2012-03-01 - Building mobile experiences that don't suckConfoo 2012-03-01 - Building mobile experiences that don't suck
Confoo 2012-03-01 - Building mobile experiences that don't suck
 
PHP Reset
PHP ResetPHP Reset
PHP Reset
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenches
 

Similar a Introduction à Sinatra

Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantHugo Hamon
 
Play Framework - Toulouse JUG - nov 2011
Play Framework - Toulouse JUG - nov 2011Play Framework - Toulouse JUG - nov 2011
Play Framework - Toulouse JUG - nov 2011Sylvain Wallez
 
Quoi de neuf dans Zend Framework 1.10 ?
Quoi de neuf dans Zend Framework 1.10 ?Quoi de neuf dans Zend Framework 1.10 ?
Quoi de neuf dans Zend Framework 1.10 ?Mickael Perraud
 
Atelier autour de UWA à ParisWeb 2007
Atelier autour de UWA à ParisWeb 2007Atelier autour de UWA à ParisWeb 2007
Atelier autour de UWA à ParisWeb 2007Netvibes
 
Quelle place pour le framework Rails dans le développement d'application web
Quelle place pour le framework Rails dans le développement d'application webQuelle place pour le framework Rails dans le développement d'application web
Quelle place pour le framework Rails dans le développement d'application web5pidou
 
LESS : moins de CSS, plus de fun ! (KiwiParty 2011)
LESS : moins de CSS, plus de fun ! (KiwiParty 2011)LESS : moins de CSS, plus de fun ! (KiwiParty 2011)
LESS : moins de CSS, plus de fun ! (KiwiParty 2011)Corinne Schillinger
 
Hands on lab Elasticsearch
Hands on lab ElasticsearchHands on lab Elasticsearch
Hands on lab ElasticsearchDavid Pilato
 
Rich Desktop Applications
Rich Desktop ApplicationsRich Desktop Applications
Rich Desktop Applicationsgoldoraf
 
Cours yeoman backbone box2d
Cours yeoman backbone box2dCours yeoman backbone box2d
Cours yeoman backbone box2dhugomallet
 
Présentation complète de l'HTML5
Présentation complète de l'HTML5Présentation complète de l'HTML5
Présentation complète de l'HTML5jverrecchia
 
La mobilité dans Drupal
La mobilité dans DrupalLa mobilité dans Drupal
La mobilité dans DrupalAdyax
 
démonstration code source site web ecole.docx
démonstration code source site web ecole.docxdémonstration code source site web ecole.docx
démonstration code source site web ecole.docxVincentBweka
 
Comment traduire ses bases de données sans douleur
Comment traduire ses bases de données sans douleurComment traduire ses bases de données sans douleur
Comment traduire ses bases de données sans douleurDavid Paccoud
 
Grails from scratch to prod - MixIT 2011
Grails from scratch to prod - MixIT 2011Grails from scratch to prod - MixIT 2011
Grails from scratch to prod - MixIT 2011Aurélien Maury
 
Gagnez en productivité grâce aux préprocesseurs css
Gagnez en productivité grâce aux préprocesseurs cssGagnez en productivité grâce aux préprocesseurs css
Gagnez en productivité grâce aux préprocesseurs csspefringant
 
Développement Web - HTML5, CSS3, APIs Web
Développement Web - HTML5, CSS3, APIs WebDéveloppement Web - HTML5, CSS3, APIs Web
Développement Web - HTML5, CSS3, APIs WebYoann Gotthilf
 
vue j'avais pas vu !!
vue j'avais pas vu !!vue j'avais pas vu !!
vue j'avais pas vu !!Manuel Adele
 
Vue, j’avais pas vu !
Vue, j’avais pas vu !Vue, j’avais pas vu !
Vue, j’avais pas vu !Bruno Bonnin
 
Comment évaluer la qualité d'un site web selon les techniques d'intégration w...
Comment évaluer la qualité d'un site web selon les techniques d'intégration w...Comment évaluer la qualité d'un site web selon les techniques d'intégration w...
Comment évaluer la qualité d'un site web selon les techniques d'intégration w...Renoir Boulanger
 

Similar a Introduction à Sinatra (20)

Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 Performant
 
Play Framework - Toulouse JUG - nov 2011
Play Framework - Toulouse JUG - nov 2011Play Framework - Toulouse JUG - nov 2011
Play Framework - Toulouse JUG - nov 2011
 
Quoi de neuf dans Zend Framework 1.10 ?
Quoi de neuf dans Zend Framework 1.10 ?Quoi de neuf dans Zend Framework 1.10 ?
Quoi de neuf dans Zend Framework 1.10 ?
 
Atelier autour de UWA à ParisWeb 2007
Atelier autour de UWA à ParisWeb 2007Atelier autour de UWA à ParisWeb 2007
Atelier autour de UWA à ParisWeb 2007
 
Quelle place pour le framework Rails dans le développement d'application web
Quelle place pour le framework Rails dans le développement d'application webQuelle place pour le framework Rails dans le développement d'application web
Quelle place pour le framework Rails dans le développement d'application web
 
LESS : moins de CSS, plus de fun ! (KiwiParty 2011)
LESS : moins de CSS, plus de fun ! (KiwiParty 2011)LESS : moins de CSS, plus de fun ! (KiwiParty 2011)
LESS : moins de CSS, plus de fun ! (KiwiParty 2011)
 
Hands on lab Elasticsearch
Hands on lab ElasticsearchHands on lab Elasticsearch
Hands on lab Elasticsearch
 
Rich Desktop Applications
Rich Desktop ApplicationsRich Desktop Applications
Rich Desktop Applications
 
Cours yeoman backbone box2d
Cours yeoman backbone box2dCours yeoman backbone box2d
Cours yeoman backbone box2d
 
Présentation complète de l'HTML5
Présentation complète de l'HTML5Présentation complète de l'HTML5
Présentation complète de l'HTML5
 
Tapestry
TapestryTapestry
Tapestry
 
La mobilité dans Drupal
La mobilité dans DrupalLa mobilité dans Drupal
La mobilité dans Drupal
 
démonstration code source site web ecole.docx
démonstration code source site web ecole.docxdémonstration code source site web ecole.docx
démonstration code source site web ecole.docx
 
Comment traduire ses bases de données sans douleur
Comment traduire ses bases de données sans douleurComment traduire ses bases de données sans douleur
Comment traduire ses bases de données sans douleur
 
Grails from scratch to prod - MixIT 2011
Grails from scratch to prod - MixIT 2011Grails from scratch to prod - MixIT 2011
Grails from scratch to prod - MixIT 2011
 
Gagnez en productivité grâce aux préprocesseurs css
Gagnez en productivité grâce aux préprocesseurs cssGagnez en productivité grâce aux préprocesseurs css
Gagnez en productivité grâce aux préprocesseurs css
 
Développement Web - HTML5, CSS3, APIs Web
Développement Web - HTML5, CSS3, APIs WebDéveloppement Web - HTML5, CSS3, APIs Web
Développement Web - HTML5, CSS3, APIs Web
 
vue j'avais pas vu !!
vue j'avais pas vu !!vue j'avais pas vu !!
vue j'avais pas vu !!
 
Vue, j’avais pas vu !
Vue, j’avais pas vu !Vue, j’avais pas vu !
Vue, j’avais pas vu !
 
Comment évaluer la qualité d'un site web selon les techniques d'intégration w...
Comment évaluer la qualité d'un site web selon les techniques d'intégration w...Comment évaluer la qualité d'un site web selon les techniques d'intégration w...
Comment évaluer la qualité d'un site web selon les techniques d'intégration w...
 

Introduction à Sinatra

  • 2. Rémi Prévost Développeur Web @remi + http://remiprevost.com
  • 3. Sinatra • Présentation • Installation • Utilisation • Déploiement
  • 5. Historique 2008 Blake Mizerany & Adam Wiggins
  • 6. Historique Problème Services Web légers
  • 7. Historique Solution Un micro-framework
  • 8. Historique Possibilités infinies
  • 9. Historique Prototypes d’applications Web
  • 10. Historique Applications Web complètes
  • 11. Historique APIs « RESTful »
  • 13. Avantages Installation rapide
  • 14. $ gem install sinatra => Successfully installed rack-1.2.1 Successfully installed tilt-1.2.2 Successfully installed sinatra-1.2.0
  • 16. # contenu de hello.rb require "sinatra" get "/" do "Hello world." end $ ruby -rubygems hello.rb => == Sinatra/1.2 has taken the stage on 4567… $ curl http://localhost:4567/ => Hello world.
  • 17. $ rails new blogue => create README create Rakefile create config.ru create .gitignore create Gemfile create app … $ du -hd0 => 428K .
  • 18. Avantages Déploiement facile
  • 19. Désavantages Les moins bons côtés
  • 20. Désavantages • Fonctionnalités réduites • Expansion moins guidée • Documentation moins large
  • 22. Rack Framework pour frameworks
  • 23. # contenu de config.ru class RackApp def call(env) [200, { "Content-type" => "text/html" }, "Hello world."] end end run RackApp.new $ rackup --env development => INFO WEBrick::HTTPServer#start: pid=37743 port=9292 $ curl http://localhost:9292/ => Hello world.
  • 24. # contenu de blogue.rb require "sinatra" class Blogue < Sinatra::Base # Code l’application Sinatra end # contenu de config.ru require "blogue" run Blogue.new
  • 25. # contenu de blogue.rb require "sinatra" # Code l’application Sinatra au premier niveau # contenu de config.ru require "blogue" run Sinatra::Application
  • 27. Routes REST Basées sur les méthodes HTTP
  • 28. Routes • GET • POST • PUT • DELETE
  • 30. methode_http(route) { reponse } get("/") { "Hello world." }
  • 31. Routes Statiques Routes fixes
  • 32. get "/" do "Page principale du blogue" end post "/admin/article" do "Création d’un nouvel article" end
  • 33. Routes Paramètres Routes variables
  • 34. get "/auteur/:username" do "Les billets de #{params[:username]}" end delete "/articles/:id" do "Suppression de l’article #{params[:id]}" end put "/articles/:id" do |id| "Modification de l’article #{id}" end
  • 35. Routes Splat Routes avec « wildcards »
  • 36. get "/fichiers/*.*" do # GET /fichiers/images/2011/03/foo.jpg # params[:splat] => ["/images/2011/03/foo", ".jpg"] end get "/*" do # GET /url/inconnu # params[:splat] => ["url/inconnu"] end
  • 37. Routes Regex Routes avec expressions
  • 38. get /^/(d{4})$/ do |annee| "Les articles de l’année #{annee}" # params["captures"] => [annee] end get %r{^(d{4})/(d{2})$} do |annee, mois| "Les articles du mois #{mois} de #{annee}" # params["captures"] => [annee, mois] end # seulement ruby 1.9 get %r{^(?<annee>d{4})/(?<mois>d{2})$} do "Les articles du mois #{params[:mois]} de #{params[:annee]}" end
  • 39. Routes Conditions Routes conditionnelles
  • 40. get "/", :agent => /msie [w.]+/i do "Page d’accueil pour Internet Explorer" end get "/" do "Page d’accueil pour les autres user-agents" end
  • 41. set(:secret) do |value| condition { params.include?(:secret) == value } end get "/", :secret => true do "Page d’accueil secrète!" end get "/" do "Page d’accueil régulière." end
  • 42. Routes • methode_http(route) { reponse } • Paramètres (réguliers, regex, splat) • Conditions
  • 44. Exécution Passer d’une route à la suivante
  • 45. get "/admin/dashboard" do pass unless authenticate! "Le tableau de bord secret" end get "/admin/*" do "Vous semblez ne pas être identifié." end
  • 46. Exécution Arrêter l’exécution du code
  • 47. get "/admin/dashboard" do halt(401, "Vous voulez hacker ce blogue?") unless authenticate! "Le tableau de bord secret" end
  • 48. Exécution Filtrer avant et après
  • 49. Exécution before Avant la route
  • 50. before "/admin/*" do halt(401, "Vous voulez hacker ce blogue?") unless authenticate! end get "/admin/dashboard" do "Tableau de bord de quelqu’un d’authentifié" end post "/admin/billets" do "Création d’un billet par quelqu’un d’authentifié" end
  • 51. before "/compte/*" do @user = User.find(session[:user_id]) end get "/compte/photo" do "Formulaire de modification de la photo de #{@user}" end get "/compte/motdepasse" do "Formulaire de modification du mot de passe de #{@user}" end
  • 52. before :agent => /msie 6.0/i do @message = "Vous utilisez un navigateur dépassé…" end
  • 53. Exécution after Après la route
  • 54. after "*" do headers "X-Secret-Data" => "LOL" end
  • 56. Templates Réponses compatibles avec Rack
  • 57. get "/" do "Page principale du blogue" end
  • 58. get "/" do [200, "Page principale du blogue"] end get "/api/articles.json" do [200, { "Content-type": "application/json" }, "[]"] end
  • 59. Templates Tilt Templates à la demande
  • 60. get "/" do haml :index end get "/css/screen.css" do sass :screen end get "/api/articles.xml" do nokogiri :"api/articles" end get "/api/articles.json" do coffee :"api/articles" end
  • 61. Templates Options pour chaque engin
  • 62. get "/" do haml :index, :format => :html4 end get "/css/screen.css" do scss :screen, :style => :compressed end
  • 63. set :haml, :format => :html5, :ugly => true set :scss, :style => :compressed
  • 64. Templates Internes Stockés dans le code Ruby
  • 65. enable :inline_templates get "/" do haml :index end __END__ @@ layout !!! %html %body =yield @@ index %h1 Bienvenue sur mon blogue.
  • 66. template :layout do "!!!n%htmln%bodyn=yieldn" end template :index do "%h1 Bienvenue sur mon blogue." end get "/" do haml :index end
  • 67. get "/" do haml "!!!n%body Bienvenue sur mon blogue." end
  • 68. Templates Externes Stockés en tant que fichiers
  • 69. get "/" do haml :index # /views/index.haml end get "/css/screen.css" do sass :screen # /views/screen.sass end get "/api/articles.xml" do builder :"api/articles"# /views/api/articles.builder end get "/api/articles.json" do coffee :"api/articles" # /views/api/articles.coffee end
  • 70. set :views, Proc.new { File.join(root, "templates") }
  • 71. Templates Layout Template commun
  • 72. get "/" do haml :index # template: views/index.haml # layout: views/layout.haml end get "/article/:id" do @article = Article.find(params[:id]) markdown :article, :layout_engine => :haml # template: views/article.markdown # layout: views/layout.haml end get "/ajax/article/:id.html" do @article = Article.find(params[:id]) haml :article, :layout => false # template: views/article.haml # layout: n/a end
  • 73. Templates Données Les utiliser dans les templates
  • 74. get "/" do @articles = Article.all haml :index end -# contenu de index.haml .hfeed - @articles.each do |article| .entry %h1= article.titre .entry-content = markdown(article.contenu)
  • 75. get "/" do articles = Article.all haml :index, :locals => { :articles => articles } end -# contenu de index.haml .hfeed - articles.each do |article| .entry %h1= article.titre .entry-content = markdown(article.contenu)
  • 76. get "/" do @articles = Article.all haml :index end -# contenu de index.haml .hfeed - @articles.each do |article| .entry = haml :article, :locals => { :article => article } -# contenu de article.haml .entry %h1= article.titre .entry-content = markdown(article.contenu)
  • 77. Templates Helpers Utilitaires disponibles partout
  • 78. helpers do def heading(level, text) "<h#{level}>#{text}</h#{level}>" end end %h1 Derniers articles %ul.articles - @articles.each do |article| %li =heading(2, article.title)
  • 79. helpers do def link_to(path, text) path = "#{request.host}#{path}" if request.xhr? "<a href="#{path}">#{text}</a>" end end def other_link_to(path, text) # n’a pas accès à `request` "<a href="#{path}">#{text}</a>" end %h1 Bienvenue %p= link_to "/", "Accueil" %p= other_link_to "/", "Accueil encore"
  • 80. Templates • Tilt • Options • Internes + Externes • Données • Helpers
  • 81. Configuration et environnements
  • 82. Configuration Globale à tous les environnements
  • 83. configure do DataMapper.setup :default, ENV["DATABASE_URL"] DataMapper::Pagination.defaults[:per_page] = 20 DataMapper::Logger.new $stdout, :debug end get "/" do @articles = Article.all haml :index end
  • 84. Configuration Spécifique à un environnement
  • 85. $ rackup --env development => INFO WEBrick::HTTPServer#start: pid=37743 port=9292 $ rackup --env production => INFO WEBrick::HTTPServer#start: pid=37743 port=9292 $ shotgun --env development == Shotgun/WEBrick on http://127.0.0.1:9393/ $ thin start --env production >> Thin web server (v1.2.8 codename Black Keys) >> Listening on 0.0.0.0:3000, CTRL+C to stop
  • 86. configure :development do set :scss, :style => :expanded set :haml, :ugly => false end configure :production do set :scss, :style => :compressed set :haml, :ugly => true end
  • 87. configure :development, :test do set :s3, { :bucket => "blogue-dev", :key => "efg456" } end configure :production do set :s3, { :bucket => "blogue", :key => "abc123" } end get "/" do "La valeur de s3/bucket est de #{settings.s3[:bucket]}" end
  • 89. Erreurs Routes introuvables
  • 90. not_found do "Cette page n’a pu être trouvée" end
  • 91. not_found do haml :erreur end
  • 92. Erreurs HTTP Codes d’erreurs standards
  • 93. error 403 do haml :"erreurs/interdit" end error 405..500 do haml :"erreurs/autre" end
  • 94. Erreurs Exceptions personnalisées
  • 95. error UnauthenticatedUser do haml :"erreurs/non_authentifie" end before "/admin/*" do raise UnauthenticatedUser unless authenticate! end
  • 97. Fichiers Fichiers publics
  • 98. $ tree . => "## blogue.rb "## config.ru "## public    "## css    %   &## screen.css    &## js    &## global.js $ curl http://localhost:9292/css/screen.css => … $ curl http://localhost:9292/js/global.js => …
  • 99. set :public, Proc.new { File.join(root, "fichiers/statiques") }
  • 101. get "/live/report.txt" do # Construction dynamique du fichier /tmp/report.txt # … send_file "/tmp/report.txt", :type => :attachment end
  • 103. Sessions Sessions Données temporaires encryptées
  • 104. enable :sessions before "/admin/*" do unless session[:admin] halt "Vous devez être <a href="/login">connecté</a>." end end get "/login" do haml :login end post "/login" do if params[:username] == "foo" and params[:password] == "bar" session[:admin] = true redirect "/admin" end end
  • 105. Sessions Cookies Données persistantes
  • 106. before do unless request.cookies.include?("deja_venu_ici") response.set_cookies("deja_venu_ici", { :value => true, :expires => Time.now + (60*60*24*365) }) @nouveau_visiteur = true end end get "/" do haml :index # peut utiliser @nouveau_visiteur end
  • 108. Sessions Rack::Test Tests pour applications Rack
  • 109. $ gem install rack-test => Successfully installed rack-test-0.5.7
  • 110. require "blogue" require "test/unit" require "rack/test" class BlogueTest < Test::Unit::TestCase include Rack::Test::Methods def app; Blogue; end def test_page_accueil get "/" assert_equal "Page d’accueil du blogue", last_response.body end end
  • 111. require "blogue" require "test/unit" require "rack/test" class BlogueTest < Test::Unit::TestCase include Rack::Test::Methods def app; Blogue; end def test_redirection_mauvais_acces_au_tableau_de_bord get "/admin/dashboard" assert_equal "/admin/login", last_request.url assert last_response.ok? end def test_redirection_connexion_au_tableau_de_bord post "/admin/login", :username => "foo", :password => "bar" assert_equal "/admin/dashboard", last_request.url assert last_response.ok? end end
  • 112. $ ruby test.rb => Loaded suite test Started .. Finished in 0.009936 seconds. 2 tests, 2 assertions, 0 failures, 0 errors
  • 114. Déploiement Bundler Gestionnaire de gems
  • 115. Déploiement Sans Bundler
  • 116. # Contenu de config.ru require "rubygems" require "sinatra" require "haml" require "dm-core" require "blogue" run Blogue.new
  • 117. $ gem install sinatra dm-core haml => Successfully installed rack 1.2.1 Successfully installed tilt-1.2.2 Successfully installed sinatra-1.1.3 Successfully installed extlib-0.9.15 Successfully installed dm-core-1.0.2 Successfully installed haml-3.0.25
  • 118. Déploiement Avec Bundler
  • 119. $ gem install bundler => Successfully installed bundler-1.0.10
  • 120. # Contenu du fichier Gemfile source "http://rubygems.org" gem "sinatra" gem "haml" gem "dm-core", "~> 1.0"
  • 121. $ bundle install --path .bundle/gems => Fetching source index for http://rubygems.org/ Installing addressable (2.2.4) Installing extlib (0.9.15) Installing dm-core (1.0.2) Installing haml (3.0.25) Installing rack (1.2.1) Installing tilt (1.2.2) Installing sinatra (1.1.3) Using bundler (1.0.10) Your bundle is complete! It was installed into ./bundle/gems
  • 122. # Contenu de config.ru require "bundler" Bundler.require require "blogue" run Blogue.new
  • 123. $ bundle exec rackup => INFO WEBrick::HTTPServer#start: pid=22866 port=9292
  • 124. Déploiement Heroku Plateforme de déploiement
  • 125. $ gem install heroku => Successfully installed configuration-1.2.0 Successfully installed launchy-0.3.7 Successfully installed heroku-1.17.16 3 gems installed
  • 126. $ git init => Initialized empty Git repository in /Code/blogue/.git/ $ echo ".bundle" > .gitignore
  • 127. $ heroku create blogue => Creating blogue.... done http://blogue.heroku.com/ | git@heroku.com:blogue.git Git remote heroku added
  • 128. $ git add . $ git commit -m "Initial commit" $ git push heroku master => Counting objects: 14, done. Delta compression using up to 2 threads. Compressing objects: 100% (10/10), done. Writing objects: 100% (14/14), 1.81 KiB, done. Total 14 (delta 0), reused 0 (delta 0) -----> Heroku receiving push -----> Sinatra app detected -----> Gemfile detected, running Bundler version 1.0.7 Unresolved dependencies detected; Installing... … Your bundle is complete! Compiled slug size is 924K -----> Launching... done http://blogue.heroku.com deployed to Heroku To git@heroku.com:blogue.git * [new branch] master -> master
  • 130. Résumé Rack Compatible avec tout (!)
  • 131. Résumé Développement minimaliste
  • 132. Résumé Routes orientées « REST »
  • 133. Résumé Templates flexibles
  • 134. Résumé Sessions, cookies, tests, filtres, etc.
  • 135. Résumé Déploiement facile avec Bundler
  • 137. Ressources • sinatrarb.com • sinatra-book.gittr.com/ • peepcode.com/products/sinatra • irc.freenode.net/sinatra (IRC) • github.com/remiprev/nid (exemple)