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:
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
$ sudo gem install sinatra
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.
Siga os seguintes passos:
E para utilizar isto basta adicionar a seguinte linha no arquivo da sua aplicação:
$:.unshift File.dirname(__FILE__) + '/sinatra/lib'
require 'sinatra'
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
end
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?
# hello_world.rb
require 'rubygems'
require 'sinatra'
get '/' do
"Olá Mundo, agora é #{Time.now} no servidor!"
end
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.
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.
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.
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.
Simples
get '/hi' do
...
end
Com parâmetros
get '/:name' do
# matches /sinatra and the like and sets params[:name]
end
em breve
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
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
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.
post '/foo' do
"você requisitou por foo, com o parâmetro bar via post igual a #{params[:bar]}"
end
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 '/'
redirect '/posts/1'
redirect 'http://www.google.com'
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:
enable :sessions
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.
em breve
em breve
em breve
em breve
Cookies são bastante simples de se usar no Sinatra, porém com algumas ressalvas.
Vamos primeiro olhar um simples caso de uso:
require 'sinatra'
get '/' do
# Get the string representation
cookie = request.cookies["thing"]
# Set a default
cookie ||= 0
# Convert to an integer
cookie = cookie.to_i
# Do something with the value
cookie += 1
# Reset the cookie
set_cookie("thing", cookie)
# Render something
"Thing is now: #{cookie}"
end
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:
get '/' do
status 404
"Não funciona"
end
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.
em breve
Este filtro é executado em Sinatra::EventContext
before do
.. este código será executado antes de cada evento ..
end
Se você quiser usar um formulário com parametrôs ao estilo deste (aka. Rails’ nested params)
<form>
<input ... name="post[title]" />
<input ... name="post[body]" />
<input ... name="post[author]" />
</form>
Você deve converter os parametros para um hash. Você pode fazer isso facilmente usando o filtro “before”:
before do
new_params = {}
params.each_pair do |full_key, value|
this_param = new_params
split_keys = full_key.split(/\]\[|\]|\[/)
split_keys.each_index do |index|
break if split_keys.length == index + 1
this_param[split_keys[index]] ||= {}
this_param = this_param[split_keys[index]]
end
this_param[split_keys.last] = value
end
request.params.replace new_params
end
Para então se tornarem nos seguintes paramêtros:
{“post”=>{ “title”=>”“, “body”=>”“, “author”=>”” }}
Todos arquivos-base serão localizados na seguinte estrutura:
root
| - views/
get '/' do
haml :index
end
Isto irá renderizar ./views/index.haml
get '/' do
sass :styles
end
Isto irá renderizar ./views/styles.sass
get '/' do
erb :index
end
Isto irá renderizar ./views/index.erb
get '/' do
builder :index
end
Isto irá renderizar ./views/index.builder
get '/' do
builder do |xml|
xml.node do
xml.subnode "Texto interno"
end
end
end
Isto irá renderizar o xml inline, diretamente do handler.
em breve
Suponhamos que a url do site seja http://liftoff.msfc.nasa.gov/.
get '/rss.xml' do
builder do |xml|
xml.instruct! :xml, :version => '1.0'
xml.rss :version => "2.0" do
xml.channel do
xml.title "Liftoff News"
xml.description "Liftoff to Space Exploration."
xml.link "http://liftoff.msfc.nasa.gov/"
@posts.each do |post|
xml.item do
xml.title post.title
xml.link "http://liftoff.msfc.nasa.gov/posts/#{post.id}"
xml.description post.body
xml.pubDate Time.parse(post.created_at.to_s).rfc822()
xml.guid "http://liftoff.msfc.nasa.gov/posts/#{post.id}"
end
end
end
end
end
end
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:
%html
%head
%title SINATRA BOOK
%body
#container
= yield
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.
get '/' do
haml :index, :layout => false
end
Isto é uma fria:
get '/' do
haml :index
end
use_in_file_templates!
__END__
@@ layout
X
= yield
X
@@ index
%div.title Olá Mundo!!!!!
Experimente!
em breve
em breve
em breve
Primeiro você deverá incluir a gem ActiveRecord na sua aplicação, em seguida definir os dados de conexão ao banco de dados:
require 'rubygems'
require 'sinatra'
require 'activerecord'
ActiveRecord::Base.establish_connection(
:adapter => 'sqlite3',
: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)
class Post < ActiveRecord::Base
end
get '/' do
@posts = Post.all()
erb :index
end
Para renderizar isso em ./views/index.html:
<% for post in @posts %>
<h1><% post.title %></h1>
<% end %>
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.
Exemplo:
helpers do
def bar(name)
"#{name}bar"
end
end
get '/:name' do
bar(params[:name])
end
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:
# Usage: partial :foo
helpers do
def partial(page, options={})
haml page, options.merge!(:layout => false)
end
end
Uma versão mais avançada desse handler passando variaveis locais e interando um hash seria algo parecido com isto:
# Render the page once:
# Usage: partial :foo
#
# foo will be rendered once for each element in the array, passing in a local variable named "foo"
# Usage: partial :foo, :collection => @my_foos
helpers do
def partial(template, *args)
options = args.extract_options!
options.merge!(:layout => false)
if collection = options.delete(:collection) then
collection.inject([]) do |buffer, member|
buffer << haml(template, options.merge(
:layout => false,
:locals => {template.to_sym => member}
)
)
end.join("\n")
else
haml(template, options)
end
end
end
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:
require 'sinatra'
require 'my_custom_middleware'
use Rack::Lint
use MyCustomMiddleware
get '/hello' do
'Hello World'
end
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:
use Rack::Auth::Basic do |username, password|
username == 'admin' && password == 'secreto'
end
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
not_found do
'Isto esta longe de ser encontrado'
end
Por default os erros são capturados por Sinatra::ServerError
O Sinatra irá enviar seu erro através do ‘sinatra.error’ no request.env
error do
'Desculpe mas houve um erro desagradável - ' + request.env['sinatra.error'].name
end
Customizando o error mapping:
error MyCustomError do
'O que acabou de acontecer foi...' + request.env['sinatra.error'].message
end
se isto acontecer:
get '/' do
raise MyCustomError, 'algo terrível'
end
você irá obter isto:
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:
configure :production do
not_found do
"Desculpe-nos, mas isto não esta funcionando"
end
error do
"Algo realmente desagradável aconteceu. Estamos trabalhando nisto!"
end
end
Para interromper imediatamente um request durante ou antes com um filtro ou na utilização de um evento:
throw :halt
Para definir o corpo do resultado com um método helper:
throw :halt, :helper_method
Define o corpo do resultado com um método helper enviando depois com os parametros do escopo local
throw :halt, [:helper_method, foo, bar]
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
throw :halt, [401, [:helper_method, foo, bar]]
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”
class MyResultObject
def to_result(event_context, *args)
event_context.body = 'Isto será a mensagem!'
end
end
get '/' do
throw :halt, MyResultObject.new
end
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
.
configure :development do
set :dbname, 'devdb'
end
configure :production do
set :dbname, 'productiondb'
end
…
get '/qualbanco' do
'Você esta utilizando o banco de dados ' + options.dbname
end
em breve
em breve
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:
gem install thin
Crie seu arquivo de rackup - é necessario que tenha a linha “require ‘app’“, equivalente a sua aplicação Sinatra.
require 'app'
set :env, :production
set :port, 4567
disable :run, :reload
run Sinatra.application
Configure o config.yml - mude o /local/da/minha/app para o diretório correto da sua aplicação.
---
environment: production
chdir: /local/da/minha/app
address: 127.0.0.1
user: root
group: root
port: 4567
pid: /local/da/minha/app/thin.pid
rackup: /local/da/minha/app/config.ru
log: /local/da/minha/app/thin.log
max_conns: 1024
timeout: 30
max_persistent_conns: 512
daemonize: true
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.balance = "fair"
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”.
thin -s 2 -C config.yml -R config.ru 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 {
server 127.0.0.1:5000;
server 127.0.0.1:5001;
}
server {
listen www.mydomain.com:80
server_name www.mydomain.com live;
access_log /path/to/logfile.log
location / {
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
Domains -> Manage Domains -> Edit (web hosting column)
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'
Salve suas alterações
Criando a estrutura de diretórios
domain.com/
domain.com/tmp
domain.com/public
# 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 'rubygems'
require 'test.rb' # assuma que o arquivo da sua aplicação Sinatra seja 'test.rb'
set :env, :production
disable :run
run Sinatra.application
Uma aplicação Sinatra bastante simples
# este é o arquivo test.rb citado acima
get '/' do
"Trabalhando na dreamhost"
end
get '/foo/:bar' do
"Você requisitou por foo/#{params[:bar]}"
end
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:
Sinatra::Application.default_options.merge!(
:run => false,
: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:
.htaccess RewriteEngine on
AddHandler fastcgi-script .fcgi
Options +FollowSymLinks +ExecCGI
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
dispatch.fcgi #!/usr/bin/ruby
require 'sinatra/lib/sinatra.rb'
require 'rubygems'
fastcgi_log = File.open("fastcgi.log", "a")
STDOUT.reopen fastcgi_log
STDERR.reopen fastcgi_log
STDOUT.sync = true
set :logging, false
set :server, "FastCGI"
module Rack
class Request
def path_info
@env["REDIRECT_URL"].to_s
end
def path_info=(s)
@env["REDIRECT_URL"] = s.to_s
end
end
end
load 'test.rb'
sinatra.rb - Modificar esta função com uma nova versão aqui (descomentando as linhas puts
)
def run
begin
#puts "== Sinatra começou os trabalhos na porta #{port} para #{env} apoiado pelo #{server.name}"
require 'pp'
server.run(application) do |server|
trap(:INT) do
server.stop
#puts "\n== Sinatra já terminou sua configuração (e a multidão aplaude)"
end
end
rescue Errno::EADDRINUSE => e
#puts "== Algo já está sendo executando na porta #{port}!"
end
end
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:
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
run Sinatra.application
git push
$ git remote add heroku git@heroku.com:my-sinatra-app.git
$ git push heroku master
// 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:
Após isso, clonar o repositório do Sinatra será muito fácil bastando digitar a seguinte linha em sua linha de comando:
git clone git://github.com/bmizerany/sinatra.git
em breve
em breve