O que é Sinatra?
Vivendo com as novidades
Aplicação "Hello Word"
Aplicações do mundo real com Sinatra
os métodos PUT e DELETE
como as rotas são requisitadas
Padrão de Cookie baseado em Sessões
Memória baseada em sessões
Memcached baseado em sessões
Arquivos baseados em sessões
Banco de dados baseados em sessões
before do…
Manipulação de parametrôs aninhados ao estilo Rails
Linguagens de Template
evitando um layout
No arquivo das Views
implementando partials no estilo rails
Use as opções "set" do Sinatra
Arquivo de configuração externa através do bloco de configuração
Módulo da aplicação / Área de configuração
Lighttpd Proxied to Thin
Passenger (mod rails)
Fuzed e Amazon
Poolparty e Amazon EC2
Como eu posso clonar o repositório do Sinatra?
Como criar um patch?
Como enviar um path para o repositório oficial do Sinatra?
Sinatra é uma linguagem de domínio específico (DSL - Domain Specific Language) para a criação rápida de aplicações web escritas em ruby.
Ele mantém uma característica mínima definida, deixando livre o desenvolvedor para utilizar as ferramentas que melhor lhe servir em sua aplicação.
Ele não exige muito sobre sua aplicação, apenas que:
será escrito em linguagem de programação Ruby
terá URLs
Em Sinatra, você pode escrever pequenas ad hoc aplicações ou maduras e grandes aplicações coma a mesma facilidade. (Veja a seção "Aplicações do mundo real" depois neste livro.)
Você pode utilizar o poder de varias Rubygems e outras bibliotecas para Ruby disponíveis.
Sinatra realmente se destaca quando você utiliza-o para experimentos e aplicações mock-ups ou para criar uma rápida interface para o seu código.
Este não é um framework Model-View-Controller, mas controles especificos de URL que direciona para código Ruby relevante que retorna resultados como resposta. Isto irá habilitar você a escrever códigos limpos, com aplicações devidamente organizadas: separando as views do código da aplicação, por exemplo.
A maneira mais simples de se obter o Sinatra é através da rubygems
Sinatra depende da gem Rack (http://rack.rubyforge.org).
Para obter uma melhor experiência no uso você pode também instalar as gems Haml (http://haml.hamptoncatlin.com) e Builder (http://builder.rubyforge.org), que simplificarão os trabalhos com as views.
$ sudo gem install builder haml
As últimas novidades do Sinatra estão no Github, disponível em http://github.com/sinatra/sinatra/tree/master.
Você também pode utilizar a última versão para contribuir com novas funcionalidades para o framework.
cd local/do/seu/projeto
ln -s ../sinatra
E para utilizar isto basta adicionar a seguinte linha no arquivo da sua aplicação:
Você pode verificar qual a versão que a aplicação esta utilizando adicionando a seguinte rota:
get '/versao' do
"Versão utilizada: " + Sinatra::VERSION
para verificar o resultado acesse http://localhost:4567/versao.
O Sinatra já está instalado e você esta pronto para experimentá-lo, que tal construir sua primeira aplicação?
"Olá Mundo, agora é #{Time.now} no servidor!"
Rode isto com o seguinte comando $ ruby myapp.rb e visualize o resultado em http://localhost:4567
Git hosting disponibilizado pelo Github utiliza Sinatra para post-receive hooks, chamando os serviços/URLs especificas do usuário, sempre que alguém envia algo para os repositórios:
Git Wiki é um mecanismo minimo de Wiki desenvolvido com Sinatra e Git. Veja também os diversos forks com funcionalidades adicionais.
http://github.com/sr/git-wiki
http://github.com/sr/git-wiki/network
Integrity é um serviço pequeno e limpo de integração continua utilizando Sinatra, detectando falhas em builds de seu codebase e notificando você através de difersos canais de comunicação.
http://www.integrityapp.com/
http://github.com/foca/integrity
Seinfeld Calendar é uma divertida aplicação para monitorar as suas contribuições em projetos open-source, mostrando seus "streaks", ou seja seus commits em seus repositórios do Github.
http://www.calendaraboutnothing.com
http://github.com/entp/seinfeld
Este livro assume que você já tem um conhecimento básico da linguagem Ruby e sabe como funciona o interpretador Ruby.
Para maiores informações sobre a linguagem Ruby visite os seguintes links:
As rotas do Sinatra foram concebidas para responder a métodos de requisições HTTP.
Os outros métodos são requisitados exatamente da mesma forma como uma rota "get". Você simplesmente usa o "post", "put" ou "delete" que já estarão definidos como uma rota, além do "get" é claro. Para acessar os parâmetros POSTados, use params[:xxx] onde xxx é nome do elemento postado pelo seu formulário.
"você requisitou por foo, com o parâmetro bar via post igual a #{params[:bar]}"
Quando os browsers não suportavam nativamente os métodos PUT e DELETE, alguns hacks ou workaround eram adotados pela comunidade web. Bastava adicionar um elemento hidden com o nome "metodo" e o valor igual ao método HTTP que você desejava usar. O formulário continuará sendo enviado como um POST, porém o Sinatra irá interpretá-lo com o método desejado.
Quando você quiser usar PUT ou DELETE em um formulário com um browser que não tem suporte (da mesma forma como Curl ou ActiveResorce), simplesmente vá em frente e use-os normalmente, ignorando aquele método citado acima. Aquilo é apenas para "hackear" um suporte aos browsers.
Cada vez que você adiciona uma nova rota na sua aplicação, é compilada uma nova expressão regular para verifica-lá. Isto é guardado em um array através de um handler que adiciona um bloco de código para cada rota.
Quando é feita uma nova requisição, ela passa pela expressão regular que roda para verifica-lá. Então o handler (bloco de código) anexado para a rota é executado.
Handler é um termo genérico utilizado pelo Sinatra para "controllers". Um handler é o ponto inicial de entrada para uma nova requisição http em sua aplicação.
Para saber mais sobre rotas, leia o capitúlo Rotas (logo acima deste)
O helper redirect é um atalho para o código (302) de resposta http comum.
Basicamente é muito fácil:
redirect '/posts/1'
Atualmente o redirect envia de volta para o browser um Location header e o browser faz a requisição seguinte para o local indicado. Desde que o browser faça a requisição seguinte você poderá redirecionar para outra página em sua aplicação ou totalmente para um outro site.
O fluxo de requests durante um redirect é:
Browser –> Server (redirect to '/') –> Browser (request '/') –> Server (result for '/')
Sinatra envia por padrão o código de resposta 302. Segundo o spec, 302 não pode alterar o método de requisição, mas você vê uma nota na maioria dos browsers dizendo que irão mudar isto. Aparentemente os browsers mobile que as pessoas estão usando fazem as coisas corretamente ( ao invés de seguir má interpretação da maioria ).
A solução para isso no spec é enviar 2 diferentes códigos de resposta: 303 e 307. 303 reinicia o GET, 307 mantém o mesmo método.
Para forçar o sinatra a enviar um código de resposta diferente, é muito simples:
redirect '/', 303 # força o retorno do código 303
redirect '/', 307 # força o retorno do código 307
Sinatra possui um suporte básico para cookie baseado em sessão. Para habilitar isso, no bloco de configuração ou no inicio da sua aplicação, você precisará habilitar a seguinte opção:
A desvantagem desta abordagem com sessão é que todos os dados serão armazenados no cookie. Cookies sempre terão um limite de 4 kilobytes, você nao poderá armazenar muitos dados. Outra questão é que cookies não são invioláveis. O usuário poderá modificar quaisquer dados na sua sessão. Mas…. por ser muito fácil, não terá problemas tendo de escalar memória ou banco de dados para rodar de backend junto com a sessão.
Cookies são bastante simples de se usar no Sinatra, porém com algumas ressalvas.
Vamos primeiro olhar um simples caso de uso:
cookie = request.cookies["thing"]
cookie ||= 0
cookie = cookie.to_i
# Reset the cookie
"Thing is now: #{cookie}"
Definir um diretório, data de expiração ou domínio requer um pouco mais de complicação - veja o código-fonte do set_cookie se você quiser ir mais a fundo.
set_cookie("thing", { :domain => myDomain,
:path => myPath,
:expires => Date.new } )
Estas são as coisas mais simples com cookies - Você pode também serializar um objeto de Arrays, separando com "e" comercial (&), mas quando obter de volta, terá que desserializar e dividi-lo de qualquer forma, uma grande mão de obra, codificando uma string e depois parseando-a para o seu prazer.
Se você deseja definir seu próprio status para resposta ao invés do convencional 200 (Successo), você pode usar o helper status- para definir o código, e ainda assim renderizar normalmente:
Alternativamente você pode usar throw :halt, [404, "Not found"] para imediatamente parar futuras ações e retornar o código de status especificado e uma string para o cliente. throw suportam mais opções a respeito disto, consulte o capítulo adequado para maiores informações.
Este filtro é executado em Sinatra::EventContext
.. este código será executado antes de cada evento ..
Se você quiser usar um formulário com parametrôs ao estilo deste (aka. Rails' nested params)
<input ... name="post[title]" />
<input ... name="post[body]" />
<input ... name="post[author]" />
Você deve converter os parametros para um hash. Você pode fazer isso facilmente usando o filtro "before":
Para então se tornarem nos seguintes paramêtros:
{"post"=>{ "title"=>"", "body"=>"", "author"=>"" }}
Todos arquivos-base serão localizados na seguinte estrutura:
Isto irá renderizar ./views/index.haml
sass :styles
Isto irá renderizar ./views/styles.sass
Isto irá renderizar ./views/index.erb
Isto irá renderizar ./views/index.builder
xml.node do
xml.subnode "Texto interno"
Isto irá renderizar o xml inline, diretamente do handler.
Suponhamos que a url do site seja http://liftoff.msfc.nasa.gov/.
Isso irá renderizar o rss inline, diretamente no handler.
Layouts são muito simples no Sinatra. Crie um arquivo em seu diretório de views nomeado como "layout.erb", "layout.haml" ou "layout.builder". Quando a página renderizar, o layout apropriado será invocado (do mesmo tipo de arquivo) e usado.
O layout pode ter no seu contexto um ponto onde será realizada uma chamada para incluir outros conteúdos.
Um exemplo de um layout com haml seria um arquivo parecido com este:
%title SINATRA BOOK
Algumas vezes você deseja que o layout não seja renderizado. No seu método de renderização simplesmente passe :layout => false e você será o cara.
haml :index, :layout => false
Isto é uma fria:
Primeiro você deverá incluir a gem ActiveRecord na sua aplicação, em seguida definir os dados de conexão ao banco de dados:
:dbfile =>  'sinatra_application.sqlite3.db'
Agora você pode criar e usar modelos com o ActiveRecord assim como no Rails (o exemplo pressupõe que você já tem uma tabela 'posts' no seu banco de dados)
Para renderizar isso em ./views/index.html:
<h1><% post.title %></h1>
Não é aconselhável que você crie helpers na raiz da sua aplicação. Eles distorcem o namespace global e não têm um fácil acesso aos requests, reponse, session ou cookies.
Em vez disso, use o prático método Sinatra::EventContenxt para instalar helpers para o uso dentro de eventos e templates.
Usar partials em suas views é uma ótima maneira de mante-las limpas. Para que Sinatra possa se aproximar do design de um framework, você terá que implementar um handler de partial nele próprio.
Eis aqui uma versão realmente básica:
Uma versão mais avançada desse handler passando variaveis locais e interando um hash seria algo parecido com isto:
Sinatra pode rodar sob Rack, um padrão mínimo de interface para frameworks web escritos em Ruby. Uma das capacidades mais interessantes do Rack é a de se poder desenvolver uma aplicação sob um "middleware" — componente localizado entre o servidor e sua aplicação monitorando e/ou manipulando requisições/respostas HTTP fornecendo várias funcionalidades em comuns.
Sinatra faz a utilização de um canal Rack middleware através do uso muito fácil de um método de alto nível:
A semântica de utilização é idêntica a definida para o Rack:: Construtor DSL (mais frequentemente utilizado a partir do arquivo rackup). Como por exemplo, ao utilizar um método que aceita múltiplos/variáveis argumentos da mesma forma como os blocos:
username == 'admin' && password == 'secreto'
Rack é distribuída com uma variedade de middleware padrões para login, debug, URL routing, autenticação e manipulação de sessões. Sinatra usa muito desses componentes automaticamente baseado na configuração de modo que você normalmente não tenha que usá-los explicitamente.
Lembre-se: Isto irá rodar sob o Sinatra::EventContext que significa que você poderá te-lo em todos os bons formatos que lhe são oferecidos (i.e. haml, erb, :halt, etc.)
Sempre que uma NotFound é levantadas ela é tratada pela seguinte chamada
'Isto esta longe de ser encontrado'
Por default os erros são capturados por Sinatra::ServerError
O Sinatra irá enviar seu erro através do 'sinatra.error' no request.env
'Desculpe mas houve um erro desagradável - ' + request.env['sinatra.error'].name
Customizando o error mapping:
'O que acabou de acontecer foi...' + request.env['sinatra.error'].message
raise MyCustomError, 'algo terrível'
O que acabou de acontecer foi... algo terrível
Com Sinatra você pode tornar o padrão de error e not_found mais seguro em :production. Se você deseja customizar apenas para :production com uma tela mais amigável do que em :development então faça o seguinte:
"Desculpe-nos, mas isto não esta funcionando"
"Algo realmente desagradável aconteceu.  Estamos trabalhando nisto!"
Para interromper imediatamente um request durante ou antes com um filtro ou na utilização de um evento:
Para definir o corpo do resultado com um método helper:
Define o corpo do resultado com um método helper enviando depois com os parametros do escopo local
Para definir o corpo do resultado com uma string:
throw :halt, 'Isto será a mensagem!'
Para definir um status e depois o corpo da mensagem:
throw :halt, [401, 'vá embora!']
Define o status e então chama o método helper com os parametros do escopo local
Roda uma proc na instancia de Sinatra:EventContext e define o corpo do resultado
throw :halt, lambda { puts 'Na proc!'; 'Eu escrevi ao $stdout!' }
Crie seu próprio "toresult"
event_context.body = 'Isto será a mensagem!'
Blocos de configuração não são executados no contexto dos eventos e não possuem acesso as variaveis de instância. Para guardar um pedaço de informação que você queira acessar nas suas rotas, utilize set.
set :dbname, 'devdb'
set :dbname, 'productiondb'
get '/qualbanco' do
'Você esta utilizando o banco de dados ' + options.dbname
Iremos cobrir aqui como realizar o deploy no Sinatra com suporte a proxy reverso e load balancing utilizando Lighttpd e Thin.
Instalando Lighttpd e Thin
# Verifique se você já tem lighttpd, isto pode ser verificado através do gerenciado de pacotes da sua distribuição Linux
# Para o Thin:
Crie seu arquivo de rackup - é necessario que tenha a linha "require 'app'", equivalente a sua aplicação Sinatra.
set :env,       :production
set :port,      4567
Configure o config.yml - mude o /local/da/minha/app para o diretório correto da sua aplicação.
chdir: /local/da/minha/app
pid: /local/da/minha/app/thin.pid
rackup: /local/da/minha/app/config.ru
log: /local/da/minha/app/thin.log
Configure o lighttpd.conf - troque "mydomain" pelo edereço correto. Também marque corretamente a porta primária conforme configurado no config.yml.
$HTTP["host"] =~ "(www\.)?mydomain\.com"  {
proxy.server =  ("/" =>
( "host" => "127.0.0.1", "port" => 4567 ),
( "host" => "127.0.0.1", "port" => 4568 )
Inicie o thin e a sua aplicação. Eu criei um script que já faz isso chamado de "rake start".
Esta feito! Va até o seu dominio "mydomain.com/" e veja o resultado! Tudo pode ser configurado agora, verifique também a configuração do seu dominio no seu arquivo lighttpd.conf.
Variações - nginx via proxy - O mesmo acesso do proxy pode ser aplicado ao web server nginx
upstream www_mydomain_com {
listen		www.mydomain.com:80
server_name	www.mydomain.com live;
access_log /path/to/logfile.log
proxy_pass http://www_mydomain_com;
Variações - Mais instâncias Thin - Para adicionar mais instâncias thin, mude o paramêtro -s 2 no comando de inicialização do thin para a quantos servidores você deseja. E não se esqueça dos proxies lighttpd, adicionando uma nova linha para cada um deles. Após, reinicie o lighttpd e tudo irá subir conforme o esperado.
Odeia fazer deployment com FastCGI? Você não esta sozinho. Pois advinhe só, Passenger tem suporte a Rack; e este livro irá lhe dizer como fazer tudo isso.
Você pode encontrar documentação adicional sobre Passenger no seu repositório no Github.
Configurando através da interface de conta na Dreamhost
Habilite 'Ruby on Rails Passenger (mod_rails)'
Adicione o diretório "public" no campo para diretórios web. Caso você estiver usando 'rails.com', isto irá mudar para 'rails.com/public'
domain.com/tmp
# local para uma versão do sinatra - não necessário caso estiver usando gems
domain.com/sinatra
Criando o arquivo de "Rackup" (rack configuration file) config.ru
# Este arquivo irá ficar em domain.com/config.ru
require 'sinatra/lib/sinatra.rb'   # "require 'sinatra'" caso tiver sido instalado via gems
require 'test.rb' # assuma que o arquivo da sua aplicação Sinatra seja 'test.rb'
Uma aplicação Sinatra bastante simples
# este é o arquivo test.rb citado acima
"Trabalhando na dreamhost"
get '/foo/:bar' do
"Você requisitou por foo/#{params[:bar]}"
E isso é tudo que necessitamos por enquanto! Uma vez tudo configurado, acesse seu dominio e você já poderá ver a página "Trabalhando na dreamhost". Para reiniciar a aplicação após algumas mudanças, você precisará executar touch tmp/restart.txt.
Observe que na versão atual do passenger (2.0.3) existe um bug onde o Sinatra não encontra o diretório das views. Neste caso, adicione a opção :views => '/diretório/das/views/' no seu arquivo Rackup do Sinatra.
Nota complementar: algumas documentações terão um formato diferente de passar as opções no arquivo Rackup do Sinatra, como por exemplo:
:env => :production,
:raise_errors => true
O método padrão para fazer deployment é usando Thin ou Mongrel, e ter um proxy reverso (lighttpd, nginx ou mesmo Apache) apontando para o seus servidores.
Mas nem sempre isto é possível. Em hosts baratos e compartilhados (como Dreamhost) você não pode ter rodando Thin ou Mongrel, ou configurar proxy reverso (pelo menos no plano padrão compartilhado).
Felizmente, Rack suporta varias conexões, incluindo CGI e FastCGI. Infelizmente para nós, FastCGI não trabalha muito bem com a versão atual do Sinatra.
Para enviar um simples 'hello world' com uma aplicação Sinatra rodando na Dreamhost é necessário baixar todo o código atual do Sinatra, e hackear ele um pouco. Não se preocupe, isto somente requer comentar algumas linhas e ajustar algumas outras.
Passos para um deploy com FastCGI:
Tweaked sinatra.rb
dispatch.fcgi #!/usr/bin/ruby
fastcgi_log = File.open("fastcgi.log", "a")
set :server, "FastCGI"
sinatra.rb - Modificar esta função com uma nova versão aqui (descomentando as linhas puts)
#puts "== Sinatra começou os trabalhos na porta #{port} para #{env} apoiado pelo #{server.name}"
server.run(application) do |server|
#puts "\n== Sinatra já terminou sua configuração (e a multidão aplaude)"
#puts "== Algo já está sendo executando na porta #{port}!"
Heroku já tem um suporte basico para aplicações em Sinatra. Esta é provavelmente a opção mais fácil de deployment desde que configurada corretamente, deploying no heroku torna-se basicamente uma questão de um simples git push.
Passos para deploy no Heroku:
crie o config/rackup.ru
um exemplo de arquivo rackup:
require File.dirname(__FILE__) + "/../my_sinatra_app"
set     :app_file, File.expand_path(File.dirname(__FILE__) + '/../my_sinatra_app.rb')
set     :public,   File.expand_path(File.dirname(__FILE__) + '/../public')
set     :views,    File.expand_path(File.dirname(__FILE__) + '/../views')
set     :env,      :production
disable :run,      :reload
$ git remote add heroku git@heroku.com:my-sinatra-app.git
// TODO: Conversar com o Blake sobre isso
// TODO: Quais outras estratégias de deployment são usadas lá?
Antes de tudo, você precisará usar Git como seu sistema de controle de versão. Git está disponível para todas as principais plataformas:
Usuarios Linux e BSD geralmente conseguem adquirir o Git através do seu sistema de gerenciamento de pacotes, e.g. "apt-get install git-core" em sistemas Debian.
Após isso, clonar o repositório do Sinatra será muito fácil bastando digitar a seguinte linha em sua linha de comando:
Esta é uma tradução livre para o português realizada por Tailor R. Fontela, se você encontrar algum erro ou quiser colaborar com a evolução do projeto adicionando mais conteúdo faça um fork do projeto no Github.