<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>decodeURI &#187; rack</title>
	<atom:link href="http://decodeuri.com/tag/rack/feed/" rel="self" type="application/rss+xml" />
	<link>http://decodeuri.com</link>
	<description>blog of Luciano Germán Panaro</description>
	<lastBuildDate>Sat, 24 Apr 2010 12:41:43 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='decodeuri.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://1.gravatar.com/blavatar/f9eef72031f2217eea8619b16256eea0?s=96&#038;d=http://s2.wp.com/i/buttonw-com.png</url>
		<title>decodeURI &#187; rack</title>
		<link>http://decodeuri.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://decodeuri.com/osd.xml" title="decodeURI" />
	<atom:link rel='hub' href='http://decodeuri.com/?pushpress=hub'/>
		<item>
		<title>Creating a Rack Middleware for Minifying Your Javascript files</title>
		<link>http://decodeuri.com/2008/10/15/creating-a-rack-middleware-for-minifying-your-javascript-files/</link>
		<comments>http://decodeuri.com/2008/10/15/creating-a-rack-middleware-for-minifying-your-javascript-files/#comments</comments>
		<pubDate>Wed, 15 Oct 2008 22:40:46 +0000</pubDate>
		<dc:creator>lucianopanaro</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[jsmin]]></category>
		<category><![CDATA[middleware]]></category>
		<category><![CDATA[rack]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.decodeuri.com/?p=59</guid>
		<description><![CDATA[If you are in the Ruby world you have probably heard of Rack. If you haven&#8217;t, and you are a Pythonista, then you only need to know that Rack is a sort of &#8220;WSGI for Ruby&#8221;. And in case you don&#8217;t know what Rack or WSGI are, then here&#8217;s a brief description: &#8220;Rack provides a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=decodeuri.com&amp;blog=2195581&amp;post=59&amp;subd=lucianopanaro&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>If you are in the Ruby world you have probably heard of <a href="http://rack.rubyforge.org/" target="_blank">Rack</a>. If you haven&#8217;t, and you are a Pythonista, then you only need to know that Rack is a sort of &#8220;<a href="http://wsgi.org/wsgi/" target="_blank">WSGI</a> for Ruby&#8221;. And in case you don&#8217;t know what Rack or WSGI are, then here&#8217;s a brief description:</p>
<blockquote><p>&#8220;Rack provides a minimal, modular and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call.&#8221;</p></blockquote>
<p>So you can think of Rack as a &#8220;<a href="http://macournoyer.wordpress.com/2007/12/14/rack-the-framework-framework/" target="_blank">frameworks framework</a>&#8220;. <a href="http://brainspl.at/articles/2008/02/16/so-merb-core-is-built-on-rack-you-say-why-should-i-care" target="_blank">Merb</a> and other <a href="http://ramaze.net" target="_blank">ruby</a> <a href="http://railswaves.com/" target="_blank">frameworks</a> already support Rack, which means that they can share the middleware described above.</p>
<h2>Creating a Rack Middleware</h2>
<p>So let&#8217;s say you want your application (built on Rails, Merb, Ramaze or even Rack) to intercept any request for javascript files so that you can first minify them. Below is the sample code for achieving this with a Rack Middleware:</p>
<p><em>(You can checkout this code, its spec and example from <a href="http://github.com/lucianopanaro/rack-javascript-minifier" target="_blank">http://github.com/lucianopanaro/rack-javascript-minifier</a>. The javascript minifier is a port from <a href="http://www.crockford.com/javascript/jsmin.html" target="_blank">Douglas Crockford&#8217;s library</a> <a href="http://github.com/rgrove/jsmin/" target="_blank">done by Ryan Grove</a>.)</em></p>
<pre class="brush: ruby;">
  class JavascriptMinifier
    F = ::File

    def initialize(app, path)
      @app = app
      @root = F.expand_path(path)
      raise &quot;Provided path #{@root} does not exist&quot; unless F.directory?(@root)
    end

    def call(env)
      path = F.join(@root, Utils.unescape(env[&quot;PATH_INFO&quot;]))

      unless path.match(/.*\/(\w+\.js)$/) and F.file?(path)
        return @app.call(env)
      end

      if env[&quot;PATH_INFO&quot;].include?(&quot;..&quot;) or !F.readable?(path)
        body = &quot;Forbidden\n&quot;
        size = body.respond_to?(:bytesize) ? body.bytesize : body.size
        return [403, {&quot;Content-Type&quot; =&amp;gt; &quot;text/plain&quot;,&quot;Content-Length&quot; =&amp;gt; size.to_s}, [body]]
      end

      last_modified = F.mtime(path)
      min_path = F.join(@root, &quot;m_#{last_modified.to_i}_#{F.basename(path)}&quot;)

      unless F.file?(min_path)
        F.open(path, &quot;r&quot;) { |file|
          F.open(min_path, &quot;w&quot;) { |f| f.puts JSMin.minify(file) }
        }
      end

      [200, {
             &quot;Last-Modified&quot;  =&amp;gt; F.mtime(min_path).httpdate,
             &quot;Content-Type&quot;   =&amp;gt; &quot;text/javascript&quot;,
             &quot;Content-Length&quot; =&amp;gt; F.size(min_path).to_s
            }, F.new(min_path, &quot;r&quot;)]
    end
  end
</pre>
<p>Rack Middleware&#8217;s interface is dead simple. As <a href="http://macournoyer.wordpress.com/2008/02/09/the-flexible-thin-anorexic-gymnast-that-democratized-deployment/">Marc-André Cournoyer points out</a>: <em>&#8220;It must have a call method and receive a Rack app as the first argument of new&#8221;</em>.</p>
<p>So here, when we initialize the JavascriptMinifier, we pass the root path where the javascript files are placed. Every time it gets called, the middleware first checks if the request is for a javascript file. If it&#8217;s not, it passes it to the application. If the request is for a javascript in a parent directory, then we return a forbidden (403) page. Finally, if the request passes these filters, the middleware creates a minified version of the javascript file and returns it.</p>
<h2>Running your application with middleware</h2>
<p>This is also really simple using <a href="http://rack.rubyforge.org/doc/classes/Rack/Builder.html" target="_blank">Rack::Builder</a>:</p>
<blockquote><p>&#8220;Rack::Builder implements a small DSL to iteratively construct Rack applications. <a href="http://rack.rubyforge.org/doc/classes/Rack/Builder.html#M000112" target="_blank">use</a> adds a middleware to the stack, <a href="http://rack.rubyforge.org/doc/classes/Rack/Builder.html#M000113">run</a> dispatches to an application.&#8221; </p></blockquote>
<p>So here is an example of a rackup file that you can use to startup your application with some middleware:</p>
<pre class="brush: jscript;">
   use Rack::CommonLogger
   use Rack::ShowExceptions
   use JavascriptMinifier, &quot;./&quot;
   run Rack::Lobster.new
</pre>
<h2>Testing and Spec&#8217;ing helpers</h2>
<p>Rack provides two helpers that will be of great use for testing your application: <a href="http://rack.rubyforge.org/doc/classes/Rack/MockRequest.html" target="_blank">Rack::MockRequest</a> and <a href="http://rack.rubyforge.org/doc/classes/Rack/MockResponse.html" target="_blank">Rack::MockResponse</a>, so you have no excuses to test your Rack Middleware and do some TDD/BDD!</p>
<h2>Where to go from here</h2>
<p>To learn how to develop your own Rack Middleware, your best resource will be Rack sources. You will learn a lot of Rack (and Ruby in general) by reading the code and specs they provide: <a href="http://rack.rubyforge.org/doc/classes/Rack/URLMap.html" target="_blank">URLMap</a>, <a href="http://rack.rubyforge.org/doc/classes/Rack/CommonLogger.html">CommonLogger</a>, <a href="http://rack.rubyforge.org/doc/classes/Rack/File.html">File</a>. There also is a <a href="http://groups.google.com/group/rack-devel">group</a> where you can ask your questions too.</p>
<p>So enjoy your trip with Rack Middleware and feel free to comment your thoughts and questions!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/lucianopanaro.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/lucianopanaro.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/lucianopanaro.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/lucianopanaro.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/lucianopanaro.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/lucianopanaro.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/lucianopanaro.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/lucianopanaro.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/lucianopanaro.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/lucianopanaro.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/lucianopanaro.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/lucianopanaro.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/lucianopanaro.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/lucianopanaro.wordpress.com/59/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=decodeuri.com&amp;blog=2195581&amp;post=59&amp;subd=lucianopanaro&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://decodeuri.com/2008/10/15/creating-a-rack-middleware-for-minifying-your-javascript-files/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/55d4558687335fd7de57eb9a2786fb90?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">lucianopanaro</media:title>
		</media:content>
	</item>
	</channel>
</rss>