Sinatra est un DSL permettant de créer rapidement des applications Web dans Ruby avec un minimum d'effort :
# myapp.rb
require 'sinatra'
get '/' do
'Hello world!'
end
Installez les gemmes nécessaires :
gem install sinatra rackup puma
Et courez avec :
ruby myapp.rb
Voir sur : http://localhost:4567
Le code que vous avez modifié ne prendra effet qu'au redémarrage du serveur. Veuillez redémarrer le serveur chaque fois que vous modifiez ou utilisez un rechargeur de code comme une réexécution ou un rechargement de rack.
Il est recommandé d'exécuter également gem install puma
, que Sinatra récupérera si disponible.
yield
et mises en page imbriquéesDans Sinatra, une route est une méthode HTTP associée à un modèle de correspondance d'URL. Chaque itinéraire est associé à un bloc :
get '/' do
.. show something ..
end
post '/' do
.. create something ..
end
put '/' do
.. replace something ..
end
patch '/' do
.. modify something ..
end
delete '/' do
.. annihilate something ..
end
options '/' do
.. appease something ..
end
link '/' do
.. affiliate something ..
end
unlink '/' do
.. separate something ..
end
Les itinéraires sont mis en correspondance dans l'ordre dans lequel ils sont définis. La première route qui correspond à la demande est invoquée.
Les itinéraires avec des barres obliques finales sont différents de ceux sans :
get '/foo' do
# Does not match "GET /foo/"
end
Les modèles de route peuvent inclure des paramètres nommés, accessibles via le hachage params
:
get '/hello/:name' do
# matches "GET /hello/foo" and "GET /hello/bar"
# params['name'] is 'foo' or 'bar'
"Hello #{ params [ 'name' ] } !"
end
Vous pouvez également accéder aux paramètres nommés via les paramètres de bloc :
get '/hello/:name' do | n |
# matches "GET /hello/foo" and "GET /hello/bar"
# params['name'] is 'foo' or 'bar'
# n stores params['name']
"Hello #{ n } !"
end
Les modèles de route peuvent également inclure des paramètres splat (ou joker), accessibles via le tableau params['splat']
:
get '/say/*/to/*' do
# matches /say/hello/to/world
params [ 'splat' ] # => ["hello", "world"]
end
get '/download/*.*' do
# matches /download/path/to/file.xml
params [ 'splat' ] # => ["path/to/file", "xml"]
end
Ou avec des paramètres de bloc :
get '/download/*.*' do | path , ext |
[ path , ext ] # => ["path/to/file", "xml"]
end
Correspondance d'itinéraire avec des expressions régulières :
get / / hello / ([ w ]+)/ do
"Hello, #{ params [ 'captures' ] . first } !"
end
Ou avec un paramètre block :
get %r{/hello/([ w ]+)} do | c |
# Matches "GET /meta/hello/world", "GET /hello/world/1234" etc.
"Hello, #{ c } !"
end
Les modèles de route peuvent avoir des paramètres facultatifs :
get '/posts/:format?' do
# matches "GET /posts/" and any extension "GET /posts/json", "GET /posts/xml" etc
end
Les routes peuvent également utiliser des paramètres de requête :
get '/posts' do
# matches "GET /posts?title=foo&author=bar"
title = params [ 'title' ]
author = params [ 'author' ]
# uses title and author variables; query is optional to the /posts route
end
À propos, à moins que vous ne désactiviez la protection contre les attaques par traversée de chemin (voir ci-dessous), le chemin de la requête peut être modifié avant de correspondre à vos routes.
Vous pouvez personnaliser les options Mustermann utilisées pour un itinéraire donné en passant un hachage :mustermann_opts
:
get 'A/postsz' , :mustermann_opts => { :type => :regexp , :check_anchors => false } do
# matches /posts exactly, with explicit anchoring
"If you match an anchored pattern clap your hands!"
end
Cela ressemble à une condition, mais ce n’en est pas une ! Ces options seront fusionnées dans le hachage global :mustermann_opts
décrit ci-dessous.
Les routes peuvent inclure une variété de conditions de correspondance, telles que l'agent utilisateur :
get '/foo' , :agent => /Songbird ( d . d )[ d / ]*?/ do
"You're using Songbird version #{ params [ 'agent' ] [ 0 ] } "
end
get '/foo' do
# Matches non-songbird browsers
end
Les autres conditions disponibles sont host_name
et provides
:
get '/' , :host_name => /^admin . / do
"Admin Area, Access denied!"
end
get '/' , :provides => 'html' do
haml :index
end
get '/' , :provides => [ 'rss' , 'atom' , 'xml' ] do
builder :feed
end
provides
des recherches dans l'en-tête Accept de la demande.
Vous pouvez facilement définir vos propres conditions :
set ( :probability ) { | value | condition { rand <= value } }
get '/win_a_car' , :probability => 0.1 do
"You won!"
end
get '/win_a_car' do
"Sorry, you lost."
end
Pour une condition qui prend plusieurs valeurs, utilisez un splat :
set ( :auth ) do |* roles | # <- notice the splat here
condition do
unless logged_in? && roles . any? { | role | current_user . in_role? role }
redirect "/login/" , 303
end
end
end
get "/my/account/" , :auth => [ :user , :admin ] do
"Your Account Details"
end
get "/only/admin/" , :auth => :admin do
"Only admins are allowed here!"
end
La valeur de retour d'un bloc de route détermine au moins le corps de la réponse transmis au client HTTP ou au moins le middleware suivant dans la pile Rack. Le plus souvent, il s'agit d'une chaîne, comme dans les exemples ci-dessus. Mais d'autres valeurs sont également acceptées.
Vous pouvez renvoyer un objet qui serait soit une réponse Rack valide, un objet corps Rack ou un code d'état HTTP :
[status (Integer), headers (Hash), response body (responds to #each)]
[status (Integer), response body (responds to #each)]
#each
et ne transmet que des chaînes au bloc donnéDe cette façon, nous pouvons, par exemple, facilement implémenter un exemple de streaming :
class Stream
def each
100 . times { | i | yield " #{ i } n " }
end
end
get ( '/' ) { Stream . new }
Vous pouvez également utiliser la méthode d'assistance stream
(décrite ci-dessous) pour réduire le passe-partout et intégrer la logique de streaming dans l'itinéraire.
Comme indiqué ci-dessus, Sinatra est livré avec une prise en charge intégrée pour l'utilisation de modèles de chaînes et d'expressions régulières comme correspondances d'itinéraire. Mais cela ne s’arrête pas là. Vous pouvez facilement définir vos propres matchers :
class AllButPattern
def initialize ( except )
@except = except
end
def to_pattern ( options )
return self
end
def params ( route )
return { } unless @except === route
end
end
def all_but ( pattern )
AllButPattern . new ( pattern )
end
get all_but ( "/index" ) do
# ...
end
Notez que l'exemple ci-dessus peut être trop élaboré, car il peut également être exprimé comme suit :
get /.*/ do
pass if request . path_info == "/index"
# ...
end
Les fichiers statiques sont servis à partir du répertoire ./public
. Vous pouvez spécifier un emplacement différent en définissant l'option :public_folder
:
set :public_folder , __dir__ + '/static'
Notez que le nom du répertoire public n'est pas inclus dans l'URL. Un fichier ./public/css/style.css
est mis à disposition sous http://example.com/css/style.css
.
Utilisez le paramètre :static_cache_control
(voir ci-dessous) pour ajouter des informations d'en-tête Cache-Control
.
Chaque langage de modèle est exposé via sa propre méthode de rendu. Ces méthodes renvoient simplement une chaîne :
get '/' do
erb :index
end
Cela rend views/index.erb
.
Au lieu d'un nom de modèle, vous pouvez également simplement transmettre directement le contenu du modèle :
get '/' do
code = "<%= Time.now %>"
erb code
end
Les modèles prennent un deuxième argument, le hachage des options :
get '/' do
erb :index , :layout => :post
end
Cela rendra views/index.erb
intégrées dans les views/post.erb
(la valeur par défaut est views/layout.erb
, s'il existe).
Toutes les options non comprises par Sinatra seront transmises au moteur de modèles :
get '/' do
haml :index , :format => :html5
end
Vous pouvez également définir des options par langue de modèle en général :
set :haml , :format => :html5
get '/' do
haml :index
end
Les options transmises à la méthode render remplacent les options définies via set
.
Options disponibles :
Les modèles sont supposés se trouver directement sous le répertoire ./views
. Pour utiliser un autre répertoire de vues :
set :views , settings . root + '/templates'
Une chose importante à retenir est que vous devez toujours référencer les modèles avec des symboles, même s'ils se trouvent dans un sous-répertoire (dans ce cas, utilisez : :'subdir/template'
ou 'subdir/template'.to_sym
). Vous devez utiliser un symbole car sinon les méthodes de rendu rendront directement toutes les chaînes qui leur sont transmises.
get '/' do
haml '%div.title Hello World'
end
Renvoie la chaîne du modèle. Vous pouvez éventuellement spécifier :path
et :line
pour une trace plus claire s'il existe un chemin ou une ligne du système de fichiers associé à cette chaîne :
get '/' do
haml '%div.title Hello World' , :path => 'examples/file.haml' , :line => 3
end
Certains langages ont plusieurs implémentations. Pour spécifier quelle implémentation utiliser (et pour être thread-safe), vous devez simplement l'exiger en premier :
require 'rdiscount'
get ( '/' ) { markdown :index }
Dépendance | haml |
Extension du fichier | .haml |
Exemple | haml :index, :format => :html5 |
Dépendance | erubi ou erb (inclus dans Ruby) |
Extensions de fichiers | .erb , .rhtml ou .erubi (Erubi uniquement) |
Exemple | Erb :index |
Dépendance | constructeur |
Extension du fichier | .constructeur |
Exemple | constructeur { |xml| xml.em "salut" } |
Il faut également un bloc pour les modèles en ligne (voir exemple).
Dépendance | nokogiri |
Extension du fichier | .nokogiri |
Exemple | nokogiri { |xml| xml.em "salut" } |
Il faut également un bloc pour les modèles en ligne (voir exemple).
Dépendance | intégré sass |
Extension du fichier | .toupet |
Exemple | sass :feuille de style, :style => :expanded |
Dépendance | intégré sass |
Extension du fichier | .scss |
Exemple | scss :feuille de style, :style => :expanded |
Dépendance | liquide |
Extension du fichier | .liquide |
Exemple | liquide :index, :locals => { :key => 'valeur' } |
Étant donné que vous ne pouvez pas appeler de méthodes Ruby (sauf pour yield
) à partir d'un modèle Liquid, vous souhaitez presque toujours lui transmettre des informations locales.
Dépendance | N'importe qui parmi : RDiscount, RedCarpet, Kramdown, Commonmarker Pandoc |
Extensions de fichiers | .markdown , .mkd et .md |
Exemple | démarque :index, :layout_engine => :erb |
Il n'est pas possible d'appeler des méthodes depuis Markdown, ni de lui transmettre des locales. Vous l'utiliserez donc généralement en combinaison avec un autre moteur de rendu :
erb :overview , :locals => { :text => markdown ( :introduction ) }
Notez que vous pouvez également appeler la méthode markdown
depuis d'autres modèles :
% h1 Hello From Haml!
% p = markdown ( :greetings )
Puisque vous ne pouvez pas appeler Ruby depuis Markdown, vous ne pouvez pas utiliser de mises en page écrites en Markdown. Il est cependant possible d'utiliser un autre moteur de rendu pour le template que pour la mise en page en passant l'option :layout_engine
.
Dépendance | Rdoc |
Extension du fichier | .rdoc |
Exemple | rdoc :README, :layout_engine => :erb |
Il n'est pas possible d'appeler des méthodes depuis RDoc, ni de lui transmettre des locales. Vous l'utiliserez donc généralement en combinaison avec un autre moteur de rendu :
erb :overview , :locals => { :text => rdoc ( :introduction ) }
Notez que vous pouvez également appeler la méthode rdoc
depuis d'autres modèles :
% h1 Hello From Haml!
% p = rdoc ( :greetings )
Puisque vous ne pouvez pas appeler Ruby depuis RDoc, vous ne pouvez pas utiliser de mises en page écrites en RDoc. Il est cependant possible d'utiliser un autre moteur de rendu pour le template que pour la mise en page en passant l'option :layout_engine
.
Dépendance | Asciidocteur |
Extension du fichier | .asciidoc , .adoc et .ad |
Exemple | asciidoc :README, :layout_engine => :erb |
Comme vous ne pouvez pas appeler des méthodes Ruby directement à partir d'un modèle AsciiDoc, vous souhaitez presque toujours lui transmettre des informations locales.
Dépendance | Markaby |
Extension du fichier | .mab |
Exemple | markaby { h1 "Bienvenue !" } |
Il faut également un bloc pour les modèles en ligne (voir exemple).
Dépendance | Rabl |
Extension du fichier | .rabl |
Exemple | rabl :index |
Dépendance | Slim Lang |
Extension du fichier | .mince |
Exemple | mince :index |
Dépendance | yajl-rubis |
Extension du fichier | .yajl |
Exemple | yajl :index, :locals => { :key => 'qux' }, :callback => 'présent', :variable => 'resource' |
La source du modèle est évaluée comme une chaîne Ruby et la variable json résultante est convertie à l'aide de #to_json
:
json = { :foo => 'bar' }
json [ :baz ] = key
Les options :callback
et :variable
peuvent être utilisées pour décorer l'objet rendu :
var resource = { "foo" : "bar" , "baz" : "qux" } ;
present ( resource ) ;
Les modèles sont évalués dans le même contexte que les gestionnaires de routes. Les variables d'instance définies dans les gestionnaires de routes sont directement accessibles par les modèles :
get '/:id' do
@foo = Foo . find ( params [ 'id' ] )
haml '%h1= @foo.name'
end
Ou spécifiez un hachage explicite de variables locales :
get '/:id' do
foo = Foo . find ( params [ 'id' ] )
haml '%h1= bar.name' , :locals => { :bar => foo }
end
Ceci est généralement utilisé lors du rendu de modèles sous forme de partiels à partir d'autres modèles.
yield
et mises en page imbriquées Une mise en page n'est généralement qu'un modèle qui appelle yield
. Un tel modèle peut être utilisé soit via l'option :template
comme décrit ci-dessus, soit il peut être rendu avec un bloc comme suit :
erb :post , :layout => false do
erb :index
end
Ce code est principalement équivalent à erb :index, :layout => :post
.
Passer des blocs aux méthodes de rendu est très utile pour créer des mises en page imbriquées :
erb :main_layout , :layout => false do
erb :admin_layout do
erb :user
end
end
Cela peut également être fait en moins de lignes de code avec :
erb :admin_layout , :layout => :main_layout do
erb :user
end
Actuellement, les méthodes de rendu suivantes acceptent un bloc : erb
, haml
, liquid
, slim
. De plus, la méthode générale render
accepte un bloc.
Des modèles peuvent être définis à la fin du fichier source :
require 'sinatra'
get '/' do
haml :index
end
__END__
@@ layout
%html
!= yield
@@ index
%div.title Hello world.
REMARQUE : les modèles en ligne définis dans le fichier source qui nécessitent Sinatra sont automatiquement chargés. Appelez explicitement enable :inline_templates
si vous avez des modèles en ligne dans d’autres fichiers source.
Les modèles peuvent également être définis à l'aide de la méthode template
de niveau supérieur :
template :layout do
"%html n =yield n "
end
template :index do
'%div.title Hello World!'
end
get '/' do
haml :index
end
Si un modèle nommé « layout » existe, il sera utilisé à chaque rendu d'un modèle. Vous pouvez désactiver individuellement les mises en page en passant :layout => false
ou les désactiver par défaut via set :haml, :layout => false
:
get '/' do
haml :index , :layout => ! request . xhr?
end
Pour associer une extension de fichier à un moteur de modèle, utilisez Tilt.register
. Par exemple, si vous souhaitez utiliser l'extension de fichier tt
pour les modèles Haml, vous pouvez procéder comme suit :
Tilt . register Tilt [ :haml ] , :tt
Commencez par enregistrer votre moteur auprès de Tilt, puis créez une méthode de rendu :
Tilt . register MyAwesomeTemplateEngine , :myat
helpers do
def myat ( * args ) render ( :myat , * args ) end
end
get '/' do
myat :index
end
Rend ./views/index.myat
. En savoir plus sur l'inclinaison.
Pour implémenter votre propre mécanisme de recherche de modèle, vous pouvez écrire votre propre méthode #find_template
:
configure do
set :views , [ './views/a' , './views/b' ]
end
def find_template ( views , name , engine , & block )
Array ( views ) . each do | v |
super ( v , name , engine , & block )
end
end
Les filtres Before sont évalués avant chaque requête dans le même contexte que celui des routes et peuvent modifier la requête et la réponse. Les variables d'instance définies dans les filtres sont accessibles par des routes et des modèles :
before do
@note = 'Hi!'
request . path_info = '/foo/bar/baz'
end
get '/foo/*' do
@note #=> 'Hi!'
params [ 'splat' ] #=> 'bar/baz'
end
Les filtres After sont évalués après chaque requête dans le même contexte que celui des routes et peuvent également modifier la requête et la réponse. Les variables d'instance définies avant les filtres et les routes sont accessibles via les filtres après :
after do
puts response . status
end
Remarque : À moins que vous n'utilisiez la méthode body
plutôt que de simplement renvoyer une chaîne à partir des routes, le corps ne sera pas encore disponible dans le filtre after, puisqu'il est généré ultérieurement.
Les filtres prennent éventuellement un modèle, ce qui les oblige à être évalués uniquement si le chemin de la requête correspond à ce modèle :
before '/protected/*' do
authenticate!
end
after '/create/:slug' do | slug |
session [ :last_slug ] = slug
end
Comme les itinéraires, les filtres prennent également des conditions :
before :agent => /Songbird/ do
# ...
end
after '/blog/*' , :host_name => 'example.com' do
# ...
end
Utilisez la méthode helpers
de niveau supérieur pour définir des méthodes d'assistance à utiliser dans les gestionnaires de routes et les modèles :