Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add all README translations to website.

  • Loading branch information...
commit 4b2600d9e6ec66758c80092144ad0b47e7e1ac8b 1 parent 4ca6788
@rkh rkh authored
View
40 Rakefile
@@ -1,16 +1,20 @@
require 'rake/clean'
require 'rdoc/markup/to_html'
+def readme(pattern = "%s", &block)
+ return readme(pattern).each(&block) if block_given?
+ %w[en de es fr jp].map do |lang|
+ pattern % "README#{lang == "en" ? "" : ".#{lang}"}"
+ end
+end
+
task :default => ['_sinatra', :build]
desc "Build outdated static files and API docs"
task :build => ['build:static']
desc "Build outdated static files"
-task 'build:static' => [
- '_includes/README.html',
- '_includes/README.jp.html'
-]
+task 'build:static' => readme("_includes/%s.html")
desc "Build anything that's outdated and stage changes for next commit"
task :regen => [:build] do
@@ -36,25 +40,19 @@ end
file('_sinatra') { Rake::Task['pull:sinatra'].invoke }
CLOBBER.include '_sinatra'
-%w[README.rdoc README.jp.rdoc AUTHORS].each do |fn|
- file "_sinatra/#{fn}" => ['_sinatra']
-end
+readme("_sinatra/%s.rdoc") { |fn| file fn => '_sinatra' }
+file 'AUTHORS' => '_sinatra'
-# Build _includes/README.html from RDoc
-file '_includes/README.html' => ['_sinatra/README.rdoc', 'Rakefile'] do |f|
- html = RDoc::Markup::ToHtml.new.convert(File.read("_sinatra/README.rdoc")).
- sub("<h1>Sinatra</h1>", "")
- File.open(f.name, 'wb') { |io| io.write(html) }
-end
-CLEAN.include '_includes/README.html'
-
-# Build _includes/README.jp.html from RDoc
-file '_includes/README.jp.html' => ['_sinatra/README.jp.rdoc', 'Rakefile'] do |f|
- html = RDoc::Markup::ToHtml.new.convert(File.read("_sinatra/README.jp.rdoc")).
- sub("<h1>Sinatra</h1>", "")
- File.open(f.name, 'wb') { |io| io.write(html) }
+readme do |fn|
+ file "_includes/#{fn}.html" => ["_sinatra/#{fn}.rdoc", "Rakefile"] do |f|
+ html =
+ RDoc::Markup::ToHtml.new.
+ convert(File.read("_sinatra/#{fn}.rdoc")).
+ sub("<h1>Sinatra</h1>", "")
+ File.open(f.name, 'wb') { |io| io.write(html) }
+ end
+ CLEAN.include "_includes/#{fn}.html"
end
-CLEAN.include '_includes/README.jp.html'
desc 'Rebuild site under _site with Jekyll'
task :jekyll do
View
1,092 _includes/README.de.html
@@ -0,0 +1,1092 @@
+
+<p>
+<em>Wichtig: Dieses Dokument ist eine Übersetzung aus dem Englischen und
+unter Umständen nicht auf dem aktuellsten Stand.</em>
+</p>
+<p>
+Sinatra ist eine DSL, die das schnelle Erstellen von Webanwendungen in Ruby
+mit minimalen Aufwand ermöglicht:
+</p>
+<pre>
+ # myapp.rb
+ require 'sinatra'
+ get '/' do
+ 'Hallo Welt!'
+ end
+</pre>
+<p>
+Einfach via rubygems installieren und starten:
+</p>
+<pre>
+ gem install sinatra
+ ruby -rubygems myapp.rb
+</pre>
+<p>
+Die Seite kann nun unter <a href="http://localhost:4567">localhost:4567</a>
+betrachtet werden.
+</p>
+<h2>Routen</h2>
+<p>
+In Sinatra wird eine Route durch eine HTTP-Methode und ein URL-Muster
+definiert. Jeder dieser Routen wird ein Ruby-Block zugeordnet.
+</p>
+<pre>
+ get '/' do
+ .. zeige etwas ..
+ end
+
+ post '/' do
+ .. erstelle etwas ..
+ end
+
+ put '/' do
+ .. update etwas ..
+ end
+
+ delete '/' do
+ .. entferne etwas ..
+ end
+</pre>
+<p>
+Die Routen werden in der Reihenfolge durchlaufen, in der sie definiert
+wurden. Das erste Routemuster, das mit dem Request übereinstimmt, wird
+ausgeführt.
+</p>
+<p>
+Die Muster der Routen können benannte Parameter beinhalten, die über den
+<tt>params</tt>-Hash zugänglich gemacht werden:
+</p>
+<pre>
+ get '/hallo/:name' do
+ # passt auf &quot;GET /hallo/foo&quot; und &quot;GET /hallo/bar&quot;
+ # params[:name] ist 'foo' oder 'bar'
+ &quot;Hallo #{params[:name]}!&quot;
+ end
+</pre>
+<p>
+Man kann auf diese auch mit Blockparametern zugreifen:
+</p>
+<pre>
+ get '/hallo/:name' do |n|
+ &quot;Hallo #{n}!&quot;
+ end
+</pre>
+<p>
+Routenmuster können auch mit Splat- oder Wildcardparametern über das
+<tt>params[:splat]</tt> Array angesprochen werden.
+</p>
+<pre>
+ get '/sag/*/zu/*' do
+ # passt auf /sag/hallo/zu/welt
+ params[:splat] # =&gt; [&quot;hallo&quot;, &quot;welt&quot;]
+ end
+
+ get '/download/*.*' do
+ # passt auf /download/pfad/zu/datei.xml
+ params[:splat] # =&gt; [&quot;pfad/zu/datei&quot;, &quot;xml&quot;]
+ end
+</pre>
+<p>
+Routen mit regulären Ausdrücken sind auch möglich:
+</p>
+<pre>
+ get %r{/hallo/([\w]+)} do
+ &quot;Hallo, #{params[:captures].first}!&quot;
+ end
+</pre>
+<p>
+Und auch hier kann man Blockparameter nutzen:
+</p>
+<pre>
+ get %r{/hallo/([\w]+)} do |c|
+ &quot;Hallo, #{c}!&quot;
+ end
+</pre>
+<h3>Bedingungen</h3>
+<p>
+An Routen können eine Vielzahl von Bedingungen angehängt werden, die
+erfüllt sein müssen, damit der Block ausgeführt wird. Möglich wäre
+etwa eine Einschränkung des User Agents:
+</p>
+<pre>
+ get '/foo', :agent =&gt; /Songbird (\d\.\d)[\d\/]*?/ do
+ &quot;Du verwendest Songbird Version #{params[:agent][0]}&quot;
+ end
+
+ get '/foo' do
+ # passt auf andere Browser
+ end
+</pre>
+<p>
+Andere mitgelieferte Bedingungen sind <tt>host_name</tt> und
+<tt>provides</tt>:
+</p>
+<pre>
+ get '/', :host_name =&gt; /^admin\./ do
+ &quot;Adminbereich, Zugriff verweigert!&quot;
+ end
+
+ get '/', :provides =&gt; 'html' do
+ haml :index
+ end
+
+ get '/', :provides =&gt; ['rss', 'atom', 'xml'] do
+ builder :feed
+ end
+</pre>
+<p>
+Man kann auch relativ einfach eigene Bedingungen hinzufügen:
+</p>
+<pre>
+ set(:probability) { |value| condition { rand &lt;= value } }
+
+ get '/auto_gewinnen', :probability =&gt; 0.1 do
+ &quot;Du hast gewonnen!&quot;
+ end
+
+ get '/auto_gewinnen' do
+ &quot;Tut mir leid, verloren.&quot;
+ end
+</pre>
+<h3>Rückgabewerte</h3>
+<p>
+Durch den Rückgabewert eines Routenblocks wird mindestens der Response
+Body festgelegt, der an den HTTP Client, bzw die nächste Rack Middleware
+weitergegeben wird. Im Normalfall handelt es sich hierbei, wie in den
+vorangehenden Beispielen zu sehen war, um einen String. Es werden
+allerdings auch andere Werte akzeptiert.
+</p>
+<p>
+Man kann jedes Objekt zurückgeben, bei dem es sich entweder um einenen
+validen Rack-Rückgabewert, einen validen Rack-Body oder einen HTTP Status
+Code handelt:
+</p>
+<ul>
+<li><p>
+Ein Array mit drei Elementen: <tt>[Status (Fixnum), Headers (Hash),
+Response Body (hört auf #each)]</tt>
+</p>
+</li>
+<li><p>
+Ein Array mit zwei Elementen: <tt>[Status (Fixnum), Response Body (hört
+auf #each)]</tt>
+</p>
+</li>
+<li><p>
+Ein Objekt, das auf <tt>#each</tt> hört und den an diese Methode
+übergebenen Block nur mit Strings als Übergabewerte aufruft.
+</p>
+</li>
+<li><p>
+Ein Fixnum, das den Status Code festlegt.
+</p>
+</li>
+</ul>
+<p>
+Damit lässt sich relativ einfach Streaming implementieren:
+</p>
+<pre>
+ class Stream
+ def each
+ 100.times { |i| yield &quot;#{i}\n&quot; }
+ end
+ end
+
+ get('/') { Stream.new }
+</pre>
+<h2>Statische Dateien</h2>
+<p>
+Statische Dateien werden aus dem <tt>./public</tt> Ordner ausgeliefert. Es
+ist möglich einen anderen Ort zu definieren, indem man die
+<tt>:public</tt> Option setzt:
+</p>
+<pre>
+ set :public, File.dirname(__FILE__) + '/static'
+</pre>
+<p>
+Zu beachten ist, dass der Ordnername public nicht Teil der URL ist. Die
+Datei <tt>./public/css/style.css</tt> ist unter <tt><a
+href="http://example.com/css/style.css">example.com/css/style.css</a></tt>
+zu finden.
+</p>
+<h2>Views / Templates</h2>
+<p>
+Standardmäßig wird davon ausgegangen, dass sich Templates im
+<tt>./views</tt> Ordner befinden. Man kann jedoch einen anderen Ordner
+festlegen:
+</p>
+<pre>
+ set :views, File.dirname(__FILE__) + '/templates'
+</pre>
+<p>
+Eine wichtige Sache, die man sich hierbei merken sollte, ist das man immer
+mit Symbols auf Templates verweisen sollte, auch wenn sich ein Template in
+einem Unterordner befindet (in diesen Fall <tt>:'subdir/template'</tt>).
+Renderingmethoden rendern jeden String direkt.
+</p>
+<h3>Haml-Templates</h3>
+<p>
+Das haml gem wird benötigt, um Haml-Templates rendern zu können:
+</p>
+<pre>
+ ## haml muss eingebunden werden
+ require 'haml'
+
+ get '/' do
+ haml :index
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/index.haml</tt>.
+</p>
+<p>
+<a
+href="http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#options">Hamls
+Optionen</a> können global durch die Sinatrakonfiguration gesetzt werden,
+siehe <a href="http://www.sinatrarb.com/configuration.html">Optionen und
+Konfiguration</a>, und individuell überschrieben werden.
+</p>
+<pre>
+ set :haml, :format =&gt; :html5 # Standard Haml-Format ist :xhtml
+
+ get '/' do
+ haml :index, :format =&gt; :html4 # überschrieben
+ end
+</pre>
+<h3>Erb-Templates</h3>
+<pre>
+ ## erb muss eingebunden werden
+ require 'erb'
+
+ get '/' do
+ erb :index
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/index.erb</tt>.
+</p>
+<h3>Erubis</h3>
+<p>
+Das erubis gem wird benötigt, um Erubis-Templates rendern zu können:
+</p>
+<pre>
+ ## erbubis muss eingebunden werden
+ require 'erubis'
+
+ get '/' do
+ erubis :index
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/index.erubis</tt>.
+</p>
+<h3>Builder-Templates</h3>
+<p>
+Das buidler gem wird benötigt, um Builder-Templates rendern zu können:
+</p>
+<pre>
+ ## builder muss eingebunden werden
+ require 'builder'
+
+ get '/' do
+ builder :index
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/index.builder</tt>.
+</p>
+<h3>Nokogiri-Templates</h3>
+<p>
+Das nokogiri gem wird benötigt, um Nokogiri-Templates rendern zu können:
+</p>
+<pre>
+ ## nokogiri muss eingebunden werden
+ require 'nokogiri'
+
+ get '/' do
+ nokogiri :index
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/index.nokogiri</tt>.
+</p>
+<h3>Sass-Templates</h3>
+<p>
+Das haml gem wird benötigt, um SASS-Templates rendern zu können:
+</p>
+<pre>
+ ## sass muss eingebunden werden
+ require 'sass'
+
+ get '/stylesheet.css' do
+ sass :stylesheet
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/stylesheet.sass</tt>.
+</p>
+<p>
+<a
+href="http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options">Sass
+Optionen</a> können global durch die Sinatra-Konfiguration gesetzt werden,
+siehe <a href="http://www.sinatrarb.com/configuration.html">Optionen und
+Konfiguration</a>, und individuell überschrieben werden.
+</p>
+<pre>
+ set :sass, :style =&gt; :compact # Standard Sass-Style ist :nested
+
+ get '/stylesheet.css' do
+ sass :stylesheet, :style =&gt; :expanded # überschrieben
+ end
+</pre>
+<h3>Scss-Templates</h3>
+<p>
+Das haml gem wird benötigt, um SCSS-Templates rendern zu können:
+</p>
+<pre>
+ ## sass muss eingebunden werden
+ require 'sass'
+
+ get '/stylesheet.css' do
+ scss :stylesheet
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/stylesheet.scss</tt>.
+</p>
+<p>
+<a
+href="http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options">Scss
+Optionen</a> können global durch die Sinatra-Konfiguration gesetzt werden,
+siehe <a href="http://www.sinatrarb.com/configuration.html">Optionen und
+Konfiguration</a>, und individuell überschrieben werden.
+</p>
+<pre>
+ set :scss, :style =&gt; :compact # Standard Scss-Style ist :nested
+
+ get '/stylesheet.css' do
+ scss :stylesheet, :style =&gt; :expanded # überschrieben
+ end
+</pre>
+<h3>Less-Templates</h3>
+<p>
+Das less gem wird benötigt, um Less-Templates rendern zu können:
+</p>
+<pre>
+ ## less muss eingebunden werden
+ require 'less'
+
+ get '/stylesheet.css' do
+ less :stylesheet
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/stylesheet.less</tt>.
+</p>
+<h3>Liquid-Templates</h3>
+<p>
+Das liquid gem wird benötigt, um Liquid-Templates rendern zu können:
+</p>
+<pre>
+ ## liquid muss eingebunden werden
+ require 'liquid'
+
+ get '/' do
+ liquid :index
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/index.liquid</tt>.
+</p>
+<p>
+Da man aus Liquid-Templates heraus keine Methoden (abgesehen von
+<tt>yield</tt>) aufrufen kann, will man nahezu in allen Fällen
+<tt>locals</tt> übergeben:
+</p>
+<pre>
+ liquid :index, :locals =&gt; { :key =&gt; 'value' }
+</pre>
+<h3>Markdown-Templates</h3>
+<p>
+Das rdiscount gem wird benötigt, um Markdown-Templates rendern zu können:
+</p>
+<pre>
+ ## rdiscount muss eingebunden werden
+ require &quot;rdiscount&quot;
+
+ get '/' do
+ markdown :index
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/index.markdown</tt> (<tt>md</tt> und
+<tt>mkd</tt> sind ebenfalls zulässige Dateiendungen).
+</p>
+<p>
+Da es weder möglich ist Methoden aufzurufen, noch <tt>locals</tt> zu
+übergeben, ist es am sinnvollsten Markdown in Kombination mit einer
+anderen Template-Engine zu nutzen:
+</p>
+<pre>
+ erb :overview, :locals =&gt; { :text =&gt; markdown(:introduction) }
+</pre>
+<p>
+Es ist auch möglich die <tt>markdown</tt> Methode aus anderen Templates
+heraus aufzurufen:
+</p>
+<pre>
+ %h1 Hallo von Haml!
+ %p= markdown(:greetings)
+</pre>
+<h3>Textile-Templates</h3>
+<p>
+Das RedCloth gem wird benötigt, um Textile-Templates rendern zu können:
+</p>
+<pre>
+ ## redcloth muss eingebunden werden
+ require &quot;redcloth&quot;
+
+ get '/' do
+ textile :index
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/index.textile</tt>.
+</p>
+<p>
+Da es weder möglich ist Methoden aufzurufen, noch <tt>locals</tt> zu
+übergeben, ist es am sinnvollsten Textile in Kombination mit einer anderen
+Template-Engine zu nutzen:
+</p>
+<pre>
+ erb :overview, :locals =&gt; { :text =&gt; textile(:introduction) }
+</pre>
+<p>
+Es ist auch möglich die <tt>textile</tt> Methode aus anderen Templates
+heraus aufzurufen:
+</p>
+<pre>
+ %h1 Hallo von Haml!
+ %p= textile(:greetings)
+</pre>
+<h3>RDoc-Templates</h3>
+<p>
+Das rdoc gem wird benötigt, um RDoc-Templates rendern zu können:
+</p>
+<pre>
+ ## RDoc muss eingebunden werden
+ require &quot;rdoc&quot;
+
+ get '/' do
+ rdoc :index
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/index.rdoc</tt>.
+</p>
+<p>
+Da es weder möglich ist Methoden aufzurufen, noch <tt>locals</tt> zu
+übergeben, ist es am sinnvollsten RDoc in Kombination mit einer anderen
+Template-Engine zu nutzen:
+</p>
+<pre>
+ erb :overview, :locals =&gt; { :text =&gt; rdoc(:introduction) }
+</pre>
+<p>
+Es ist auch möglich die <tt>rdoc</tt> Methode aus anderen Templates heraus
+aufzurufen:
+</p>
+<pre>
+ %h1 Hallo von Haml!
+ %p= rdoc(:greetings)
+</pre>
+<h3>Radius-Templates</h3>
+<p>
+Das radius gem wird benötigt, um Radius-Templates rendern zu können:
+</p>
+<pre>
+ ## radius muss eingebunden werden
+ require 'radius'
+
+ get '/' do
+ radius :index
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/index.radius</tt>.
+</p>
+<p>
+Da man aus Radius-Templates heraus keine Methoden (abgesehen von
+<tt>yield</tt>) aufrufen kann, will man nahezu in allen Fällen
+<tt>locals</tt> übergeben:
+</p>
+<pre>
+ radius :index, :locals =&gt; { :key =&gt; 'value' }
+</pre>
+<h3>Markaby-Templates</h3>
+<p>
+Das markaby gem wird benötigt, um Markaby-Templates rendern zu können:
+</p>
+<pre>
+ ## markaby muss eingebunden werden
+ require 'markaby'
+
+ get '/' do
+ markaby :index
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/index.mab</tt>.
+</p>
+<h3>CoffeScript-Templates</h3>
+<p>
+Das coffee-script gem und das `coffee`-Programm werden benötigt, um
+CoffeScript-Templates rendern zu können:
+</p>
+<pre>
+ ## coffee-script muss eingebunden werden
+ require 'coffee-script'
+
+ get '/application.js' do
+ coffee :application
+ end
+</pre>
+<p>
+Dieser Code rendert <tt>./views/application.coffee</tt>.
+</p>
+<h3>Inline-Templates</h3>
+<pre>
+ get '/' do
+ haml '%div.title Hallo Welt'
+ end
+</pre>
+<p>
+Rendert den Inline-Template-String.
+</p>
+<h3>Auf Variablen in Templates zugreifen</h3>
+<p>
+Templates werden im selben Kontext ausgeführt wie Routen. Instanzvariablen
+in Routen sind auch direkt im Template verfügbar:
+</p>
+<pre>
+ get '/:id' do
+ @foo = Foo.find(params[:id])
+ haml '%h1= @foo.name'
+ end
+</pre>
+<p>
+Oder durch einen expliziten Hash von lokalen Variablen:
+</p>
+<pre>
+ get '/:id' do
+ foo = Foo.find(params[:id])
+ haml '%h1= foo.name', :locals =&gt; { :foo =&gt; foo }
+ end
+</pre>
+<p>
+Dies wird typischerweise bei Verwendung von Subtemplates (partials) in
+anderen Templates eingesetzt.
+</p>
+<h3>Inline-Templates</h3>
+<p>
+Templates können auch am Ende der Datei definiert werden:
+</p>
+<pre>
+ require 'sinatra'
+
+ get '/' do
+ haml :index
+ end
+
+ __END__
+
+ @@ layout
+ %html
+ = yield
+
+ @@ index
+ %div.title Hallo Welt!!!!!
+</pre>
+<p>
+Anmerkung: Inline-Templates die in der Datei definiert sind, die
+<tt>require 'sinatra'</tt> aufruft, werden automatisch geladen. Um andere
+Inline-Templates in anderen Dateien aufzurufen, muss <tt>enable
+:inline_templates</tt> explizit verwendet werden.
+</p>
+<h3>Benannte Templates</h3>
+<p>
+Templates können auch mit der Top-Level <tt>template</tt>-Methode
+definiert werden:
+</p>
+<pre>
+ template :layout do
+ &quot;%html\n =yield\n&quot;
+ end
+
+ template :index do
+ '%div.title Hallo Welt!'
+ end
+
+ get '/' do
+ haml :index
+ end
+</pre>
+<p>
+Wenn ein Template mit dem Namen &#8220;layout&#8221; existiert, wird es bei
+jedem Aufruf verwendet. Durch <tt>:layout =&gt; false</tt> kann das
+Ausführen verhindert werden.
+</p>
+<pre>
+ get '/' do
+ haml :index, :layout =&gt; !request.xhr?
+ end
+</pre>
+<h2>Helfer</h2>
+<p>
+Durch die Top-Level <tt>helpers</tt>-Methode, werden sogenannte
+Helfer-Methoden definiert, die in Routen und Templates verwendet werden
+können:
+</p>
+<pre>
+ helpers do
+ def bar(name)
+ &quot;#{name}bar&quot;
+ end
+ end
+
+ get '/:name' do
+ bar(params[:name])
+ end
+</pre>
+<h2>Filter</h2>
+<p>
+Before-Filter werden immer vor jedem Request in dem selben Kontext wie
+danach die Routen ausgeführt. So kann man etwa Request und Antwort
+ändern. Gesetzte Instanzvariablen in Filtern können in Routen und
+Templates verwendet werden:
+</p>
+<pre>
+ before do
+ @note = 'Hi!'
+ request.path_info = '/foo/bar/baz'
+ end
+
+ get '/foo/*' do
+ @note #=&gt; 'Hi!'
+ params[:splat] #=&gt; 'bar/baz'
+ end
+</pre>
+<p>
+After-Filter werden nach jedem Request im selben Kontext ausgeführt, und
+können ebenfalls Request und Antwort ändern. In Before-Filtern gesetzte
+Instanzvariablen können in After-Filterm verwendet werden:
+</p>
+<pre>
+ after do
+ puts response.status
+ end
+</pre>
+<p>
+Filter können optional auch mit einem Pattern ausgestattet werden, welche
+auf den Request-Pfad passen müssen, damit der Filter ausgeführt wird:
+</p>
+<pre>
+ before '/protected/*' do
+ authenticate!
+ end
+
+ after '/create/:slug' do |slug|
+ session[:last_slug] = slug
+ end
+</pre>
+<h2>Anhalten</h2>
+<p>
+Zum sofortigen stoppen eines Request in einem Filter oder einer Route:
+</p>
+<pre>
+ halt
+</pre>
+<p>
+Der Status kann beim stoppen auch angegeben werden:
+</p>
+<pre>
+ halt 410
+</pre>
+<p>
+Oder auch den Response-Body:
+</p>
+<pre>
+ halt 'Hier steht der Body'
+</pre>
+<p>
+Oder beides:
+</p>
+<pre>
+ halt 401, 'verschwinde!'
+</pre>
+<p>
+Sogar mit Headers:
+</p>
+<pre>
+ halt 402, {'Content-Type' =&gt; 'text/plain'}, 'Rache'
+</pre>
+<h2>Weiterspringen</h2>
+<p>
+Eine Route kann mittels <tt>pass</tt> zu der nächsten passenden Route
+springen:
+</p>
+<pre>
+ get '/raten/:wer' do
+ pass unless params[:wer] == 'Frank'
+ 'Du hast mich!'
+ end
+
+ get '/raten/*' do
+ 'Du hast mich verfehlt!'
+ end
+</pre>
+<p>
+Der Block wird sofort verlassen und es wird nach der nächsten treffenden
+Route gesucht. Ein 404 Fehler wird zurückgegeben, wenn kein treffendes
+Routen-Muster gefunden wird.
+</p>
+<h2>Konfiguration</h2>
+<p>
+Wird einmal beim Starten in jedweder Umgebung ausgeführt:
+</p>
+<pre>
+ configure do
+ ...
+ end
+</pre>
+<p>
+Läuft nur, wenn die Umgebung (RACK_ENV Umgebungsvariable) auf
+<tt>:production</tt> gesetzt ist:
+</p>
+<pre>
+ configure :production do
+ ...
+ end
+</pre>
+<p>
+Läuft nur, wenn die Umgebung auf <tt>:production</tt> oder auf
+<tt>:test</tt> gesetzt ist:
+</p>
+<pre>
+ configure :production, :test do
+ ...
+ end
+</pre>
+<h2>Fehlerbehandlung</h2>
+<p>
+Error Handler laufen im selben Kontext wie Routen und Filter, was bedeutet,
+dass alle Goodies wie <tt>haml</tt>, <tt>erb</tt>, <tt>halt</tt>, etc.
+verwendet werden können.
+</p>
+<h3>Nicht gefunden</h3>
+<p>
+Wenn eine <tt>Sinatra::NotFound</tt> Exception geworfen wird oder der
+Statuscode 404 ist, wird der <tt>not_found</tt> Handler ausgeführt:
+</p>
+<pre>
+ not_found do
+ 'Seite kann nirgendwo gefunden werden.'
+ end
+</pre>
+<h3>Fehler</h3>
+<p>
+Der <tt>error</tt> Handler wird immer ausgeführt, wenn eine Exception in
+einem Routenblock oder in einen Filter geworfen wurde. Die Exception kann
+über die <tt>sinatra.error</tt> Rack-Variable angesprochen werden:
+</p>
+<pre>
+ error do
+ 'Entschuldige es gab einen hässlichen Fehler - ' + env['sinatra.error'].name
+ end
+</pre>
+<p>
+Benutzerdefinierte Fehler:
+</p>
+<pre>
+ error MeinFehler do
+ 'Was passiert ist...' + request.env['sinatra.error'].message
+ end
+</pre>
+<p>
+Dann, wenn das passiert:
+</p>
+<pre>
+ get '/' do
+ raise MeinFehler, 'etwas schlechtes'
+ end
+</pre>
+<p>
+Bekommt man dieses:
+</p>
+<pre>
+ Was passiert ist... etwas schlechtes
+</pre>
+<p>
+Alternativ kann ein Error Handler auch für Statuscode definiert werden:
+</p>
+<pre>
+ error 403 do
+ 'Zugriff verboten'
+ end
+
+ get '/geheim' do
+ 403
+ end
+</pre>
+<p>
+Oder ein Statuscode-Bereich:
+</p>
+<pre>
+ error 400..510 do
+ 'Boom'
+ end
+</pre>
+<p>
+Sinatra setzt verschiedene <tt>not_found</tt> und <tt>error</tt> Handler in
+der Development Umgebung.
+</p>
+<h2>Mime-Types</h2>
+<p>
+Wenn <tt>send_file</tt> oder statische Dateien verwendet werden, kann es
+vorkommen, dass Sinatra den Mime-Typ nicht kennt. Registriert wird dieser
+mit <tt>mime_type</tt> per Dateiendung:
+</p>
+<pre>
+ mime_type :foo, 'text/foo'
+</pre>
+<p>
+Es kann aber auch der <tt>content_type</tt> Helfer verwendet werden:
+</p>
+<pre>
+ content_type :foo
+</pre>
+<h2>Rack Middleware</h2>
+<p>
+Sinatra baut auf <a href="http://rack.rubyforge.org/">Rack</a>, einem
+minimalen Standardinterface für Ruby Webframeworks. Eines der
+interessantesten Features für Entwickler ist der Support von Middleware,
+die zwischen den Server und die Anwendung geschaltet wird und so HTTP
+Request und/oder Antwort überwachen und/oder manipulieren kann.
+</p>
+<p>
+Sinatra macht das erstellen von Middleware-Verkettungen mit der Top-Level
+Methode <tt>use</tt> zu einem Kinderspiel:
+</p>
+<pre>
+ require 'sinatra'
+ require 'meine_middleware'
+
+ use Rack::Lint
+ use MeineMiddleware
+
+ get '/hallo' do
+ 'Hallo Welt'
+ end
+</pre>
+<p>
+Die Semantik von <tt>use</tt> entspricht der gleichnamigen Methode der <a
+href="http://rack.rubyforge.org/doc/classes/Rack/Builder.html">Rack::Builder</a>
+DSL (meist verwendet in Rackup-Dateien). Ein Beispiel dafür ist, dass die
+<tt>use</tt>-Methode mehrere/verschiedene Argumente und auch Blöcke
+entgegen nimmt:
+</p>
+<pre>
+ use Rack::Auth::Basic do |username, password|
+ username == 'admin' &amp;&amp; password == 'geheim'
+ end
+</pre>
+<p>
+Rack bietet eine Vielzahl von standard Middleware für Logging, Debugging,
+URL-Routing, Authentifizierung und Session-Verarbeitung. Sinatra verwendet
+viele von diesen Komponenten automatisch, abhängig von der Konfiguration.
+So muss man häufig <tt>use</tt> nicht explizit verwenden.
+</p>
+<h2>Testen</h2>
+<p>
+Sinatra Tests können mit jedem auf Rack aufbauendem Test Framework
+geschrieben werden. <a
+href="http://gitrdoc.com/brynary/rack-test">Rack::Test</a> wird empfohlen:
+</p>
+<pre>
+ require 'my_sinatra_app'
+ require 'rack/test'
+
+ class MyAppTest &lt; Test::Unit::TestCase
+ include Rack::Test::Methods
+
+ def app
+ Sinatra::Application
+ end
+
+ def test_my_default
+ get '/'
+ assert_equal 'Hallo Welt!', last_response.body
+ end
+
+ def test_with_params
+ get '/meet', :name =&gt; 'Frank'
+ assert_equal 'Hallo Frank!', last_response.body
+ end
+
+ def test_with_rack_env
+ get '/', {}, 'HTTP_USER_AGENT' =&gt; 'Songbird'
+ assert_equal &quot;Du verwendest Songbird!&quot;, last_response.body
+ end
+ end
+</pre>
+<p>
+Anmerkung: Das eingebaute Sinatra::Test Modul und die Sinatra::TestHarness
+Klasse werden seit Version 0.9.2 nicht mehr unterstützt.
+</p>
+<h2>Sinatra::Base - Middleware, Bibliotheken, und modulare Anwendungen</h2>
+<p>
+Das Definitieren einer Top-Level Anwendung funktioniert gut für
+Microanwendungen, hat aber Nachteile, wenn man wiederverwendbare
+Komponenten wie Middleware, Rails Metal, einfache Bibliotheken mit Server
+Komponenten oder auch Sinatra Erweiterungen bauen will. Die Top-Level DSL
+belastet den Objekt-Namespace und setzt einen Microanwendungsstil voraus
+(eine einzelne Anwendungsdatei, ./public und ./views Ordner, Logging,
+Exception-Detail-Seite, usw.). Genau hier kommt Sinatra::Base ins Spiel:
+</p>
+<pre>
+ require 'sinatra/base'
+
+ class MyApp &lt; Sinatra::Base
+ set :sessions, true
+ set :foo, 'bar'
+
+ get '/' do
+ 'Hallo Welt!'
+ end
+ end
+</pre>
+<p>
+Die MyApp-Klasse ist eine unabhängige Rack-Komponente, die als Middleware,
+Endpunkt oder via Rails Metal verwendet werden kann. Verwendet wird sie
+durch <tt>use</tt> oder <tt>run</tt> von einer Rackup <tt>config.ru</tt>
+Datei oder als Serverkomponente einer Bibliothek:
+</p>
+<pre>
+ MyApp.run! :host =&gt; 'localhost', :port =&gt; 9090
+</pre>
+<p>
+Die Methoden der Sinatra::Base-Subklasse sind genau die selben wie die der
+Top-Level DSL. Die meisten Top-Level Anwendungen können mit nur zwei
+Veränderungen zu Sinatra::Base-Komponenten konvertiert werden:
+</p>
+<ul>
+<li><p>
+Die Datei sollte <tt>require 'sinatra/base'</tt> anstelle von <tt>require
+'sinatra/base'</tt> aufrufen, ansonsten werden alle von Sinatras DSL
+Methoden in den Top-Level- Namespace importiert.
+</p>
+</li>
+<li><p>
+Alle Routen, Error Handler, Filter und Optionen der Applikation müssen in
+einer Subklasse von Sinatra::Base definiert werden.
+</p>
+</li>
+</ul>
+<p>
+<tt>Sinatra::Base</tt> ist ein unbeschriebense Blatt. Die meisten Optionen
+sind per default deaktiviert. Das betrifft auch den eingebauten Server.
+Siehe <a href="http://sinatra.github.com/configuration.html">Optionen und
+Konfiguration</a> für Details über möglichen Optionen.
+</p>
+<p>
+SIDEBAR: Sinatras Top-Level DSL-Methoden sind als einfache Delegationen
+implementiert. Die Sinatra::Application-Klasse &#8212; eine spezielle
+Subklasse von Sinatra::Base &#8212; erhält alle :get, :put, :post,
+:delete, :before, :error, :not_found, :configure und :set Meldungen, die
+vom Top-Level aus gesendet werden. Schau am besten im Code nach: Hier ist
+<a
+href="http://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1064">Sinatra::Delegator
+mixin</a> definiert und wird in den <a
+href="http://github.com/sinatra/sinatra/blob/master/lib/sinatra/main.rb#L25">globalen
+Namespace eingebunden</a>.
+</p>
+<h2>Kommandozeile</h2>
+<p>
+Sinatra Anwendungen können direkt von der Kommandozeile aus gestartet
+werden:
+</p>
+<pre>
+ ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-h HOST] [-s HANDLER]
+</pre>
+<p>
+Die Optionen sind:
+</p>
+<pre>
+ -h # Hilfe
+ -p # Port setzen (Standard ist 4567)
+ -h # Host setzen (Standard ist 0.0.0.0)
+ -e # Umgebung setzen (Standard ist development)
+ -s # Rack Server/Handler setzen (Standard ist thin)
+ -x # Mutex lock einschalten (Standard ist off)
+</pre>
+<h2>Der neueste Stand (The Bleeding Edge)</h2>
+<p>
+Um auf den neuesten Stand von Sinatras Code zu sein, kann eine lokale Kopie
+angelegt werden. Gestartet wird in der Anwendung mit dem
+<tt>sinatra/lib</tt> Ordner im <tt>LOAD_PATH</tt>:
+</p>
+<pre>
+ cd myapp
+ git clone git://github.com/sinatra/sinatra.git
+ ruby -Isinatra/lib myapp.rb
+</pre>
+<p>
+Alternativ kann der <tt>sinatra/lib</tt> Ordner zum <tt>LOAD_PATH</tt> in
+der Anwendung hinzugefügt werden:
+</p>
+<pre>
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
+ require 'rubygems'
+ require 'sinatra'
+
+ get '/ueber' do
+ &quot;Ich laufe auf Version &quot; + Sinatra::VERSION
+ end
+</pre>
+<p>
+Um Sinatra Code von Zeit zu Zeit zu aktualisieren:
+</p>
+<pre>
+ cd myproject/sinatra
+ git pull
+</pre>
+<h2>Mehr</h2>
+<ul>
+<li><p>
+<a href="http://sinatra.github.com/">Projekt Website</a> - Ergänzende
+Dokumentation, News und Links zu anderen Ressourcen.
+</p>
+</li>
+<li><p>
+<a href="http://sinatra.github.com/contributing.html">Hilfe beisteuern</a>
+- Einen Fehler gefunden? Brauchst du Hilfe? Hast du einen Patch?
+</p>
+</li>
+<li><p>
+<a href="http://github.com/sinatra/sinatra/issues">Issue Tracker</a>
+</p>
+</li>
+<li><p>
+<a href="http://twitter.com/sinatra">Twitter</a>
+</p>
+</li>
+<li><p>
+<a href="http://groups.google.com/group/sinatrarb">Mailingliste</a>
+</p>
+</li>
+<li><p>
+<a href="irc://chat.freenode.net/#sinatra">IRC: #sinatra</a> auf <a
+href="http://freenode.net">freenode.net</a>
+</p>
+</li>
+</ul>
View
1,325 _includes/README.es.html
@@ -0,0 +1,1325 @@
+
+<p>
+<em>Atención: Este documento es una traducción de la versión en inglés
+y puede estar desactualizado.</em>
+</p>
+<p>
+Sinatra es un DSL para crear aplicaciones web rápidamente en Ruby con un
+mínimo esfuerzo:
+</p>
+<pre>
+ # miapp.rb
+ require 'sinatra'
+
+ get '/' do
+ 'Hola mundo!'
+ end
+</pre>
+<p>
+Instalá la gem y ejecutá la aplicación con:
+</p>
+<pre>
+ gem install sinatra
+ ruby -rubygems miapp.rb
+</pre>
+<p>
+Podés verla en: <a href="http://localhost:4567">localhost:4567</a>
+</p>
+<h2>Rutas</h2>
+<p>
+En Sinatra, una ruta está compuesta por un método HTTP y un patrón de
+una URL. Cada ruta se asocia con un bloque:
+</p>
+<pre>
+ get '/' do
+ .. mostrar algo ..
+ end
+
+ post '/' do
+ .. crear algo ..
+ end
+
+ put '/' do
+ .. actualizar algo ..
+ end
+
+ delete '/' do
+ .. aniquilar algo ..
+ end
+</pre>
+<p>
+Las rutas son comparadas en el orden en el que son definidas. La primer
+ruta que coincide con la petición es invocada.
+</p>
+<p>
+Los patrones de las rutas pueden incluir parámetros nombrados, accesibles
+a través de el hash <tt>params</tt>:
+</p>
+<pre>
+ get '/hola/:nombre' do
+ # coincide con &quot;GET /hola/foo&quot; y &quot;GET /hola/bar&quot;
+ # params[:nombre] es 'foo' o 'bar'
+ &quot;Hola #{params[:nombre]}!&quot;
+ end
+</pre>
+<p>
+También podés acceder a los parámetros nombrados usando parámetros de
+bloque:
+</p>
+<pre>
+ get '/hola/:nombre' do |n|
+ &quot;Hola #{n}!&quot;
+ end
+</pre>
+<p>
+Los patrones de ruta también pueden incluir parámetros splat (o
+wildcard), accesibles a través del arreglo <tt>params[:splat]</tt>.
+</p>
+<pre>
+ get '/decir/*/al/*' do
+ # coincide con /decir/hola/al/mundo
+ params[:splat] # =&gt; [&quot;hola&quot;, &quot;mundo&quot;]
+ end
+
+ get '/descargar/*.*' do
+ # coincide con /descargar/path/al/archivo.xml
+ params[:splat] # =&gt; [&quot;path/al/archivo&quot;, &quot;xml&quot;]
+ end
+</pre>
+<p>
+Rutas con Expresiones Regulares:
+</p>
+<pre>
+ get %r{/hola/([\w]+)} do
+ &quot;Hola, #{params[:captures].first}!&quot;
+ end
+</pre>
+<p>
+O con un parámetro de bloque:
+</p>
+<pre>
+ get %r{/hola/([\w]+)} do |c|
+ &quot;Hola, #{c}!&quot;
+ end
+</pre>
+<h3>Condiciones</h3>
+<p>
+Las rutas pueden incluir una variedad de condiciones de selección, como
+por ejemplo el user agent:
+</p>
+<pre>
+ get '/foo', :agent =&gt; /Songbird (\d\.\d)[\d\/]*?/ do
+ &quot;Estás usando la versión de Songbird #{params[:agent][0]}&quot;
+ end
+
+ get '/foo' do
+ # Coincide con browsers que no sean songbird
+ end
+</pre>
+<p>
+Otras condiciones disponibles son <tt>host_name</tt> y <tt>provides</tt>:
+</p>
+<pre>
+ get '/', :host_name =&gt; /^admin\./ do
+ &quot;Área de Administración, Acceso denegado!&quot;
+ end
+
+ get '/', :provides =&gt; 'html' do
+ haml :index
+ end
+
+ get '/', :provides =&gt; ['rss', 'atom', 'xml'] do
+ builder :feed
+ end
+</pre>
+<p>
+Podés definir tus propias condiciones fácilmente:
+</p>
+<pre>
+ set(:probabilidad) { |valor| condition { rand &lt;= valor } }
+
+ get '/gana_un_auto', :probabilidad =&gt; 0.1 do
+ &quot;Ganaste!&quot;
+ end
+
+ get '/gana_un_auto' do
+ &quot;Lo siento, perdiste.&quot;
+ end
+</pre>
+<h3>Valores de retorno</h3>
+<p>
+El valor de retorno de un bloque de ruta determina al menos el cuerpo de la
+respuesta que se le pasa al cliente HTTP o al siguiente middleware en la
+pila de Rack. Lo más común es que sea un string, como en los ejemplos
+anteriores. Sin embargo, otros valor también son aceptados.
+</p>
+<p>
+Podés devolver cualquier objeto que sea una respuesta Rack válida, un
+objeto que represente el cuerpo de una respuesta Rack o un código de
+estado HTTP:
+</p>
+<ul>
+<li><p>
+Un arreglo con tres elementos: <tt>[estado (Fixnum), cabeceras (Hash),
+cuerpo de la respuesta (responde a #each)]</tt>
+</p>
+</li>
+<li><p>
+Un arreglo con dos elementos: <tt>[estado (Fixnum), cuerpo de la respuesta
+(responde a #each)]</tt>
+</p>
+</li>
+<li><p>
+Un objeto que responde a <tt>#each</tt> y que le pasa únicamente strings
+al bloque dado
+</p>
+</li>
+<li><p>
+Un Fixnum representando el código de estado
+</p>
+</li>
+</ul>
+<p>
+De esa manera podemos, por ejemplo, implementar fácilmente un streaming:
+</p>
+<pre>
+ class Stream
+ def each
+ 100.times { |i| yield &quot;#{i}\n&quot; }
+ end
+ end
+
+ get('/') { Stream.new }
+</pre>
+<h2>Archivos estáticos</h2>
+<p>
+Los archivos estáticos son servidos desde el directorio público
+<tt>./public</tt>. Podés especificar una ubicación diferente ajustando la
+opción <tt>:public</tt>:
+</p>
+<pre>
+ set :public, File.dirname(__FILE__) + '/estaticos'
+</pre>
+<p>
+Notá que el nombre del directorio público no está incluido en la URL.
+Por ejemplo, el archivo <tt>./public/css/style.css</tt> se accede a través
+de <tt><a
+href="http://ejemplo.com/css/style.css">ejemplo.com/css/style.css</a></tt>.
+</p>
+<h2>Vistas / Plantillas</h2>
+<p>
+Se asume que las plantillas están ubicadas directamente bajo el directorio
+<tt>./views</tt>. Para usar un directorio de vistas diferente:
+</p>
+<pre>
+ set :views, File.dirname(__FILE__) + '/plantillas'
+</pre>
+<p>
+Es importante acordarse que siempre tenés que referenciar a las plantillas
+con símbolos, incluso cuando se encuentran en un subdirectorio (en este
+caso tenés que usar <tt>:'subdir/plantilla'</tt>). Tenés que usar un
+símbolo porque los métodos de renderización van a renderizar
+directamente cualquier string que se les pase como argumento.
+</p>
+<h3>Plantillas Haml</h3>
+<p>
+La gem/librería haml es necesaria para para renderizar plantillas HAML:
+</p>
+<pre>
+ ## Vas a necesitar requerir haml en tu app
+ require 'haml'
+
+ get '/' do
+ haml :index
+ end
+</pre>
+<p>
+Renderiza <tt>./views/index.haml</tt>.
+</p>
+<p>
+Las <a
+href="http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#options">opciones
+de Haml</a> pueden ser ajustadas globalmente a través de las
+configuraciones de Sinatra, ver <a
+href="http://www.sinatrarb.com/configuration.html">Opciones y
+Configuraciones</a>, y reemplazadas individualmente.
+</p>
+<pre>
+ set :haml, :format =&gt; :html5 # el formato por defecto de Haml es :xhtml
+
+ get '/' do
+ haml :index, :format =&gt; :html4 # reemplazado
+ end
+</pre>
+<h3>Plantillas Erb</h3>
+<pre>
+ ## Vas a necesitar requerir erb en tu app
+ require 'erb'
+
+ get '/' do
+ erb :index
+ end
+</pre>
+<p>
+Renderiza <tt>./views/index.erb</tt>
+</p>
+<h3>Erubis</h3>
+<p>
+La gem/librería erubis es necesaria para renderizar plantillas erubis:
+</p>
+<pre>
+ ## Vas a necesitar requerir erubis en tu app
+ require 'erubis'
+
+ get '/' do
+ erubis :index
+ end
+</pre>
+<p>
+Renderiza <tt>./views/index.erubis</tt>
+</p>
+<h3>Plantillas Builder</h3>
+<p>
+La gem/librería builder es necesaria para renderizar plantillas builder:
+</p>
+<pre>
+ ## Vas a necesitar requerir builder en tu app
+ require 'builder'
+
+ get '/' do
+ builder :index
+ end
+</pre>
+<p>
+Renderiza <tt>./views/index.builder</tt>.
+</p>
+<h3>Plantillas Nokogiri</h3>
+<p>
+La gem/librería nokogiri es necesaria para renderizar plantillas nokogiri:
+</p>
+<pre>
+ ## Vas a necesitar requerir nokogiri en tu app
+ require 'nokogiri'
+
+ get '/' do
+ nokogiri :index
+ end
+</pre>
+<p>
+Renderiza <tt>./views/index.nokogiri</tt>.
+</p>
+<h3>Plantillas Sass</h3>
+<p>
+La gem/librería sass es necesaria para renderizar plantillas Sass:
+</p>
+<pre>
+ ## Vas a necesitar requerir haml o sass en tu app
+ require 'sass'
+
+ get '/stylesheet.css' do
+ sass :stylesheet
+ end
+</pre>
+<p>
+Renderiza <tt>./views/stylesheet.sass</tt>.
+</p>
+<p>
+Las <a
+href="http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options">opciones
+de Sass</a> pueden ser ajustadas globalmente a través de las
+configuraciones de Sinatra, ver <a
+href="http://www.sinatrarb.com/configuration.html">Opciones y
+Configuraciones</a>, y reemplazadas individualmente.
+</p>
+<pre>
+ set :sass, :style =&gt; :compact # el estilo por defecto de Sass es :nested
+
+ get '/stylesheet.css' do
+ sass :stylesheet, :style =&gt; :expanded # reemplazado
+ end
+</pre>
+<h3>Plantillas Scss</h3>
+<p>
+La gem/librería sass es necesaria para renderizar plantillas Scss:
+</p>
+<pre>
+ ## Vas a necesitar requerir haml o sass en tu app
+ require 'sass'
+
+ get '/stylesheet.css' do
+ scss :stylesheet
+ end
+</pre>
+<p>
+Renderiza <tt>./views/stylesheet.scss</tt>.
+</p>
+<p>
+Las <a
+href="http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options">opciones
+de Scss</a> pueden ser ajustadas globalmente a través de las
+configuraciones de Sinatra, ver <a
+href="http://www.sinatrarb.com/configuration.html">Opciones y
+Configuraciones</a>, y reemplazadas individualmente.
+</p>
+<pre>
+ set :scss, :style =&gt; :compact # el estilo por defecto de Sass es :nested
+
+ get '/stylesheet.css' do
+ scss :stylesheet, :style =&gt; :expanded # reemplazado
+ end
+</pre>
+<h3>Plantillas Less</h3>
+<p>
+La gem/librería less es necesaria para renderizar plantillas Less:
+</p>
+<pre>
+ ## Vas a necesitar requerir less en tu app
+ require 'less'
+
+ get '/stylesheet.css' do
+ less :stylesheet
+ end
+</pre>
+<p>
+Renderiza <tt>./views/stylesheet.less</tt>.
+</p>
+<h3>Plantillas Liquid</h3>
+<p>
+La gem/librería liquid es necesaria para renderizar plantillas Liquid:
+</p>
+<pre>
+ ## Vas a necesitar requerir liquid en tu app
+ require 'liquid'
+
+ get '/' do
+ liquid :index
+ end
+</pre>
+<p>
+Renderiza <tt>./views/index.liquid</tt>.
+</p>
+<p>
+Como no vas a poder llamar a métodos de Ruby (excepto a <tt>yield</tt>)
+desde una plantilla Liquid, casi siempre vas a querer pasarle locales:
+</p>
+<pre>
+ liquid :index, :locals =&gt; { :clave =&gt; 'valor' }
+</pre>
+<h3>Plantillas Markdown</h3>
+<p>
+La gem/librería rdiscount es necesaria para renderizar plantillas
+Markdown:
+</p>
+<pre>
+ ## Vas a necesitar requerir rdiscount en tu app
+ require &quot;rdiscount&quot;
+
+ get '/' do
+ markdown :index
+ end
+</pre>
+<p>
+Renderiza <tt>./views/index.markdown</tt> (<tt>md</tt> y <tt>mkd</tt>
+también son extensiones de archivo válidas).
+</p>
+<p>
+No es posible llamar métodos desde markdown, ni pasarle locales. Por lo
+tanto, generalmente vas a usarlo en combinación con otro motor de
+renderizado:
+</p>
+<pre>
+ erb :resumen, :locals =&gt; { :texto =&gt; markdown(:introduccion) }
+</pre>
+<p>
+Tené en cuenta que también podés llamar al método markdown desde otras
+plantillas:
+</p>
+<pre>
+ %h1 Hola Desde Haml!
+ %p= markdown(:saludos)
+</pre>
+<h3>Plantilla Textile</h3>
+<p>
+La gem/librería RedCloth es necesaria para renderizar plantillas Textile:
+</p>
+<pre>
+ ## Vas a necesitar requerir redcloth en tu app
+ require &quot;redcloth&quot;
+
+ get '/' do
+ textile :index
+ end
+</pre>
+<p>
+Renderiza <tt>./views/index.textile</tt>.
+</p>
+<p>
+No es posible llamar métodos desde textile, ni pasarle locales. Por lo
+tanto, generalmente vas a usarlo en combinación con otro motor de
+renderizado:
+</p>
+<pre>
+ erb :resumen, :locals =&gt; { :texto =&gt; textile(:introduccion) }
+</pre>
+<p>
+Tené en cuenta que también podés llamar al método textile desde otras
+plantillas:
+</p>
+<pre>
+ %h1 Hola Desde Haml!
+ %p= textile(:saludos)
+</pre>
+<h3>Plantillas RDoc</h3>
+<p>
+La gem/librería RDoc es necesaria para renderizar plantillas RDoc:
+</p>
+<pre>
+ ## Vas a necesitar requerir rdoc en tu app
+ require &quot;rdoc&quot;
+
+ get '/' do
+ rdoc :index
+ end
+</pre>
+<p>
+Renderiza <tt>./views/index.rdoc</tt>.
+</p>
+<p>
+No es posible llamar métodos desde rdoc, ni pasarle locales. Por lo tanto,
+generalmente vas a usarlo en combinación con otro motor de renderizado:
+</p>
+<pre>
+ erb :resumen, :locals =&gt; { :texto =&gt; rdoc(:introduccion) }
+</pre>
+<p>
+Tené en cuenta que también podés llamar al método rdoc desde otras
+plantillas:
+</p>
+<pre>
+ %h1 Hola Desde Haml!
+ %p= rdoc(:saludos)
+</pre>
+<h3>Plantillas Radius</h3>
+<p>
+La gem/librería radius es necesaria para renderizar plantillas Radius:
+</p>
+<pre>
+ ## Vas a necesitar requerir radius en tu app
+ require 'radius'
+
+ get '/' do
+ radius :index
+ end
+</pre>
+<p>
+Renderiza <tt>./views/index.radius</tt>.
+</p>
+<p>
+Como no vas a poder llamar a métodos de Ruby (excepto a <tt>yield</tt>)
+desde una plantilla Radius, casi siempre vas a querer pasarle locales:
+</p>
+<pre>
+ radius :index, :locals =&gt; { :clave =&gt; 'valor' }
+</pre>
+<h3>Plantillas Markaby</h3>
+<p>
+La gem/librería markaby es necesaria para renderizar plantillas Markaby:
+</p>
+<pre>
+ ## Vas a necesitar requerir markaby en tu app
+ require 'markaby'
+
+ get '/' do
+ markaby :index
+ end
+</pre>
+<p>
+Renderiza <tt>./views/index.mab</tt>.
+</p>
+<h3>Plantillas CoffeeScript</h3>
+<p>
+La gem/librería coffee-script y el binario `coffee` son necesarios para
+renderizar plantillas CoffeeScript:
+</p>
+<pre>
+ ## Vas a necesitar requerir coffee-script en tu app
+ require 'coffee-script'
+
+ get '/application.js' do
+ coffee :application
+ end
+</pre>
+<p>
+Renderiza <tt>./views/application.coffee</tt>.
+</p>
+<h3>Plantillas Inline</h3>
+<pre>
+ get '/' do
+ haml '%div.titulo Hola Mundo'
+ end
+</pre>
+<p>
+Renderiza el template contenido en el string.
+</p>
+<h3>Accediendo a Variables en Plantillas</h3>
+<p>
+Las plantillas son evaluadas dentro del mismo contexto que los manejadores
+de ruta. Las variables de instancia asignadas en los manejadores de ruta
+son accesibles directamente por las plantillas:
+</p>
+<pre>
+ get '/:id' do
+ @foo = Foo.find(params[:id])
+ haml '%h1= @foo.nombre'
+ end
+</pre>
+<p>
+O es posible especificar un Hash de variables locales explícitamente:
+</p>
+<pre>
+ get '/:id' do
+ foo = Foo.find(params[:id])
+ haml '%h1= foo.nombre', :locals =&gt; { :foo =&gt; foo }
+ end
+</pre>
+<p>
+Esto es usado típicamente cuando se renderizan plantillas como parciales
+desde adentro de otras plantillas.
+</p>
+<h3>Plantillas Inline</h3>
+<p>
+Las plantillas pueden ser definidas al final del archivo fuente:
+</p>
+<pre>
+ require 'rubygems'
+ require 'sinatra'
+
+ get '/' do
+ haml :index
+ end
+
+ __END__
+
+ @@ layout
+ %html
+ = yield
+
+ @@ index
+ %div.titulo Hola mundo!!!!!
+</pre>
+<p>
+NOTA: únicamente las plantillas inline definidas en el archivo fuente que
+requiere sinatra son cargadas automáticamente. Llamá <tt>enable
+:inline_templates</tt> explícitamente si tenés plantillas inline en otros
+archivos fuente.
+</p>
+<h3>Plantillas Nombradas</h3>
+<p>
+Las plantillas también pueden ser definidas usando el método top-level
+<tt>template</tt>:
+</p>
+<pre>
+ template :layout do
+ &quot;%html\n =yield\n&quot;
+ end
+
+ template :index do
+ '%div.titulo Hola Mundo!'
+ end
+
+ get '/' do
+ haml :index
+ end
+</pre>
+<p>
+Si existe una plantilla con el nombre &#8220;layout&#8221;, va a ser usada
+cada vez que una plantilla es renderizada. Podés desactivar los layouts
+pasando <tt>:layout =&gt; false</tt>.
+</p>
+<pre>
+ get '/' do
+ haml :index, :layout =&gt; !request.xhr?
+ end
+</pre>
+<h2>Ayudantes</h2>
+<p>
+Usá el método top-level <tt>helpers</tt> para definir métodos ayudantes
+que pueden ser utilizados dentro de los manejadores de rutas y las
+plantillas:
+</p>
+<pre>
+ helpers do
+ def bar(nombre)
+ &quot;#{nombre}bar&quot;
+ end
+ end
+
+ get '/:nombre' do
+ bar(params[:nombre])
+ end
+</pre>
+<h2>Filtros</h2>
+<p>
+Los filtros before son evaluados antes de cada petición dentro del mismo
+contexto que las rutas serán evaluadas y pueden modificar la petición y
+la respuesta. Las variables de instancia asignadas en los filtros son
+accesibles por las rutas y las plantillas:
+</p>
+<pre>
+ before do
+ @nota = 'Hey!'
+ request.path_info = '/foo/bar/baz'
+ end
+
+ get '/foo/*' do
+ @nota #=&gt; 'Hey!'
+ params[:splat] #=&gt; 'bar/baz'
+ end
+</pre>
+<p>
+Los filtros after son evaluados después de cada petición dentro del mismo
+contexto y también pueden modificar la petición y la respuesta. Las
+variables de instancia asignadas en los filtros before y rutas son
+accesibles por los filtros after:
+</p>
+<pre>
+ after do
+ puts response.status
+ end
+</pre>
+<p>
+Los filtros aceptan un patrón opcional, que cuando está presente causa
+que los mismos sean evaluados únicamente si el path de la petición
+coincide con ese patrón:
+</p>
+<pre>
+ before '/protegido/*' do
+ autenticar!
+ end
+
+ after '/crear/:slug' do |slug|
+ session[:ultimo_slug] = slug
+ end
+</pre>
+<h2>Interrupción</h2>
+<p>
+Para detener inmediatamente una petición dentro de un filtro o una ruta
+usá:
+</p>
+<pre>
+ halt
+</pre>
+<p>
+También podés especificar el estado:
+</p>
+<pre>
+ halt 410
+</pre>
+<p>
+O el cuerpo:
+</p>
+<pre>
+ halt 'esto va a ser el cuerpo'
+</pre>
+<p>
+O los dos:
+</p>
+<pre>
+ halt 401, 'salí de acá!'
+</pre>
+<p>
+Con cabeceras:
+</p>
+<pre>
+ halt 402, { 'Content-Type' =&gt; 'text/plain' }, 'venganza'
+</pre>
+<h2>Paso</h2>
+<p>
+Una ruta puede pasarle el procesamiento a la siguiente ruta que coincida
+con la petición usando <tt>pass</tt>:
+</p>
+<pre>
+ get '/adivina/:quien' do
+ pass unless params[:quien] == 'Franco'
+ 'Adivinaste!'
+ end
+
+ get '/adivina/*' do
+ 'Erraste!'
+ end
+</pre>
+<p>
+Se sale inmediatamente del bloque de la ruta y se le pasa el control a la
+siguiente ruta que coincida. Si no coincide ninguna ruta, se devuelve un
+404.
+</p>
+<h2>Accediendo al objeto de la petición</h2>
+<p>
+El objeto de la petición entrante puede ser accedido desde el nivel de la
+petición (filtros, rutas y manejadores de errores) a través del método
+`request`:
+</p>
+<pre>
+ # app corriendo en http://ejemplo.com/ejemplo
+ get '/foo' do
+ request.body # cuerpo de la petición enviado por el cliente (ver más abajo)
+ request.scheme # &quot;http&quot;
+ request.script_name # &quot;/ejemplo&quot;
+ request.path_info # &quot;/foo&quot;
+ request.port # 80
+ request.request_method # &quot;GET&quot;
+ request.query_string # &quot;&quot;
+ request.content_length # longitud de request.body
+ request.media_type # tipo de medio de request.body
+ request.host # &quot;ejemplo.com&quot;
+ request.get? # verdadero (hay métodos análogos para los otros verbos)
+ request.form_data? # falso
+ request[&quot;UNA_CABECERA&quot;] # valor de la cabecera UNA_CABECERA
+ request.referer # la referencia del cliente o '/'
+ request.user_agent # user agent (usado por la condición :agent)
+ request.cookies # hash de las cookies del browser
+ request.xhr? # es una petición ajax?
+ request.url # &quot;http://ejemplo.com/ejemplo/foo&quot;
+ request.path # &quot;/ejemplo/foo&quot;
+ request.ip # dirección IP del cliente
+ request.secure? # falso
+ requuest.env # hash de entorno directamente entregado por Rack
+ end
+</pre>
+<p>
+Algunas opciones, como <tt>script_name</tt> o <tt>path_info</tt> pueden
+también ser escritas:
+</p>
+<pre>
+ before { request.path_info = &quot;/&quot; }
+
+ get &quot;/&quot; do
+ &quot;todas las peticiones llegan acá&quot;
+ end
+</pre>
+<p>
+El objeto <tt>request.body</tt> es una instancia de IO o StringIO:
+</p>
+<pre>
+ post &quot;/api&quot; do
+ request.body.rewind # en caso de que alguien ya lo haya leído
+ datos = JSON.parse request.body.read
+ &quot;Hola #{datos['nombre']}!&quot;
+ end
+</pre>
+<h2>Configuración</h2>
+<p>
+Ejecutar una vez, en el inicio, en cualquier entorno:
+</p>
+<pre>
+ configure do
+ ...
+ end
+</pre>
+<p>
+Ejecutar únicamente cuando el entorno (la variable de entorno RACK_ENV) es
+<tt>:production</tt>:
+</p>
+<pre>
+ configure :production do
+ ...
+ end
+</pre>
+<p>
+Ejecutar cuando el entorno es <tt>:production</tt> o <tt>:test</tt>:
+</p>
+<pre>
+ configure :production, :test do
+ ...
+ end
+</pre>
+<h2>Manejo de errores</h2>
+<p>
+Los manejadores de errores se ejecutan dentro del mismo contexto que las
+rutas y los filtros before, lo que significa que podés usar, por ejemplo,
+<tt>haml</tt>, <tt>erb</tt>, <tt>halt</tt>, etc.
+</p>
+<h3>No encontrado <em>(Not Found)</em></h3>
+<p>
+Cuando se eleva una excepción <tt>Sinatra::NotFound</tt>, o el código de
+estado de la respuesta es 404, el manejador <tt>not_found</tt> es invocado:
+</p>
+<pre>
+ not_found do
+ 'No existo'
+ end
+</pre>
+<h3>Error</h3>
+<p>
+El manejador <tt>error</tt> es invocado cada vez que una excepción es
+elevada desde un bloque de ruta o un filtro. El objeto de la excepción se
+puede obtener de la variable Rack <tt>sinatra.error</tt>:
+</p>
+<pre>
+ error do
+ 'Disculpá, ocurrió un error horrible - ' + env['sinatra.error'].name
+ end
+</pre>
+<p>
+Errores personalizados:
+</p>
+<pre>
+ error MiErrorPersonalizado do
+ 'Lo que pasó fue...' request.env['sinatra.error'].message
+ end
+</pre>
+<p>
+Entonces, si pasa esto:
+</p>
+<pre>
+ get '/' do
+ raise MiErrorPersonalizado, 'algo malo'
+ end
+</pre>
+<p>
+Obtenés esto:
+</p>
+<pre>
+ Lo que pasó fue... algo malo
+</pre>
+<p>
+También, podés instalar un manejador de errores para un código de
+estado:
+</p>
+<pre>
+ error 403 do
+ 'Acceso prohibido'
+ end
+
+ get '/secreto' do
+ 403
+ end
+</pre>
+<p>
+O un rango:
+</p>
+<pre>
+ error 400..510 do
+ 'Boom'
+ end
+</pre>
+<p>
+Sinatra instala manejadores <tt>not_found</tt> y <tt>error</ttt> especiales
+cuando se ejecuta dentro del entorno de desarrollo
+&#8220;development&#8221;.
+</p>
+<h2>Tipos Mime</h2>
+<p>
+Cuando usás <tt>send_file</tt> o archivos estáticos tal vez tengas tipos
+mime que Sinatra no entiende. Usá <tt>mime_type</tt> para registrarlos a
+través de la extensión de archivo:
+</p>
+<pre>
+ mime_type :foo, 'text/foo'
+</pre>
+<p>
+También lo podés usar con el ayudante <tt>content_type</tt>:
+</p>
+<pre>
+ content_type :foo
+</pre>
+<h2>Rack Middleware</h2>
+<p>
+Sinatra corre sobre <a href="http://rack.rubyforge.org/">Rack</a>, una
+interfaz minimalista que es un estándar para frameworks webs escritos en
+Ruby. Una de las capacidades más interesantes de Rack para los
+desarrolladores de aplicaciones es el soporte de &#8220;middleware&#8221;
+&#8212; componentes que se ubican entre el servidor y tu aplicación,
+supervisando y/o manipulando la petición/respuesta HTTP para proporcionar
+varios tipos de funcionalidades comunes.
+</p>
+<p>
+Sinatra hace muy sencillo construir tuberías de Rack middleware a través
+del método top-level <tt>use</tt>:
+</p>
+<pre>
+ require 'sinatra'
+ require 'mi_middleware_personalizado'
+
+ use Rack::Lint
+ use MiMiddlewarePersonalizado
+
+ get '/hola' do
+ 'Hola Mundo'
+ end
+</pre>
+<p>
+Las semánticas de <tt>use</tt> son idénticas a las definidas para el DSL
+<a
+href="http://rack.rubyforge.org/doc/classes/Rack/Builder.html">Rack::Builder</a>
+(más frecuentemente usado desde archivos rackup). Por ejemplo, el método
+<tt>use</tt> acepta argumentos múltiples/variables así como bloques:
+</p>
+<pre>
+ use Rack::Auth::Basic do |nombre_de_usuario, password|
+ nombre_de_usuario == 'admin' &amp;&amp; password == 'secreto'
+ end
+</pre>
+<p>
+Rack es distribuido con una variedad de middleware estándar para logging,
+debugging, enrutamiento URL, autenticación, y manejo de sesiones. Sinatra
+usa muchos de estos componentes automáticamente de acuerdo a su
+configuración para que típicamente no tengas que usarlas (con
+<tt>use</tt>) explícitamente.
+</p>
+<h2>Pruebas</h2>
+<p>
+Las pruebas para las aplicaciones Sinatra pueden ser escritas utilizando
+cualquier framework o librería de pruebas basada en Rack. Se recomienda
+usar <a href="http://gitrdoc.com/brynary/rack-test">Rack::Test</a>:
+</p>
+<pre>
+ require 'mi_app_sinatra'
+ require 'test/unit'
+ require 'rack/test'
+
+ class MiAppTest &lt; Test::Unit::TestCase
+ include Rack::Test::Methods
+
+ def app
+ Sinatra::Application
+ end
+
+ def test_mi_defecto
+ get '/'
+ assert_equal 'Hola Mundo!', last_response.body
+ end
+
+ def test_con_parametros
+ get '/saludar', :name =&gt; 'Franco'
+ assert_equal 'Hola Frank!', last_response.body
+ end
+
+ def test_con_entorno_rack
+ get '/', {}, 'HTTP_USER_AGENT' =&gt; 'Songbird'
+ assert_equal &quot;Estás usando Songbird!&quot;, last_response.body
+ end
+ end
+</pre>
+<p>
+NOTA: El módulo Sinatra::Test y la clase Sinatra::TestHarness están
+deprecados a partir de la versión 0.9.2.
+</p>
+<h2>Sinatra::Base - Middleware, Librerías, y Aplicaciones Modulares</h2>
+<p>
+Definir tu aplicación en el top-level funciona bien para
+micro-aplicaciones pero trae inconvenientes considerables a la hora de
+construir componentes reutilizables como Rack middleware, Rails metal,
+simple librerías con un componente de servidor, o incluso extensiones de
+Sinatra. El DSL de top-level contamina el espacio de nombres de Object y
+asume una configuración apropiada para micro-aplicaciones (por ejemplo, un
+único archivo de aplicación, los directorios ./public y ./views, logging,
+página con detalles de excepción, etc.). Ahí es donde Sinatra::Base
+entra en el juego:
+</p>
+<pre>
+ require 'sinatra/base'
+
+ class MiApp &lt; Sinatra::Base
+ set :sessions, true
+ set :foo, 'bar'
+
+ get '/' do
+ 'Hola Mundo!'
+ end
+ end
+</pre>
+<p>
+La clase MiApp es un componente Rack independiente que puede actuar como
+Rack middleware, una aplicación Rack, o Rails metal. Podés usar (con
+<tt>use</tt>) o ejecutar (con <tt>run</tt>) esta clase desde un archivo
+rackup <tt>config.ru</tt>; o, controlar un componente de servidor provisto
+como una librería:
+</p>
+<pre>
+ MiApp.run! :host =&gt; 'localhost', :port =&gt; 9090
+</pre>
+<p>
+Las subclases de Sinatra::Base tienen disponibles exactamente los mismos
+métodos que los provistos por el DSL de top-level. La mayoría de las
+aplicaciones top-level se pueden convertir en componentes Sinatra::Base con
+dos modificaciones:
+</p>
+<ul>
+<li><p>
+Tu archivo debe requerir <tt>sinatra/base</tt> en lugar de
+<tt>sinatra</tt>; de otra manera, todos los métodos del DSL de sinatra son
+importados dentro del espacio de nombres principal.
+</p>
+</li>
+<li><p>
+Poné las rutas, manejadores de errores, filtros y opciones de tu
+aplicación en una subclase de Sinatra::Base.
+</p>
+</li>
+</ul>
+<p>
+<tt>Sinatra::Base</tt> es una pizarra en blanco. La mayoría de las
+opciones están desactivadas por defecto, incluyendo el servidor
+incorporado. Mirá <a
+href="http://sinatra.github.com/configuration.html">Opciones y
+Configuraciones</a> para detalles sobre las opciones disponibles y su
+comportamiento.
+</p>
+<h3>Utilizando Sinatra como Middleware</h3>
+<p>
+Sinatra no solo es capaz de usar otro Rack middleware, sino que a su vez,
+cualquier aplicación Sinatra puede ser agregada delante de un endpoint
+Rack como middleware. Este endpoint puede ser otra aplicación Sinatra, o
+cualquier aplicación basada en Rack (Rails/Ramaze/Camping/&#8230;).
+</p>
+<pre>
+ require 'sinatra/base'
+
+ class PantallaDeLogin&lt; Sinatra::Base
+ enable :session
+
+ get('/login') { haml :login }
+
+ post('/login') do
+ if params[:nombre] = 'admin' and params[:password] = 'admin'
+ session['nombre_de_usuario'] = params[:nombre]
+ else
+ redirect '/login'
+ end
+ end
+ end
+
+ class MiApp &lt; Sinatra::Base
+ # el middleware se ejecutará antes que los filtros
+ use PantallaDeLogin
+
+ before do
+ unless session['nombre_de_usuario']
+ halt &quot;Acceso denegado, por favor &lt;a href='/login'&gt;iniciá sesión&lt;/a&gt;.&quot;
+ end
+ end
+
+ get('/') { &quot;Hola #{session['nombre_de_usuario']}.&quot; }
+ end
+</pre>
+<h2>Ámbitos y Ligaduras</h2>
+<p>
+El ámbito en el que te encontrás determina que métodos y variables
+están disponibles.
+</p>
+<h3>Ámbito de Aplicación/Clase</h3>
+<p>
+Cada aplicación Sinatra es una subclase de Sinatra::Base. Si estás usando
+el DSL de top-level (<tt>require 'sinatra'</tt>), entonces esta clase es
+Sinatra::Application, de otra manera es la subclase que creaste
+explícitamente. Al nivel de la clase tenés métodos como `get` o
+`before`, pero no podés acceder a los objetos `request` o `session`, ya
+que hay una única clase de la aplicación para todas las peticiones.
+</p>
+<p>
+Las opciones creadas utilizando `set` son métodos al nivel de la clase:
+</p>
+<pre>
+ class MiApp &lt;&lt; Sinatra::Base
+ # Ey, estoy en el ámbito de la aplicación!
+ set :foo, 42
+ foo # =&gt; 42
+
+ get '/foo' do
+ # Hey, ya no estoy en el ámbito de la aplicación!
+ end
+ end
+</pre>
+<p>
+Tenés la ligadura al ámbito de la aplicación dentro de:
+</p>
+<ul>
+<li><p>
+El cuerpo de la clase de tu aplicación
+</p>
+</li>
+<li><p>
+Métodos definidos por extensiones
+</p>
+</li>
+<li><p>
+El bloque pasado a `helpers`
+</p>
+</li>
+<li><p>
+Procs/bloques usados como el valor para `set`
+</p>
+</li>
+</ul>
+<p>
+Este ámbito puede alcanzarse de las siguientes maneras:
+</p>
+<ul>
+<li><p>
+A través del objeto pasado a los bloques de configuración (<tt>configure
+{ |c| ...}</tt>)
+</p>
+</li>
+<li><p>
+Llamando a `settings` desde dentro del ámbito de la petición
+</p>
+</li>
+</ul>
+<h3>Ámbito de Petición/Instancia</h3>
+<p>
+Para cada petición entrante, una nueva instancia de la clase de tu
+aplicación es creada y todos los bloques de rutas son ejecutados en ese
+ámbito. Desde este ámbito podés acceder a los objetos `request` y
+`session` o llamar a los métodos de renderización como `erb` o `haml`.
+Podés acceder al ámbito de la aplicación desde el ámbito de la
+petición utilizando `settings`:
+</p>
+<pre>
+ class MiApp &lt;&lt; Sinatra::Base
+ # Ey, estoy en el ámbito de la aplicación!
+ get '/definir_ruta/:nombre' do
+ # Ámbito de petición para '/definir_ruta/:nombre'
+ @valor = 42
+
+ settings.get(&quot;/#{params[:nombre]}&quot;) do
+ # Ámbito de petición para &quot;/#{params[:nombre]}&quot;
+ @valor # =&gt; nil (no es la misma petición)
+ end
+
+ &quot;Ruta definida!&quot;
+ end
+ end
+</pre>
+<p>
+Tenés la ligadura al ámbito de la petición dentro de:
+</p>
+<ul>
+<li><p>
+bloques pasados a get/head/post/put/delete
+</p>
+</li>
+<li><p>
+filtros before/after
+</p>
+</li>
+<li><p>
+métodos ayudantes
+</p>
+</li>
+<li><p>
+plantillas/vistas
+</p>
+</li>
+</ul>
+<h3>Ámbito de Delegación</h3>
+<p>
+El ámbito de delegación solo reenvía métodos al ámbito de clase. De
+cualquier manera, no se comporta 100% como el ámbito de clase porque no
+tenés la ligadura de la clase: únicamente métodos marcados
+explícitamente para delegación están disponibles y no compartís
+variables/estado con el ámbito de clase (léase: tenés un `self`
+diferente). Podés agregar delegaciones de método llamando a
+<tt>Sinatra::Delegator.delegate :nombre_del_metodo</tt>.
+</p>
+<p>
+Tenés la ligadura al ámbito de delegación dentro de:
+</p>
+<ul>
+<li><p>
+La ligadura del top-level, si hiciste <tt>require &quot;sinatra&quot;</tt>
+</p>
+</li>
+<li><p>
+Un objeto extendido con el mixin `Sinatra::Delegator`
+</p>
+</li>
+</ul>
+<p>
+Pegale una mirada al código: acá está el <a
+href="http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/base.rb#L1128">Sinatra::Delegator
+mixin</a> que es <a
+href="http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/main.rb#L28">incluido
+en el espacio de nombres principal</a>.
+</p>
+<h2>Línea de comandos</h2>
+<p>
+Las aplicaciones Sinatra pueden ser ejecutadas directamente:
+</p>
+<pre>
+ ruby miapp.rb [-h] [-x] [-e ENTORNO] [-p PUERTO] [-o HOST] [-s MANEJADOR]
+</pre>
+<p>
+Las opciones son:
+</p>
+<pre>
+ -h # ayuda
+ -p # asigna el puerto (4567 es usado por defecto)
+ -o # asigna el host (0.0.0.0 es usado por defecto)
+ -e # asigna el entorno (development es usado por defecto)
+ -s # especifica el servidor/manejador rack (thin es usado por defecto)
+ -x # activa el mutex lock (está desactivado por defecto)
+</pre>
+<h2>A la vanguardia</h2>
+<p>
+Si querés usar el código de Sinatra más reciente, cloná el repositorio
+localmente y ejecutá tu aplicación, asegurándote que el directorio
+<tt>sinatra/lib</tt> esté en el <tt>LOAD_PATH</tt>:
+</p>
+<pre>
+ cd miapp
+ git clone git://github.com/sinatra/sinatra.git
+ ruby -Isinatra/lib miapp.rb
+</pre>
+<p>
+Otra opción consiste en agregar el directorio <tt>sinatra/lib</tt> al
+<tt>LOAD_PATH</tt> dentro de tu aplicación:
+</p>
+<pre>
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
+ require 'rubygems'
+ require 'sinatra'
+
+ get '/acerca-de' do
+ &quot;Estoy usando la versión &quot; + Sinatra::VERSION
+ end
+</pre>
+<p>
+Para actualizar el código fuente de Sinatra en el futuro:
+</p>
+<pre>
+ cd miproyecto/sinatra
+ git pull
+</pre>
+<h2>Más</h2>
+<ul>
+<li><p>
+<a href="http://www.sinatrarb.com/">Sito web del proyecto</a> -
+Documentación adicional, noticias, y enlaces a otros recursos.
+</p>
+</li>
+<li><p>
+<a href="http://www.sinatrarb.com/contributing">Contribuyendo</a> -
+¿Encontraste un error?. ¿Necesitás ayuda?. ¿Tenés un parche?.
+</p>
+</li>
+<li><p>
+<a href="http://github.com/sinatra/sinatra/issues">Seguimiento de
+problemas</a>
+</p>
+</li>
+<li><p>
+<a href="http://twitter.com/sinatra">Twitter</a>
+</p>
+</li>
+<li><p>
+<a href="http://groups.google.com/group/sinatrarb/topics">Lista de
+Correo</a>
+</p>
+</li>
+<li><p>
+<a href="irc://chat.freenode.net/#sinatra">IRC: #sinatra</a> en <a
+href="http://freenode.net">freenode.net</a>
+</p>
+</li>
+</ul>
View
1,292 _includes/README.fr.html
@@ -0,0 +1,1292 @@
+
+<p>
+<em>Attention: Ce document correspond à la traduction de la version
+anglaise et il n&#8217;est peut être plus à jour.</em>
+</p>
+<p>
+Sinatra est un DSL pour créer rapidement des applications web en Ruby et
+sans effort:
+</p>
+<pre>
+ # mon_application.rb
+ require 'sinatra'
+ get '/' do
+ 'Bonjour Monde!'
+ end
+</pre>
+<p>
+Installez le gem et lancez avec:
+</p>
+<pre>
+ gem install sinatra
+ ruby -rubygems mon_application.rb
+</pre>
+<p>
+Le résultat est visible sur: <a
+href="http://localhost:4567">localhost:4567</a>
+</p>
+<h2>Routes</h2>
+<p>
+Dans Sinatra, une route est une méthode HTTP couplée à un masque
+(pattern) URL. Chaque route est associée à un bloc:
+</p>
+<pre>
+ get '/' do
+ .. montrer quelque chose ..
+ end
+
+ post '/' do
+ .. créer quelque chose ..
+ end
+
+ put '/' do
+ .. changer quelque chose ..
+ end
+
+ delete '/' do
+ .. effacer quelque chose ..
+ end
+</pre>
+<p>
+Les routes sont comparées dans l&#8217;ordre où elles ont été
+définies. La première route qui correspond à la requête est invoquée.
+</p>
+<p>
+Les masques peuvent inclure des paramètres, accessibles par
+l&#8217;intermédiaire du hash <tt>params</tt>:
+</p>
+<pre>
+ get '/bonjour/:nom' do
+ # répond aux requêtes &quot;GET /bonjour/foo&quot; et &quot;GET /bonjour/bar&quot;
+ # params[:nom] est 'foo' ou 'bar'
+ &quot;Bonjour #{params[:nom]}!&quot;
+ end
+</pre>
+<p>
+Vous pouvez aussi les nommer directement dans les paramètres du bloc comme
+ceci:
+</p>
+<pre>
+ get '/bonjour/:nom' do |n|
+ &quot;Bonjour #{n}!&quot;
+ end
+</pre>
+<p>
+Une route peut contenir un splat (caractère joker), accessible par
+l&#8217;intermédiaire de la liste <tt>params[:splat]</tt>.
+</p>
+<pre>
+ get '/dire/*/a/*' do
+ # répondrait à /dire/bonjour/a/monde
+ params[:splat] # =&gt; [&quot;bonjour&quot;, &quot;monde&quot;]
+ end
+
+ get '/telecharger/*.*' do
+ # répondrait à /telecharger/chemin/vers/fichier.xml
+ params[:splat] # =&gt; [&quot;chemin/vers/fichier&quot;, &quot;xml&quot;]
+ end
+</pre>
+<p>
+Une route peut s&#8217;exprimer avec une Expression Régulière:
+</p>
+<pre>
+ get %r{/bonjour/([\w]+)} do
+ &quot;Bonjour, #{params[:captures].first}!&quot;
+ end
+</pre>
+<p>
+Là aussi on peut utiliser les paramètres de bloc:
+</p>
+<pre>
+ get %r{/bonjour/([\w]+)} do |c|
+ &quot;Bonjour, #{c}!&quot;
+ end
+</pre>
+<h3>Conditions</h3>
+<p>
+Les routes peuvent définir toutes sortes de conditions, comme par exemple
+le &#8220;user agent&#8221;:
+</p>
+<pre>
+ get '/foo', :agent =&gt; /Songbird (\d\.\d)[\d\/]*?/ do
+ &quot;Vous utilisez Songbird version #{params[:agent][0]}&quot;
+ end
+
+ get '/foo' do
+ # Correspond à tous les autres navigateurs
+ end
+</pre>
+<p>
+Les autres conditions disponibles sont <tt>host_name</tt> et
+<tt>provides</tt>:
+</p>
+<pre>
+ get '/', :host_name =&gt; /^admin\./ do
+ &quot;Zone Administrateur, Accès refusé!&quot;
+ end
+
+ get '/', :provides =&gt; 'html' do
+ haml :index
+ end
+
+ get '/', :provides =&gt; ['rss', 'atom', 'xml'] do
+ builder :feed
+ end
+</pre>
+<p>
+Vous pouvez facilement définir vos propres conditions:
+</p>
+<pre>
+ set(:probability) { |value| condition { rand &lt;= value } }
+
+ get '/gagner_une_voiture', :probability =&gt; 0.1 do
+ &quot;Vous avez gagné!&quot;
+ end
+
+ get '/gagner_une_voiture' do
+ &quot;Désolé, vous avez perdu.&quot;
+ end
+</pre>
+<h3>Valeurs de retour</h3>
+<p>
+La valeur de retour d&#8217;un bloc définissant une route détermine le
+corps de la réponse qui sera transmise au client HTTP ou du moins au
+prochain middleware dans la pile Rack. Le plus généralement, il
+s&#8217;agit d&#8217;une chaîne de caractères, comme dans les exemples
+précédents. Cependant, d&#8217;autres valeurs sont acceptées.
+</p>
+<p>
+Vous pouvez renvoyer n&#8217;importe quel objet qui soit une réponse Rack
+valide, un corps de réponse Rack ou un code retour HTTP:
+</p>
+<ul>
+<li><p>
+Un tableau de 3 éléments: <tt>[code retour (Fixnum), entêtes (Hash),
+corps de réponse (répondant à #each)]</tt>