<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 <title>Sinatra</title>
 <link href="http://sinatra.guthub.com/feed.xml" rel="self"/>
 <link href="http://sinatra.github.com/"/>
 <updated>2009-11-07T01:49:34-08:00</updated>
 <id>http://sinatrarb.com/</id>

 
 <entry>
   <title>We Have a FAQ Now</title>
   <link href="http://sinatra.github.com/2009/01/29/we-have-a-faq-now.html"/>
   <published>2009-01-29T00:00:00-08:00</published>
   <updated>2009-01-29T00:00:00-08:00</updated>
   <author>
     <name>Ryan Tomayko</name>
     <uri>http://tomayko.com/about</uri>
   </author>
   <id>http://sinatrarb.com/2009/01/29/we-have-a-faq-now</id>
   <content type="html">&lt;p&gt;Just getting started with Sinatra and wondering how to do something that should be obvious? &lt;a href='/faq.html'&gt;Check out The FAQ&lt;/a&gt;. We culled a few weeks worth of IRC logs and mailing list threads to compile the initial set of entries and we&amp;#8217;ll be adding to the list considerably over the coming weeks.&lt;/p&gt;

&lt;p&gt;Have an idea for a FAQ entry? Fork the &lt;a href='http://github.com/sinatra/sinatra.github.com/'&gt;sinatra.github.com repository&lt;/a&gt;, add the entry to &lt;code&gt;faq.markdown&lt;/code&gt;, and push. We&amp;#8217;ll take care of the rest.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>What's New in Sinatra 0.9.0</title>
   <link href="http://sinatra.github.com/2009/01/18/sinatra-0.9.0.html"/>
   <published>2009-01-18T00:00:00-08:00</published>
   <updated>2009-01-18T00:00:00-08:00</updated>
   <author>
     <name>Ryan Tomayko</name>
     <uri>http://tomayko.com/about</uri>
   </author>
   <id>http://sinatrarb.com/2009/01/18/sinatra-0.9.0</id>
   <content type="html">&lt;p&gt;This is the first in a series of 0.9.x releases designed to move Sinatra toward a rock solid 1.0. While we were able to add a touch of new hotness in this release, the major focus has been on getting the codebase shaped up for future development. Many longstanding bugs and minor annoyances were corrected along the way.&lt;/p&gt;

&lt;p&gt;Sinatra&amp;#8217;s internal classes and methods have changed significantly in this release. Most apps written for 0.3.x will work just fine under the new codebase but we&amp;#8217;ve begun adding deprecation warnings for things slated to be ripped out completely in 1.0. &lt;strong&gt;Please test your apps before upgrading production environments to the 0.9.0 gem.&lt;/strong&gt; We&amp;#8217;re committed to keeping existing apps running through 0.9.x so report compatibility issues through &lt;a href='/contributing.html'&gt;the normal channels&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With that out of the way, here are some of the new features to look out for in 0.9.0.&lt;/p&gt;

&lt;h2 id='sinatrabase_and_proper_rack_citizenship'&gt;Sinatra::Base and Proper Rack Citizenship&lt;/h2&gt;

&lt;p&gt;Sinatra can now be used to build modular / reusable &lt;a href='http://rack.rubyforge.org/'&gt;Rack&lt;/a&gt; applications and middleware components. This means that multiple Sinatra applications can now be run in isolation and co-exist peacefully with other Rack based frameworks.&lt;/p&gt;

&lt;p&gt;Requiring &lt;code&gt;&amp;#39;sinatra/base&amp;#39;&lt;/code&gt; instead of &lt;code&gt;&amp;#39;sinatra&amp;#39;&lt;/code&gt; causes a subset of Sinatra&amp;#8217;s features to be loaded. No methods are added to the top-level and the command-line / auto-running features are disabled. Subclassing &lt;code&gt;Sinatra::Base&lt;/code&gt; creates a Rack component with the familiar Sinatra DSL methods available in class scope. These classes can then be run as Rack applications or used as middleware components.&lt;/p&gt;

&lt;p&gt;Proper documentation on this feature is in the works but here&amp;#8217;s a quick example for illustration:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;sinatra/base&amp;#39;&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Foo&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;Sinatra&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;
  &lt;span class='c1'&gt;# all options are available for the setting:&lt;/span&gt;
  &lt;span class='n'&gt;enable&lt;/span&gt; &lt;span class='ss'&gt;:static&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:session&lt;/span&gt;
  &lt;span class='n'&gt;set&lt;/span&gt; &lt;span class='ss'&gt;:root&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;dirname&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='bp'&gt;__FILE__&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

  &lt;span class='c1'&gt;# each subclass has its own private middleware stack:&lt;/span&gt;
  &lt;span class='n'&gt;use&lt;/span&gt; &lt;span class='no'&gt;Rack&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Deflator&lt;/span&gt;

  &lt;span class='c1'&gt;# instance methods are helper methods and are available from&lt;/span&gt;
  &lt;span class='c1'&gt;# within filters, routes, and views:&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;em&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;text&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;&amp;lt;em&amp;gt;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;text&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;lt;/em&amp;gt;&amp;quot;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='c1'&gt;# routes are defined as usual:&lt;/span&gt;
  &lt;span class='n'&gt;get&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/hello/:person&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;Hello &amp;quot;&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;em&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:person&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;That thing can be plugged in anywhere along a Rack pipeline. For instance, once Rails 2.3 ships, you&amp;#8217;ll be able to use Sinatra apps to build &lt;a href='http://weblog.rubyonrails.org/2008/12/17/introducing-rails-metal'&gt;Rails Metal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Jesse Newland and Jon Crosby are &lt;a href='http://blog.joncrosby.me/post/72451217/a-world-of-middleware'&gt;already experimenting&lt;/a&gt;. Very hot.&lt;/p&gt;

&lt;h2 id='nested_params'&gt;Nested Params&lt;/h2&gt;

&lt;p&gt;Form parameters with subscripts are now parsed into a nested/recursive Hash structure. Here&amp;#8217;s a form:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='nt'&gt;&amp;lt;form&lt;/span&gt; &lt;span class='na'&gt;method=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;POST&amp;#39;&lt;/span&gt; &lt;span class='na'&gt;action=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;/guestbook/&amp;#39;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;input&lt;/span&gt; &lt;span class='na'&gt;type=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class='na'&gt;name=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;person[name]&amp;#39;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;input&lt;/span&gt; &lt;span class='na'&gt;type=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class='na'&gt;name=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;person[email]&amp;#39;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class='na'&gt;name=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;note&amp;#39;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;It looks like this on the wire:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;person[name]=Frank&amp;amp;person[email]=frank@theritz.com&amp;amp;message=Stay%20cool&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Sinatra turns it into a nested Hash structure when accessed through the &lt;code&gt;params&lt;/code&gt; method:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/guestbook/&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:person&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;    &lt;span class='c1'&gt;# =&amp;gt; { :name =&amp;gt; &amp;#39;Frank&amp;#39;, :email =&amp;gt; &amp;#39;frank@theritz.com&amp;#39; }&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;Hi &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;person&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:name&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;! Thanks for signing my guestbook.&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This was a massively popular feature requests. Thanks to &lt;a href='http://foca.tumblr.com/'&gt;Nicolás Sanguinetti&lt;/a&gt; for the patch and &lt;a href='http://manveru.net/about_me'&gt;Michael Fellinger&lt;/a&gt; for the original implementation.&lt;/p&gt;

&lt;h2 id='routing_with_regular_expressions'&gt;Routing with Regular Expressions&lt;/h2&gt;

&lt;p&gt;The route declaration methods (&lt;code&gt;get&lt;/code&gt;, &lt;code&gt;put&lt;/code&gt;, &lt;code&gt;post&lt;/code&gt;, &lt;code&gt;put&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;) now take a Regexp as a pattern. Captures are made available to the route block at &lt;code&gt;params[:captures]&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='n'&gt;get&lt;/span&gt; &lt;span class='sr'&gt;%r{/foo/(bar|baz)/(\d+)}&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='c1'&gt;# assuming: GET /foo/bar/42&lt;/span&gt;
  &lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:captures&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;  &lt;span class='c1'&gt;# =&amp;gt; [&amp;#39;bar&amp;#39;, 42]&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='passing_on_a_route'&gt;Passing on a Route&lt;/h2&gt;

&lt;p&gt;We added a new request-level &lt;code&gt;pass&lt;/code&gt; method that immediately exits the current block and passes control to the next matching route. For example:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='n'&gt;get&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/shoot/:person&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;pass&lt;/span&gt; &lt;span class='k'&gt;unless&lt;/span&gt; &lt;span class='sx'&gt;%w[Kenny Sherrif]&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;include?&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:person&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;You shot &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:person&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;.&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='n'&gt;get&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/shoot/*&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;Missed!&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;If no matching route is found after a &lt;code&gt;pass&lt;/code&gt;, a &lt;code&gt;NotFound&lt;/code&gt; exception is raised and the application 404s as if no route had matched in the first place.&lt;/p&gt;

&lt;h2 id='refined_test_framework'&gt;Refined Test Framework&lt;/h2&gt;

&lt;p&gt;Sinatra&amp;#8217;s testing support no longer depends on &lt;code&gt;Test::Unit&lt;/code&gt; (or any specific test framework for that matter). Requiring &lt;code&gt;&amp;#39;sinatra/test&amp;#39;&lt;/code&gt; brings in the &lt;a href='/api/classes/Sinatra/Test.html'&gt;&lt;code&gt;Sinatra::Test&lt;/code&gt; module&lt;/a&gt; and the &lt;a href='/api/classes/Sinatra/TestHarness.html'&gt;&lt;code&gt;Sinatra::TestHarness&lt;/code&gt; class&lt;/a&gt;, which can be used as necessary to simulate requests and make assertions about responses.&lt;/p&gt;

&lt;p&gt;You can also require &lt;code&gt;sinatra/test/unit&lt;/code&gt;, &lt;code&gt;sinatra/test/spec&lt;/code&gt;, &lt;code&gt;sinatra/test/rspec&lt;/code&gt;, or &lt;code&gt;sinatra/test/bacon&lt;/code&gt; to setup a framework-specific testing environment. See the section on &amp;#8220;Testing&amp;#8221; in the &lt;a href='/intro.html'&gt;&lt;code&gt;README&lt;/code&gt;&lt;/a&gt; for examples.&lt;/p&gt;

&lt;h2 id='more'&gt;More&lt;/h2&gt;

&lt;p&gt;See the &lt;a href='./changes.html'&gt;&lt;code&gt;CHANGES&lt;/code&gt;&lt;/a&gt; file for a comprehensive list of enhancements, bug fixes, and deprecations.&lt;/p&gt;</content>
 </entry>
 
</feed>
