Sinatra es un DSL para crear rápidamente aplicaciones web en Ruby con el mínimo esfuerzo:
# myapp.rb
require 'sinatra'
get '/' do
'Hello world!'
end
Instale las gemas necesarias:
gem install sinatra rackup puma
Y ejecuta con:
ruby myapp.rb
Ver en: http://localhost:4567
El código que cambió no tendrá efecto hasta que reinicie el servidor. Reinicie el servidor cada vez que cambie o utilice un recargador de código como rerun o rack-unreloader.
Se recomienda ejecutar también gem install puma
, que Sinatra seleccionará si está disponible.
yield
y diseños anidadosEn Sinatra, una ruta es un método HTTP emparejado con un patrón de coincidencia de URL. Cada ruta está asociada a un bloque:
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
Las rutas coinciden en el orden en que se definen. Se invoca la primera ruta que coincida con la solicitud.
Las rutas con barras diagonales son diferentes de las que no las tienen:
get '/foo' do
# Does not match "GET /foo/"
end
Los patrones de ruta pueden incluir parámetros con nombre, accesibles a través del hash params
:
get '/hello/:name' do
# matches "GET /hello/foo" and "GET /hello/bar"
# params['name'] is 'foo' or 'bar'
"Hello #{ params [ 'name' ] } !"
end
También puede acceder a parámetros con nombre a través de parámetros de bloque:
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
Los patrones de ruta también pueden incluir parámetros splat (o comodines), accesibles a través de la matriz 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
O con parámetros de bloque:
get '/download/*.*' do | path , ext |
[ path , ext ] # => ["path/to/file", "xml"]
end
Coincidencia de rutas con expresiones regulares:
get / / hello / ([ w ]+)/ do
"Hello, #{ params [ 'captures' ] . first } !"
end
O con un parámetro de bloque:
get %r{/hello/([ w ]+)} do | c |
# Matches "GET /meta/hello/world", "GET /hello/world/1234" etc.
"Hello, #{ c } !"
end
Los patrones de ruta pueden tener parámetros opcionales:
get '/posts/:format?' do
# matches "GET /posts/" and any extension "GET /posts/json", "GET /posts/xml" etc
end
Las rutas también pueden utilizar parámetros de consulta:
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
Por cierto, a menos que desactive la protección contra ataques de recorrido de ruta (ver más abajo), la ruta de solicitud podría modificarse antes de compararla con sus rutas.
Puede personalizar las opciones de Mustermann utilizadas para una ruta determinada pasando un hash :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
¡Parece una condición, pero no lo es! Estas opciones se fusionarán en el hash global :mustermann_opts
que se describe a continuación.
Las rutas pueden incluir una variedad de condiciones coincidentes, como el agente de usuario:
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
Otras condiciones disponibles son host_name
y 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
búsquedas en el encabezado Aceptar de la solicitud.
Puede definir fácilmente sus propias condiciones:
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
Para una condición que toma múltiples valores use un símbolo:
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
El valor de retorno de un bloque de ruta determina al menos el cuerpo de la respuesta pasado al cliente HTTP o al menos al siguiente middleware en la pila de Rack. Lo más común es que sea una cadena, como en los ejemplos anteriores. Pero también se aceptan otros valores.
Puede devolver un objeto que sería una respuesta válida de Rack, un objeto de cuerpo de Rack o un código de estado HTTP:
[status (Integer), headers (Hash), response body (responds to #each)]
[status (Integer), response body (responds to #each)]
#each
y no pasa nada más que cadenas al bloque dadoDe esa manera podemos, por ejemplo, implementar fácilmente un ejemplo de transmisión:
class Stream
def each
100 . times { | i | yield " #{ i } n " }
end
end
get ( '/' ) { Stream . new }
También puede utilizar el método de ayuda stream
(que se describe a continuación) para reducir el texto repetitivo e incorporar la lógica de transmisión en la ruta.
Como se muestra arriba, Sinatra viene con soporte incorporado para usar patrones de cadenas y expresiones regulares como coincidencias de rutas. Sin embargo, la cosa no se detiene ahí. Puedes definir fácilmente tus propios comparadores:
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
Tenga en cuenta que el ejemplo anterior podría estar sobredimensionado, ya que también se puede expresar como:
get /.*/ do
pass if request . path_info == "/index"
# ...
end
Los archivos estáticos se sirven desde el directorio ./public
. Puede especificar una ubicación diferente configurando la opción :public_folder
:
set :public_folder , __dir__ + '/static'
Tenga en cuenta que el nombre del directorio público no está incluido en la URL. Un archivo ./public/css/style.css
está disponible como http://example.com/css/style.css
.
Utilice la configuración :static_cache_control
(ver más abajo) para agregar información del encabezado Cache-Control
.
Cada lenguaje de plantilla se expone a través de su propio método de representación. Estos métodos simplemente devuelven una cadena:
get '/' do
erb :index
end
Esto representa views/index.erb
.
En lugar de un nombre de plantilla, también puedes pasar el contenido de la plantilla directamente:
get '/' do
code = "<%= Time.now %>"
erb code
end
Las plantillas toman un segundo argumento, el hash de opciones:
get '/' do
erb :index , :layout => :post
end
Esto mostrará views/index.erb
incrustado en views/post.erb
(el valor predeterminado es views/layout.erb
, si existe).
Cualquier opción que Sinatra no entienda se pasará al motor de plantillas:
get '/' do
haml :index , :format => :html5
end
También puede configurar opciones por idioma de plantilla en general:
set :haml , :format => :html5
get '/' do
haml :index
end
Las opciones pasadas al método de renderizado anulan las opciones establecidas mediante set
.
Opciones disponibles:
Se supone que las plantillas están ubicadas directamente en el directorio ./views
. Para utilizar un directorio de vistas diferente:
set :views , settings . root + '/templates'
Una cosa importante que debes recordar es que siempre debes hacer referencia a las plantillas con símbolos, incluso si están en un subdirectorio (en este caso, usa: :'subdir/template'
o 'subdir/template'.to_sym
). Debe utilizar un símbolo porque, de lo contrario, los métodos de representación representarán cualquier cadena que se les pase directamente.
get '/' do
haml '%div.title Hello World'
end
Representa la cadena de plantilla. Opcionalmente, puede especificar :path
y :line
para un seguimiento más claro si hay una ruta o línea del sistema de archivos asociada con esa cadena:
get '/' do
haml '%div.title Hello World' , :path => 'examples/file.haml' , :line => 3
end
Algunos lenguajes tienen múltiples implementaciones. Para especificar qué implementación usar (y que sea segura para subprocesos), simplemente debe solicitarla primero:
require 'rdiscount'
get ( '/' ) { markdown :index }
Dependencia | haml |
Extensión de archivo | .haml |
Ejemplo | haml :índice, :formato => :html5 |
Dependencia | erubi o erb (incluido en Ruby) |
Extensiones de archivos | .erb , .rhtml o .erubi (solo Erubi) |
Ejemplo | erb: índice |
Dependencia | constructor |
Extensión de archivo | .constructor |
Ejemplo | constructor { |xml| xml.em "hola" } |
También se necesita un bloque para plantillas en línea (ver ejemplo).
Dependencia | nokogiri |
Extensión de archivo | .nokogiri |
Ejemplo | nokogiri { |xml| xml.em "hola" } |
También se necesita un bloque para plantillas en línea (ver ejemplo).
Dependencia | descarado |
Extensión de archivo | .hablar con descaro a |
Ejemplo | sass :hoja de estilo, :estilo => :expandido |
Dependencia | descarado |
Extensión de archivo | .scss |
Ejemplo | scss :hoja de estilo, :estilo => :expandido |
Dependencia | líquido |
Extensión de archivo | .líquido |
Ejemplo | líquido :índice, :locales => { :clave => 'valor' } |
Como no puedes llamar a métodos de Ruby (excepto yield
) desde una plantilla de Liquid, casi siempre querrás pasarle valores locales.
Dependencia | Cualquiera de: RDiscount, RedCarpet, kramdown, commonmarker pandoc |
Extensiones de archivos | .markdown , .mkd y .md |
Ejemplo | rebaja: índice,: diseño_motor =>: erb |
No es posible llamar a métodos desde Markdown ni pasarle locales. Por lo tanto, normalmente lo utilizarás en combinación con otro motor de renderizado:
erb :overview , :locals => { :text => markdown ( :introduction ) }
Tenga en cuenta que también puede llamar al método markdown
desde otras plantillas:
% h1 Hello From Haml!
% p = markdown ( :greetings )
Como no puedes llamar a Ruby desde Markdown, no puedes usar diseños escritos en Markdown. Sin embargo, es posible utilizar otro motor de renderizado para la plantilla que no sea el del diseño pasando la opción :layout_engine
.
Dependencia | RDoc |
Extensión de archivo | .rdoc |
Ejemplo | rdoc :README, :layout_engine => :erb |
No es posible llamar a métodos desde RDoc, ni pasarle locales. Por lo tanto, normalmente lo utilizarás en combinación con otro motor de renderizado:
erb :overview , :locals => { :text => rdoc ( :introduction ) }
Tenga en cuenta que también puede llamar al método rdoc
desde otras plantillas:
% h1 Hello From Haml!
% p = rdoc ( :greetings )
Como no puedes llamar a Ruby desde RDoc, no puedes usar diseños escritos en RDoc. Sin embargo, es posible utilizar otro motor de renderizado para la plantilla que no sea el del diseño pasando la opción :layout_engine
.
Dependencia | asciidoctor |
Extensión de archivo | .asciidoc , .adoc y .ad |
Ejemplo | asciidoc :README, :layout_engine => :erb |
Como no puedes llamar a métodos Ruby directamente desde una plantilla AsciiDoc, casi siempre querrás pasarle archivos locales.
Dependencia | Markabí |
Extensión de archivo | .mab |
Ejemplo | markaby { h1 "¡Bienvenido!" } |
También se necesita un bloque para plantillas en línea (ver ejemplo).
Dependencia | rabl |
Extensión de archivo | .rabl |
Ejemplo | rabl :índice |
Dependencia | Lang delgado |
Extensión de archivo | .delgado |
Ejemplo | delgado: índice |
Dependencia | yajl-rubí |
Extensión de archivo | .yajl |
Ejemplo | yajl :index, :locals => { :key => 'qux' }, :callback => 'presente', :variable => 'recurso' |
La fuente de la plantilla se evalúa como una cadena Ruby y la variable json resultante se convierte usando #to_json
:
json = { :foo => 'bar' }
json [ :baz ] = key
Las opciones :callback
y :variable
se pueden usar para decorar el objeto renderizado:
var resource = { "foo" : "bar" , "baz" : "qux" } ;
present ( resource ) ;
Las plantillas se evalúan dentro del mismo contexto que los controladores de ruta. Las variables de instancia establecidas en los controladores de ruta son directamente accesibles mediante plantillas:
get '/:id' do
@foo = Foo . find ( params [ 'id' ] )
haml '%h1= @foo.name'
end
O especifique un Hash explícito de variables locales:
get '/:id' do
foo = Foo . find ( params [ 'id' ] )
haml '%h1= bar.name' , :locals => { :bar => foo }
end
Esto se utiliza normalmente cuando se representan plantillas como parciales desde otras plantillas.
yield
y diseños anidados Un diseño suele ser solo una plantilla que llama yield
. Dicha plantilla se puede usar a través de la opción :template
como se describe arriba, o se puede representar con un bloque de la siguiente manera:
erb :post , :layout => false do
erb :index
end
Este código es mayoritariamente equivalente a erb :index, :layout => :post
.
Pasar bloques a métodos de renderizado es más útil para crear diseños anidados:
erb :main_layout , :layout => false do
erb :admin_layout do
erb :user
end
end
Esto también se puede hacer en menos líneas de código con:
erb :admin_layout , :layout => :main_layout do
erb :user
end
Actualmente, los siguientes métodos de renderizado aceptan un bloque: erb
, haml
, liquid
, slim
. Además, el método render
general acepta un bloque.
Las plantillas se pueden definir al final del archivo fuente:
require 'sinatra'
get '/' do
haml :index
end
__END__
@@ layout
%html
!= yield
@@ index
%div.title Hello world.
NOTA: Las plantillas en línea definidas en el archivo fuente que requieren Sinatra se cargan automáticamente. Llame enable :inline_templates
explícitamente si tiene plantillas en línea en otros archivos fuente.
Las plantillas también se pueden definir utilizando el método template
de nivel superior:
template :layout do
"%html n =yield n "
end
template :index do
'%div.title Hello World!'
end
get '/' do
haml :index
end
Si existe una plantilla denominada "diseño", se utilizará cada vez que se represente una plantilla. Puede deshabilitar diseños individualmente pasando :layout => false
o deshabilitarlos de forma predeterminada mediante set :haml, :layout => false
:
get '/' do
haml :index , :layout => ! request . xhr?
end
Para asociar una extensión de archivo con un motor de plantillas, utilice Tilt.register
. Por ejemplo, si desea utilizar la extensión de archivo tt
para las plantillas Haml, puede hacer lo siguiente:
Tilt . register Tilt [ :haml ] , :tt
Primero, registre su motor con Tilt, luego cree un método de renderizado:
Tilt . register MyAwesomeTemplateEngine , :myat
helpers do
def myat ( * args ) render ( :myat , * args ) end
end
get '/' do
myat :index
end
Representa ./views/index.myat
. Obtenga más información sobre la inclinación.
Para implementar su propio mecanismo de búsqueda de plantillas, puede escribir su propio método #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
Los filtros Before se evalúan antes de cada solicitud dentro del mismo contexto en el que estarán las rutas y pueden modificar la solicitud y la respuesta. Las variables de instancia establecidas en los filtros son accesibles mediante rutas y plantillas:
before do
@note = 'Hi!'
request . path_info = '/foo/bar/baz'
end
get '/foo/*' do
@note #=> 'Hi!'
params [ 'splat' ] #=> 'bar/baz'
end
Los filtros posteriores se evalúan después de cada solicitud dentro del mismo contexto en el que estarán las rutas y también pueden modificar la solicitud y la respuesta. Las variables de instancia configuradas antes de los filtros y las rutas son accesibles mediante filtros posteriores:
after do
puts response . status
end
Nota: A menos que utilice el método body
en lugar de simplemente devolver una Cadena de las rutas, el cuerpo aún no estará disponible en el filtro posterior, ya que se genera más adelante.
Opcionalmente, los filtros toman un patrón, lo que hace que se evalúen solo si la ruta de la solicitud coincide con ese patrón:
before '/protected/*' do
authenticate!
end
after '/create/:slug' do | slug |
session [ :last_slug ] = slug
end
Al igual que las rutas, los filtros también aceptan condiciones:
before :agent => /Songbird/ do
# ...
end
after '/blog/*' , :host_name => 'example.com' do
# ...
end
Utilice el método helpers
de nivel superior para definir métodos de ayuda para su uso en plantillas y controladores de ruta: