138
Introduction à Sinatra Rémi Prévost — ConFoo 2011

Introduction à Sinatra

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Introduction à Sinatra

Introduction à

SinatraRémi Prévost — ConFoo 2011

Page 2: Introduction à Sinatra

Rémi Prévost

@remi + http://remiprevost.com

Développeur Web

Page 3: Introduction à Sinatra

• Présentation• Installation• Utilisation• Déploiement

Sinatra

Page 4: Introduction à Sinatra

Historiqueet possibilités

Page 5: Introduction à Sinatra

2008Blake Mizerany & Adam Wiggins

Historique

Page 6: Introduction à Sinatra

ProblèmeServices Web légers

Historique

Page 7: Introduction à Sinatra

SolutionUn micro-framework

Historique

Page 8: Introduction à Sinatra

Possibilitésinfinies

Historique

Page 9: Introduction à Sinatra

Prototypesd’applications Web

Historique

Page 10: Introduction à Sinatra

ApplicationsWeb complètes

Historique

Page 11: Introduction à Sinatra

APIs« RESTful »

Historique

Page 12: Introduction à Sinatra

AvantagesLes bons côtés

Page 13: Introduction à Sinatra

Installationrapide

Avantages

Page 14: Introduction à Sinatra

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

Page 15: Introduction à Sinatra

Développementminimaliste

Avantages

Page 16: Introduction à Sinatra

# contenu de hello.rbrequire "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.

Page 17: Introduction à Sinatra

$ rails new blogue=> create README create Rakefile create config.ru create .gitignore create Gemfile create app …

$ du -hd0=> 428K .

Page 18: Introduction à Sinatra

Déploiementfacile

Avantages

Page 19: Introduction à Sinatra

DésavantagesLes moins bons côtés

Page 20: Introduction à Sinatra

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

Désavantages

Page 21: Introduction à Sinatra

RackInterface HTTP

Page 22: Introduction à Sinatra

Frameworkpour frameworks

Rack

Page 23: Introduction à Sinatra

# contenu de config.ruclass RackApp def call(env) [200, { "Content-type" => "text/html" }, "Hello world."] endend

run RackApp.new

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

$ curl http://localhost:9292/=> Hello world.

Page 24: Introduction à Sinatra

# contenu de config.rurequire "blogue"

run Blogue.new

# contenu de blogue.rbrequire "sinatra"

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

Page 25: Introduction à Sinatra

# contenu de config.rurequire "blogue"

run Sinatra::Application

# contenu de blogue.rbrequire "sinatra"

# Code l’application Sinatra au premier niveau

Page 26: Introduction à Sinatra

RoutesLes directions

Page 27: Introduction à Sinatra

RESTBasées sur les méthodes HTTP

Routes

Page 28: Introduction à Sinatra

Routes

• GET• POST• PUT• DELETE

Page 29: Introduction à Sinatra

methode_http(route) { reponse }

Page 30: Introduction à Sinatra

methode_http(route) { reponse }

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

Page 31: Introduction à Sinatra

StatiquesRoutes fixes

Routes

Page 32: Introduction à Sinatra

get "/" do "Page principale du blogue"end

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

Page 33: Introduction à Sinatra

ParamètresRoutes variables

Routes

Page 34: Introduction à Sinatra

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

Page 35: Introduction à Sinatra

Splat Routes avec « wildcards »

Routes

Page 36: Introduction à Sinatra

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

Page 37: Introduction à Sinatra

RegexRoutes avec expressions

Routes

Page 38: Introduction à Sinatra

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.9get %r{^(?<annee>\d{4})/(?<mois>\d{2})$} do "Les articles du mois #{params[:mois]} de #{params[:annee]}"end

Page 39: Introduction à Sinatra

ConditionsRoutes conditionnelles

Routes

Page 40: Introduction à Sinatra

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

get "/" do "Page d’accueil pour les autres user-agents"end

Page 41: Introduction à Sinatra

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

Page 42: Introduction à Sinatra

Routes

• methode_http(route) { reponse }• Paramètres (réguliers, regex, splat)• Conditions

Page 43: Introduction à Sinatra

ExécutionPasser, arrêter ou filtrer

Page 44: Introduction à Sinatra

Passerd’une route à la suivante

Exécution

Page 45: Introduction à Sinatra

get "/admin/dashboard" do pass unless authenticate! "Le tableau de bord secret"end

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

Page 46: Introduction à Sinatra

Arrêterl’exécution du code

Exécution

Page 47: Introduction à Sinatra

get "/admin/dashboard" do halt(401, "Vous voulez hacker ce blogue?") unless authenticate! "Le tableau de bord secret"end

Page 48: Introduction à Sinatra

Filtreravant et après

Exécution

Page 49: Introduction à Sinatra

beforeAvant la route

Exécution

Page 50: Introduction à Sinatra

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

Page 51: Introduction à Sinatra

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

Page 52: Introduction à Sinatra

before :agent => /msie 6\.0/i do @message = "Vous utilisez un navigateur dépassé…"end

Page 53: Introduction à Sinatra

afterAprès la route

Exécution

Page 54: Introduction à Sinatra

after "*" do headers "X-Secret-Data" => "LOL"end

Page 55: Introduction à Sinatra

TemplatesLes vues

Page 56: Introduction à Sinatra

Réponsescompatibles avec Rack

Templates

Page 57: Introduction à Sinatra

get "/" do "Page principale du blogue"end

Page 58: Introduction à Sinatra

get "/" do [200, "Page principale du blogue"]end

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

Page 59: Introduction à Sinatra

TiltTemplates à la demande

Templates

Page 60: Introduction à Sinatra

get "/" do haml :indexend

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

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

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

Page 61: Introduction à Sinatra

Optionspour chaque engin

Templates

Page 62: Introduction à Sinatra

get "/" do haml :index, :format => :html4end

get "/css/screen.css" do scss :screen, :style => :compressedend

Page 63: Introduction à Sinatra

set :haml, :format => :html5, :ugly => trueset :scss, :style => :compressed

Page 64: Introduction à Sinatra

InternesStockés dans le code Ruby

Templates

Page 65: Introduction à Sinatra

enable :inline_templates

get "/" do haml :indexend

__END__

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

@@ index%h1 Bienvenue sur mon blogue.

Page 66: Introduction à Sinatra

template :layout do "!!!\n%html\n%body\n=yield\n"end

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

get "/" do haml :indexend

Page 67: Introduction à Sinatra

get "/" do haml "!!!\n%body Bienvenue sur mon blogue."end

Page 68: Introduction à Sinatra

ExternesStockés en tant que fichiers

Templates

Page 69: Introduction à Sinatra

get "/" do haml :index # /views/index.hamlend

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

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

get "/api/articles.json" do coffee :"api/articles" # /views/api/articles.coffeeend

Page 70: Introduction à Sinatra

set :views, Proc.new { File.join(root, "templates") }

Page 71: Introduction à Sinatra

LayoutTemplate commun

Templates

Page 72: Introduction à Sinatra

get "/" do haml :index # template: views/index.haml # layout: views/layout.hamlend

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

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

Page 73: Introduction à Sinatra

DonnéesLes utiliser dans les templates

Templates

Page 74: Introduction à Sinatra

get "/" do @articles = Article.all haml :indexend

-# contenu de index.haml.hfeed - @articles.each do |article| .entry %h1= article.titre .entry-content = markdown(article.contenu)

Page 75: Introduction à Sinatra

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)

Page 76: Introduction à Sinatra

get "/" do @articles = Article.all haml :indexend

-# 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)

Page 77: Introduction à Sinatra

HelpersUtilitaires disponibles partout

Templates

Page 78: Introduction à Sinatra

helpers do def heading(level, text) "<h#{level}>#{text}</h#{level}>" endend

%h1 Derniers articles%ul.articles - @articles.each do |article| %li =heading(2, article.title)

Page 79: Introduction à Sinatra

helpers do def link_to(path, text) path = "#{request.host}#{path}" if request.xhr? "<a href=\"#{path}\">#{text}</a>" endend

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"

Page 80: Introduction à Sinatra

Templates

• Tilt• Options• Internes + Externes• Données• Helpers

Page 81: Introduction à Sinatra

Configurationet environnements

Page 82: Introduction à Sinatra

Globaleà tous les environnements

Configuration

Page 83: Introduction à Sinatra

configure do DataMapper.setup :default, ENV["DATABASE_URL"] DataMapper::Pagination.defaults[:per_page] = 20 DataMapper::Logger.new $stdout, :debugend

get "/" do @articles = Article.all haml :indexend

Page 84: Introduction à Sinatra

Spécifiqueà un environnement

Configuration

Page 85: Introduction à Sinatra

$ 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

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

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

Page 86: Introduction à Sinatra

configure :development do set :scss, :style => :expanded set :haml, :ugly => falseend

configure :production do set :scss, :style => :compressed set :haml, :ugly => trueend

Page 87: Introduction à Sinatra

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

Page 88: Introduction à Sinatra

Erreursgérées comme des routes

Page 89: Introduction à Sinatra

Routesintrouvables

Erreurs

Page 90: Introduction à Sinatra

not_found do "Cette page n’a pu être trouvée"end

Page 91: Introduction à Sinatra

not_found do haml :erreurend

Page 92: Introduction à Sinatra

HTTPCodes d’erreurs standards

Erreurs

Page 93: Introduction à Sinatra

error 403 do haml :"erreurs/interdit"end

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

Page 94: Introduction à Sinatra

Exceptionspersonnalisées

Erreurs

Page 95: Introduction à Sinatra

error UnauthenticatedUser do haml :"erreurs/non_authentifie"end

before "/admin/*" do raise UnauthenticatedUser unless authenticate!end

Page 96: Introduction à Sinatra

Fichierset téléchargements

Page 97: Introduction à Sinatra

Fichierspublics

Fichiers

Page 98: Introduction à Sinatra

$ 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=> …

Page 99: Introduction à Sinatra

set :public, Proc.new { File.join(root, "fichiers/statiques") }

Page 100: Introduction à Sinatra

Téléchargementsde fichiers

Fichiers

Page 101: Introduction à Sinatra

get "/live/report.txt" do # Construction dynamique du fichier /tmp/report.txt # … send_file "/tmp/report.txt", :type => :attachmentend

Page 102: Introduction à Sinatra

Sessionset cookies

Page 103: Introduction à Sinatra

SessionsDonnées temporaires encryptées

Sessions

Page 104: Introduction à Sinatra

enable :sessions

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

get "/login" do haml :loginend post "/login" do if params[:username] == "foo" and params[:password] == "bar" session[:admin] = true redirect "/admin" endend

Page 105: Introduction à Sinatra

CookiesDonnées persistantes

Sessions

Page 106: Introduction à Sinatra

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 endend

get "/" do haml :index # peut utiliser @nouveau_visiteurend

Page 107: Introduction à Sinatra

TestsVérifier le fonctionnement

Page 108: Introduction à Sinatra

Rack::TestTests pour applications Rack

Sessions

Page 109: Introduction à Sinatra

$ gem install rack-test=> Successfully installed rack-test-0.5.7

Page 110: Introduction à Sinatra

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

Page 111: Introduction à Sinatra

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

Page 112: Introduction à Sinatra

$ ruby test.rb=> Loaded suite test Started .. Finished in 0.009936 seconds. 2 tests, 2 assertions, 0 failures, 0 errors

Page 113: Introduction à Sinatra

Déploiementd’une application

Page 114: Introduction à Sinatra

BundlerGestionnaire de gems

Déploiement

Page 115: Introduction à Sinatra

SansBundler

Déploiement

Page 116: Introduction à Sinatra

# Contenu de config.rurequire "rubygems"require "sinatra"require "haml"require "dm-core"

require "blogue"

run Blogue.new

Page 117: Introduction à Sinatra

$ 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

Page 118: Introduction à Sinatra

AvecBundler

Déploiement

Page 119: Introduction à Sinatra

$ gem install bundler=> Successfully installed bundler-1.0.10

Page 120: Introduction à Sinatra

# Contenu du fichier Gemfilesource "http://rubygems.org"

gem "sinatra"gem "haml"gem "dm-core", "~> 1.0"

Page 121: Introduction à Sinatra

$ 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

Page 122: Introduction à Sinatra

# Contenu de config.rurequire "bundler"Bundler.require

require "blogue"

run Blogue.new

Page 123: Introduction à Sinatra

$ bundle exec rackup=> INFO WEBrick::HTTPServer#start: pid=22866 port=9292

Page 124: Introduction à Sinatra

HerokuPlateforme de déploiement

Déploiement

Page 125: Introduction à Sinatra

$ gem install heroku=> Successfully installed configuration-1.2.0 Successfully installed launchy-0.3.7 Successfully installed heroku-1.17.16 3 gems installed

Page 126: Introduction à Sinatra

$ git init=> Initialized empty Git repository in /Code/blogue/.git/

$ echo ".bundle" > .gitignore

Page 127: Introduction à Sinatra

$ heroku create blogue=> Creating blogue.... done http://blogue.heroku.com/ | [email protected]:blogue.git Git remote heroku added

Page 128: Introduction à Sinatra

$ 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 [email protected]:blogue.git * [new branch] master -> master

Page 129: Introduction à Sinatra

RésuméSinatra en bref

Page 130: Introduction à Sinatra

RackCompatible avec tout (!)

Résumé

Page 131: Introduction à Sinatra

Développementminimaliste

Résumé

Page 132: Introduction à Sinatra

Routesorientées « REST »

Résumé

Page 133: Introduction à Sinatra

Templatesflexibles

Résumé

Page 134: Introduction à Sinatra

Sessions,cookies, tests, filtres, etc.

Résumé

Page 135: Introduction à Sinatra

Déploiementfacile avec Bundler

Résumé

Page 136: Introduction à Sinatra

RésuméSinatra en bref

Page 137: Introduction à Sinatra

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

Ressources

Page 138: Introduction à Sinatra

Questions?Commentaires?

@remi