<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Recursive Creative Blog</title>
 <link href="http://recursivecreative.com/blog/atom.xml" rel="self" />
 <link href="http://recursivecreative.com/blog/" />
 <updated>2009-07-24T15:02:10-04:00</updated>
 <id>http://recursivecreative.com/blog/</id>
 <author>
   <name>Recursive Creative</name>
   <email>us@recursivecreative.com</email>
 </author>

 
 <entry>
   <title>Serve: A Rapid Prototyping Framework For Designers</title>
   <link href="http://recursivecreative.com/blog/2009/04/21/reintroducing-serve-a-rapid-prototyping-framework-for-designers"/>
   <updated>2009-04-21T00:00:00-04:00</updated>
   <id>http://recursivecreative.com/blog/2009/04/21/reintroducing-serve-a-rapid-prototyping-framework-for-designers</id>
   <content type="html">&lt;p&gt;&lt;img src="http://recursivecreative.com/images/serve.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Since &lt;a href="https://twitter.com/adamlogic"&gt;Adam McCrea&lt;/a&gt; has introduced &lt;a href="http://blog.edgecase.com/2009/4/14/show-off-your-mockups"&gt;his solution&lt;/a&gt; for simplifying &lt;span class="caps"&gt;HTML&lt;/span&gt; mockups over on the EdgeCase blog, I thought I would take the time to reintroduce my own: Serve.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been using Serve for almost a year now to prototype MemberHub and before that I used various forms of a &lt;a href="http://wiseheartdesign.com/2007/9/4/a-haml-server-for-web-designers/"&gt;simple Ruby script&lt;/a&gt; to power my &lt;span class="caps"&gt;HTML&lt;/span&gt; mockups.&lt;/p&gt;
&lt;p&gt;Serve has become an indispensable part of my development methodology because it allows me to prototype the application using &lt;span class="caps"&gt;HTML&lt;/span&gt; in a &lt;span class="caps"&gt;DRY&lt;/span&gt; format independently of the work that is being done by developers. This independence is essential as we explore various facets of an application and prioritize the parts that should be developed first.&lt;/p&gt;
&lt;p&gt;To give you an idea of how it has worked on MemberHub. I sit down with the client beforehand and discuss a feature and the initial user stories that make up that feature. On a large feature I may spend some time during this phase drawing up a couple of paper prototypes so that we can get a general idea of the shape of the feature and how it will affect the application. We can then use the paper prototypes to give a client a fairly reliable estimate of how long it will take to do the initial development.&lt;/p&gt;
&lt;p&gt;Once the feature has been outlined in this way I can then begin work with the &lt;span class="caps"&gt;HTML&lt;/span&gt; prototype. I tend to start with the &lt;span class="caps"&gt;HTML&lt;/span&gt; prototype and not in a graphics program as it allows me to focus on the functionality without getting too caught up with how it looks initially. (I may drop back to a graphics program and &amp;#8220;punt&amp;#8221;, so to speak, if I&amp;#8217;m having trouble getting the layout just right for a particular screen.)&lt;/p&gt;
&lt;p&gt;Often while I&amp;#8217;m working on a screen for a particular section, I will call the client over (yes, I &lt;strong&gt;love&lt;/strong&gt; working onsite with my clients) and ask for their input on how it flows and feels. One of the chief advantages of developing an &lt;span class="caps"&gt;HTML&lt;/span&gt; prototype for your application is that it gives you the opportunity to explore the flow of your application before the backend development has begun. Hopefully, during the prototyping phase you will be able to iron out any problems in flow, with minimal expense because there is no backend to rework.&lt;/p&gt;
&lt;p&gt;The &amp;#8220;Design First&amp;#8221; approach is huge for us, because most, if not all, of the business decisions are ironed out in the design phase. Also at the point that a feature has passed completely through the design phase we can then estimate that feature with &lt;strong&gt;extreme&lt;/strong&gt; accuracy. The client also knows exactly what they are going to get when the development is done.&lt;/p&gt;
&lt;p&gt;Once the client has signed off on a feature in the prototype, it can then be thrown over the wall to the development team. Because we use Serve, the views can be copied over from the &lt;span class="caps"&gt;HTML&lt;/span&gt; prototype to the application almost as is. This does take some effort on my part to construct the views in a way that is friendly to a Rails application, but in general this is not hard if you understand the RESTful approach that Rails encourages. This process is also eased because Serve has full support for partials and layouts with either &lt;span class="caps"&gt;ERB&lt;/span&gt; or &lt;span class="caps"&gt;HAML&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Does the developer find it annoying to have to copy the views over from the prototype into the application instead of having the designer work with him in the application? In general, yes and no. Yes more work is involved in copying views over into the application (particularly when views change because a feature is revisited). But no, because he doesn&amp;#8217;t have to worry about a designer breaking tests or causing the application to fail in some way. It&amp;#8217;s also hugely beneficial to the developer because the guesswork is taken out of a feature when it is completely developed (and signed off on) in the prototype before the development begins.&lt;/p&gt;
&lt;p&gt;Also, I can&amp;#8217;t emphasize enough the freedom that the two project approach gives the designer. No longer is he caught up with views that are hooked into controllers, etc&amp;#8230; He can explore new features and focus almost completely on the &lt;span class="caps"&gt;HTML&lt;/span&gt;, &lt;span class="caps"&gt;CSS&lt;/span&gt;, and creative part of his job. With designers often juggling the roles of business analyst, creative expert, &lt;span class="caps"&gt;HTML&lt;/span&gt;/&lt;span class="caps"&gt;CSS&lt;/span&gt;/Javascript guru, asking for the two project approach small price to pay for the increased productivity.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve put together a brief overview of Serve in screencast form below. Let me know what you think.&lt;/p&gt;
&lt;p&gt;&lt;object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="453" height="360" id="viddler_53bf6942"&gt;&lt;param name="flashvars" value="disablebranding=t" /&gt;&lt;param name="movie" value="http://www.viddler.com/simple/53bf6942/" /&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;embed src="http://www.viddler.com/simple/53bf6942/" width="453" height="360" type="application/x-shockwave-flash" allowScriptAccess="always" flashvars="disablebranding=t" allowFullScreen="true" name="viddler_53bf6942"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;
&lt;p&gt;Mentioned in the screencast:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://github.com/jlong/serve"&gt;Serve on Github&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://memberhub.com"&gt;MemberHub&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://announceitapp.com"&gt;AnnounceIt&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://radiantcms.org"&gt;Radiant &lt;span class="caps"&gt;CMS&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://github.com/radiant/radiant-prototype"&gt;The Radiant &lt;span class="caps"&gt;CMS&lt;/span&gt; prototype on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>MemberHub.com in Six Minutes</title>
   <link href="http://recursivecreative.com/blog/2009/04/03/memberhub-com-in-6-minutes"/>
   <updated>2009-04-03T00:00:00-04:00</updated>
   <id>http://recursivecreative.com/blog/2009/04/03/memberhub-com-in-6-minutes</id>
   <content type="html">&lt;p&gt;&lt;a href="http://memberhub.com"&gt;&lt;img src="http://recursivecreative.com/images/memberhub.png" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since January of last year, I have been working with a small startup here in Raleigh building a web service called MemberHub. MemberHub has been a bit of a dream come true for me. It is the first time I&amp;#8217;ve had the opportunity to build a subscription-based web service that has massive online appeal. If it takes off, I believe that MemberHub could be the next Facebook or LinkedIn.&lt;/p&gt;
&lt;p&gt;Now don&amp;#8217;t write me off just yet&amp;#8230; Hear me out.&lt;/p&gt;
&lt;p&gt;People use Facebook for their personal lives to help manage the relationships they have with friends. LinkedIn is useful for keeping track of your business connections. MemberHub is designed to help organizations, such as churches and nonprofits connect with their members and manage the various groups that make up the organization.&lt;/p&gt;
&lt;p&gt;Using MemberHub, you can create online &amp;#8220;hubs&amp;#8221; for each of the groups that make up your organization. A hub is a simple online home for a group. It contains a home page, a calendar, a place for announcements, a discussion board/mailing list, and a place to upload files. A church, for example, could create hubs for each of its bible study  groups, a hub for the homeless ministry, a hub for the singles ministry, a hub for the worship team&amp;#8230; You get the idea.&lt;/p&gt;
&lt;p&gt;Now the concept of a hub is nothing new. There are plenty of services online today that offer similar features. Many organizations are using services like Yahoo Groups or Google Calendar with great success. MemberHub&amp;#8217;s chief strength&amp;#8212;and differentiator&amp;#8212;is that it provides these features in a way that is friendly to organizations &lt;strong&gt;and&lt;/strong&gt; members.&lt;/p&gt;
&lt;p&gt;For the organization, MemberHub makes it easy to setup and organize secure online homes for each of your groups. For the member, MemberHub makes it easy for you to keep up with multiple groups and even &lt;strong&gt;multiple organizations&lt;/strong&gt; in one convenient location! One of the most incredible features of MemberHub is that it can take all of the events across all of the hubs you are affiliated with and display them on one convenient calendar. Imagine never having to enter events in for your organizational activities again!&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ve really worked hard to make MemberHub simple and intuitive. Below is a brief, 6-minute video that will give you a bit of the bigger picture of what MemberHub can do for you:&lt;/p&gt;
&lt;p&gt;&lt;object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="453" height="359" id="viddler_d1564606"&gt;&lt;param name="flashvars" value="disablebranding=t" /&gt;&lt;param name="movie" value="http://www.viddler.com/simple/d1564606/" /&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;embed src="http://www.viddler.com/simple/d1564606/" width="453" height="359" type="application/x-shockwave-flash" allowScriptAccess="always" flashvars="disablebranding=t" allowFullScreen="true" name="viddler_d1564606"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;&lt;p&gt;If you&amp;#8217;d like to learn more about MemberHub, visit &lt;a href="http://memberhub.com"&gt;http://memberhub.com&lt;/a&gt;. And do let me know if you have questions or comments.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>AnnounceIt Beta Program</title>
   <link href="http://recursivecreative.com/blog/2009/03/28/announceit-beta-program"/>
   <updated>2009-03-28T00:00:00-04:00</updated>
   <id>http://recursivecreative.com/blog/2009/03/28/announceit-beta-program</id>
   <content type="html">&lt;p&gt;&lt;img src="http://recursivecreative.com/images/announceit.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Adam Williams and I are working on a new project together. It&amp;#8217;s called &lt;a href="http://announceitapp.com/"&gt;AnnounceIt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;AnnounceIt is a super easy way to put up a teaser page on a domain to start collecting e-mail addresses. It&amp;#8217;s great for an &amp;#8220;Announcements Only&amp;#8221; mailing list for an event, web site, or web application that is being developed. You can see an example of a &amp;#8220;teaser page&amp;#8221; for a Web application &lt;a href="http://missioncontrolapp.com/"&gt;here&lt;/a&gt; and &lt;a href="http://www.announceitapp.com/"&gt;here&lt;/a&gt; (yes we are using it to announce our own web application).&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;d like to be notified when we launch AnnounceIt, signup for our mailing list at &lt;a href="http://www.announceitapp.com/"&gt;announceitapp.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;d like to be part of our beta program send us an email at &lt;a href="mailto:us@recursivecreative.com"&gt;us@recursivecreative.com&lt;/a&gt; or reply to the &lt;a href="http://twitter.com/rcreative"&gt;@rcreative&lt;/a&gt; user on Twitter.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>HTML Canvas Test</title>
   <link href="http://recursivecreative.com/blog/2008/12/28/html-canvas-test"/>
   <updated>2008-12-28T00:00:00-05:00</updated>
   <id>http://recursivecreative.com/blog/2008/12/28/html-canvas-test</id>
   <content type="html">&lt;object width="453" height="280"&gt;&lt;param name="allowfullscreen" value="true" /&gt;&lt;param name="allowscriptaccess" value="always" /&gt;&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=2649757&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" /&gt;&lt;embed src="http://vimeo.com/moogaloop.swf?clip_id=2649757&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="453" height="280"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Meet Dataset: The Fixture-Killing, Data-Loading Framework</title>
   <link href="http://recursivecreative.com/blog/2008/12/12/meet-dataset-the-fixture-killing-data-loading-framework"/>
   <updated>2008-12-12T00:00:00-05:00</updated>
   <id>http://recursivecreative.com/blog/2008/12/12/meet-dataset-the-fixture-killing-data-loading-framework</id>
   <content type="html">&lt;p&gt;&lt;a href="http://github.com/aiwilliams/dataset"&gt;&lt;img src="http://recursivecreative.com/images/dataset.png" class="float-right no-border" alt="" /&gt;&lt;/a&gt; My good friend and partner &lt;a href="http://github.com/aiwilliams/"&gt;Adam Williams&lt;/a&gt; has just finished bolting the doors on his new &lt;em&gt;&lt;span class="caps"&gt;YAML&lt;/span&gt;-fixture-killing&lt;/em&gt; Rails plugin: &lt;em&gt;&lt;a href="http://github.com/aiwilliams/dataset"&gt;Dataset&lt;/a&gt;&lt;/em&gt;. Dataset is the next generation of a plugin that Adam and I wrote last year called &lt;a href="http://github.com/aiwilliams/scenarios/tree/master"&gt;Scenarios&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Why the need for a new plugin? The Scenarios plugin was originally built inside of a Rails application that we were working on. At the time we threw it together rather haphazardly. There were few tests (if any). The main thing was to prove that the idea was good. Scenarios worked so well for us that we soon extracted it and used it in our next application. A friend added support for Test::Unit. Pretty soon the implementation our &amp;#8220;simple&amp;#8221; fixture replacement plugin had grown quite complex. It was becoming hard to maintain.&lt;/p&gt;
&lt;p&gt;This year Adam and I have been working on a rather large Rails application. The run time for tests in our application had almost become unbearable. In an effort to speed up those tests and fix some of the outstanding issues in the Scenarios plugin, Adam decided to start from scratch and rewrite the plugin from the ground up using the test first approach.&lt;/p&gt;
&lt;p&gt;We have christened the rewrite &amp;#8220;Dataset&amp;#8221;. It is virtually a drop-in replacement for the Scenarios plugin. Our initial tests suggest that it is significantly faster than its predecessor.&lt;/p&gt;
&lt;p&gt;Folks our experience with it over the last year leads me to believe that Dataset is &lt;strong&gt;the&lt;/strong&gt; solution to the Rails fixture debacle. If you haven&amp;#8217;t tried it out yet give it a try!&lt;/p&gt;
&lt;h4&gt;Installation&lt;/h4&gt;
&lt;p&gt;Like most other Rails plugins you can use the &lt;tt&gt;script/plugin install&lt;/tt&gt; command to download the plugin into your current project:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;./script/plugin install git://github.com/aiwilliams/dataset.git&lt;br /&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once the plugin is installed, you will need to add the following lines to &lt;tt&gt;test/test_helper.rb&lt;/tt&gt;:&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;dataset&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Test&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;TestCase&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Dataset&lt;/span&gt;
  &lt;span class="n"&gt;datasets_directory&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;RAILS_ROOT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/test/datasets&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;h4&gt;General Usage&lt;/h4&gt;
&lt;p&gt;The basic idea behind Dataset is that creating and using fixture-like data for your application shouldn&amp;#8217;t be a chore. To this end Dataset encourages the use of Ruby code for generating your models. A set of Ruby models can be wrapped up for easy usage in a &amp;#8220;dataset&amp;#8221;.&lt;/p&gt;
&lt;p&gt;For example, suppose I&amp;#8217;m writing tests for the my application&amp;#8217;s authentication system. I could create a dataset with two users in it with the following code (assuming the User model is defined):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# in test/datasets/users_dataset.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersDataset&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Dataset&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;
    &lt;span class="n"&gt;create_record&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:john&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;John&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:password&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;doodaht&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;create_record&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:cindy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Cindy&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:password&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;whoot!&amp;#39;&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;Above, I&amp;#8217;m using the &lt;tt&gt;create_record&lt;/tt&gt; method to insert records for two people into the Users table. The &lt;tt&gt;create_record&lt;/tt&gt; method takes three parameters. The first is the singular name of the table to insert the record into, the second is the symbolic name of the record (for referencing the record in a test), and the third is a hash of the attributes of the record.&lt;/p&gt;
&lt;p&gt;Jumping over to my test case, I can now write:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# in test/unit/user_test.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserTest&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Test&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;TestCase&lt;/span&gt;
  &lt;span class="n"&gt;dataset&lt;/span&gt; &lt;span class="ss"&gt;:users&lt;/span&gt;
  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_do_something&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:john&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;doodaht&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&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;In order to use a specific dataset in a given test, you must declare that the test depends on it with the &lt;tt&gt;dataset&lt;/tt&gt; class method. In the example above I&amp;#8217;m declaring that UserTest depends on just UserDataset, but I could easily declare dependancies on multiple datasets by passing multiple parameters to the &lt;tt&gt;dataset&lt;/tt&gt; class method (similar to the way that the Rails &lt;tt&gt;fixture&lt;/tt&gt; method works). Once the dataset is declared you can reference specific models using the appropriate reader method (almost exactly the same as with Rails fixtures). In the example above, I loaded &amp;#8220;John&amp;#8221; with the reader method &lt;tt&gt;users&lt;/tt&gt; and the symbolic name &lt;tt&gt;:john&lt;/tt&gt;. Remember that in &lt;tt&gt;UsersDataset&lt;/tt&gt; I declared that &amp;#8220;John&amp;#8221; should be accessible through the symbolic name &lt;tt&gt;:john&lt;/tt&gt;. The &lt;tt&gt;users&lt;/tt&gt; reader method can also retrieve an array of models if you pass it multiple symbols: &lt;code&gt;users(:john, :cindy)&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Create A Variety of Datasets for Each Model&lt;/h4&gt;
&lt;p&gt;When you load a dataset with the &lt;tt&gt;dataset&lt;/tt&gt; class method, only the data declared in the dataset will be available to tests that use it. This is by design. Part of the dataset philosophy is that datasets should be small containing only a fraction of the data needed for your entire test suite. Instead of creating one massive file with all of the data needed for a testing a certain model in different states (like you would with Rails fixtures), create multiple smaller datasets and load only the data you need for each test.&lt;/p&gt;
&lt;h4&gt;Composition&lt;/h4&gt;
&lt;p&gt;As the complexity of your application grows there are times when it is useful to declare that a one dataset depends on another. The Dataset plugin allows you to do this through composition. You can declare that dataset C depends on dataset B. Then, when a test declares that it needs dataset C, dataset B will be loaded first and then C. If B depends on A, dataset A will be loaded first, then B, then C, and so forth.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s a simple example using posts and comments:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# in test/datasets/posts_dataset.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostsDataset&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Dataset&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;
    &lt;span class="n"&gt;create_record&lt;/span&gt; &lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;First Post&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;create_record&lt;/span&gt; &lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Second Post&amp;quot;&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;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# in test/datasets/comments_dataset.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CommentsDataset&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Dataset&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;uses&lt;/span&gt; &lt;span class="ss"&gt;:posts&lt;/span&gt;
  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;
    &lt;span class="n"&gt;create_record&lt;/span&gt; &lt;span class="ss"&gt;:comment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:body&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Nice post!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:post_id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:first&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;create_record&lt;/span&gt; &lt;span class="ss"&gt;:comment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:body&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;I like it.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:post_id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:first&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;create_record&lt;/span&gt; &lt;span class="ss"&gt;:comment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:third&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:body&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;I thoroughly disagree.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:post_id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:second&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;In the example above, &lt;tt&gt;CommentsDataset&lt;/tt&gt; declares that it depends on  &lt;tt&gt;PostsDataset&lt;/tt&gt; with the &lt;tt&gt;uses&lt;/tt&gt; class method. This means that if a test declares that it needs &lt;tt&gt;CommentsDataset&lt;/tt&gt;, &lt;tt&gt;PostsDataset&lt;/tt&gt; will be loaded first and then &lt;tt&gt;CommentsDataset&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;(Note that inside the load method I&amp;#8217;m using another form of reader method which simply yields the ID for a symbolic name. In this case: &lt;tt&gt;post_id&lt;/tt&gt;. This is useful for making associations without needing to load the model, as done here with comments and posts.)&lt;/p&gt;
&lt;h4&gt;Helper Methods&lt;/h4&gt;
&lt;p&gt;Another way of simplifying your datasets and tests is through helper methods. Helper methods are declared inside the &lt;tt&gt;helpers&lt;/tt&gt; block of a dataset:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# in test/datasets/users_dataset.rb&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersDataset&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Dataset&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;
    &lt;span class="n"&gt;create_user&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;John&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;john@example.com&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  
  &lt;span class="n"&gt;helpers&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
      &lt;span class="n"&gt;defaults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[,. ]+/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;@example.com&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;create_record&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;downcase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;defaults&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attributes&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;def&lt;/span&gt; &lt;span class="nf"&gt;login_as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:user_id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
    &lt;span class="k"&gt;end&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;Any of the methods declared inside a dataset&amp;#8217;s helper block are available to the dataset in addition to being mixed into datasets and tests that use it.&lt;/p&gt;
&lt;p&gt;In the helper block above I&amp;#8217;ve defined two methods. The first, &lt;tt&gt;create_user&lt;/tt&gt;, gives me an easy way to create new users with sensible defaults. (I would highly encourage using factory methods like this to remove duplication from your test data.) The second method, &lt;tt&gt;login_as&lt;/tt&gt;, is a helper method for integration tests. You can see it in action below:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# in test/integration/projects_test.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProjectsTest&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;IntegrationTest&lt;/span&gt;
  &lt;span class="n"&gt;dataset&lt;/span&gt; &lt;span class="ss"&gt;:users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:projects&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:todos&lt;/span&gt;
  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_should_show_active_projects&lt;/span&gt;
    &lt;span class="n"&gt;login_as&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:john&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="ss"&gt;:projects&lt;/span&gt;
    &lt;span class="n"&gt;assert_tag&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#active_projects&amp;#39;&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;h4&gt;What About Machinist, Factory Girl, and the Other Fixture Replacement Plugins?&lt;/h4&gt;
&lt;p&gt;If you&amp;#8217;ve taken the time to read everything above I hope you can see that Dataset is more than just a new way to construct models for testing. Dataset gives you an easy, declarative method for constructing sets of data to be used in testing. It is a data loading framework. This is in contrast to &lt;a href="http://github.com/notahat/machinist/tree/master"&gt;Machinist&lt;/a&gt; and &lt;a href="http://github.com/thoughtbot/factory_girl/tree/master"&gt;Factory Girl&lt;/a&gt; which focus only on making it easy to create new models for testing, but have no solution for loading sets of data. For the record you can use Dataset with Machinist or Factory Girl, though my personal preference is to create my own factory methods for each model.&lt;/p&gt;
&lt;p&gt;As to the other fixture replacement plugins? Frankly, I haven&amp;#8217;t seen anything that comes close to providing the power and flexibility of Dataset. But don&amp;#8217;t take my word for it! &lt;a href="http://github.com/aiwilliams/dataset"&gt;Try it for yourself&lt;/a&gt; and experience the difference.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Radiant Sprint on December 13</title>
   <link href="http://recursivecreative.com/blog/2008/12/03/radiant-sprint-on-december-13"/>
   <updated>2008-12-03T00:00:00-05:00</updated>
   <id>http://recursivecreative.com/blog/2008/12/03/radiant-sprint-on-december-13</id>
   <content type="html">&lt;p&gt;&lt;img src="http://recursivecreative.com/images/radiant.png" class="no-border float-right" alt="" /&gt; Just in case you missed the news &lt;a href="http://radiantcms.org/blog/archives/2008/11/25/radiant-mini-sprint---december-13/"&gt;we are planning&lt;/a&gt; another Radiant Sprint on Saturday, December 13. Several prestigious members of the &lt;a href="http://www.meetup.com/raleighrb/"&gt;Raleigh Ruby Brigade&lt;/a&gt; plan to attend along with some of the more questionable characters (like me!).&lt;/p&gt;
&lt;p&gt;The plan is to continue working to implement the &lt;a href="http://github.com/radiant/radiant-mockups/tree/master/blade"&gt;next version of the Radiant UI&lt;/a&gt; and bring some of the internals up to snuff. Radiant has recently been upgraded to use the more modern RESTful approach, but there are still plenty of tests to write and other improvements to be made.&lt;/p&gt;
&lt;p&gt;This is the perfect opportunity to gain a little insight into the Radiant development process and get up to speed on some of the tools we have been working with (&lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt;, &lt;a href="http://haml.hamptoncatlin.com/"&gt;&lt;span class="caps"&gt;HAML&lt;/span&gt;&lt;/a&gt;, &lt;a href="http://github.com/jlong/serve/"&gt;Serve&lt;/a&gt;, &lt;a href="http://github.com/aiwilliams/spec_integration/"&gt;Spec Integration&lt;/a&gt;, and &lt;a href="http://github.com/aiwilliams/dataset/"&gt;Dataset&lt;/a&gt;, to name a few).&lt;/p&gt;
&lt;p&gt;It will be hosted at Red Hat here in Raleigh. We&amp;#8217;ll get started around 9 am and continue until about 6 pm that evening. &lt;a href="http://www.meetup.com/raleighrb/calendar/9235561/"&gt;&lt;span class="caps"&gt;RSVP&lt;/span&gt; if you want to come along for the fun.&lt;/a&gt; Everyone is welcome to attend, even if all you want to do is &lt;a href="http://www.youtube.com/watch?v=PUjgdFoALok"&gt;heckle&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Create Facebook-like Windows with Popup.js</title>
   <link href="http://recursivecreative.com/blog/2008/07/17/create-facebook-like-windows-with-popup-js"/>
   <updated>2008-07-17T00:00:00-04:00</updated>
   <id>http://recursivecreative.com/blog/2008/07/17/create-facebook-like-windows-with-popup-js</id>
   <content type="html">&lt;p&gt;&lt;img src ="http://recursivecreative.com/images/popupjs.png" width="453" height="150" alt="popup.js" title="popup.js" /&gt;&lt;/p&gt;&lt;p&gt;Over the past couple of months I&amp;#8217;ve been working on a little library for a client that allows us to create Facebook-like popup windows with ease. It&amp;#8217;s called &lt;a href="http://github.com/jlong/popupjs/tree/master"&gt;popup.js&lt;/a&gt;. The library depends on Dan Webb&amp;#8217;s excellent &lt;a href="http://www.danwebb.net/2006/9/3/low-pro-unobtrusive-scripting-for-prototype"&gt;Low Pro&lt;/a&gt; and comes complete with it&amp;#8217;s own behavior for easy unobtrusive use.&lt;/p&gt;
&lt;p&gt;So how does it work? Well, once you have the proper plumbing in place you can declare a simple popup window like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;popup&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;test&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;display: none&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Popup Window&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;popup_content&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello world!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;javascript: Element.closePopup(&amp;#39;test&amp;#39;)&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Close&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This markup assumes that you are using the included &lt;tt&gt;facebook.css&lt;/tt&gt; stylesheet, but the only thing that is necessary to have a functioning popup window is a div with an ID attribute. You should also set style=&amp;#8220;display: none&amp;#8221; to ensure that the div is not visible when the page loads.&lt;/p&gt;
&lt;p&gt;Popping up the window is as simple as linking to it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#test&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;popup&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Popup&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/code&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Links with the class of &amp;#8220;popup&amp;#8221; get the &lt;tt&gt;Popup.TriggerBehavior&lt;/tt&gt; which will trigger the popup when clicked. Note that the href should be set to the ID of the element to popup. If you prefer you can set the href to a &lt;span class="caps"&gt;URL&lt;/span&gt; that returns the &lt;span class="caps"&gt;HTML&lt;/span&gt; for the popup and an &lt;span class="caps"&gt;AJAX&lt;/span&gt; call will be made to that &lt;span class="caps"&gt;URL&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;For more information about this little lib, see the &lt;span class="caps"&gt;README&lt;/span&gt; in the GitHub project:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://github.com/jlong/popupjs/tree/master/README"&gt;http://github.com/jlong/popupjs/tree/master/&lt;span class="caps"&gt;README&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And investigate the test project:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://github.com/jlong/popupjs/tree/master/test"&gt;http://github.com/jlong/popupjs/tree/master/test&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em class="fine_print"&gt;Special thanks to Five Points Solutions for their help debugging this library. They have contributed several Internet Explorer bug fixes in addition to funding much of the initial development.&lt;/em&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Pragmatic Programmer Site Live!</title>
   <link href="http://recursivecreative.com/blog/2007/10/27/pragmatic-programmer-site-live"/>
   <updated>2007-10-27T00:00:00-04:00</updated>
   <id>http://recursivecreative.com/blog/2007/10/27/pragmatic-programmer-site-live</id>
   <content type="html">&lt;p&gt;&lt;a href="http://pragprog.com/" title="The Pragmatic Programmers"&gt;&lt;img src ="http://recursivecreative.com/images/pragprog-com-screenshot.png" width="453" height="150" alt="The Pragmatic Programmers" title="The Pragmatic Programmers" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;This may be old news for some of you, but the &lt;a href="http://pragprog.com"&gt;Pragmatic Web Site&lt;/a&gt; got a face lift a couple of weeks ago. I was thrilled to have the opportunity to work on the site with Mike, Dave, and Andy. Most of the design work was done this summer, while the finishing touches on programming and the data import pushed the launch date back to the beginning of October. (Site credits &lt;a href="http://pragprog.com/resources/credits/"&gt;here&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;If you haven&amp;#8217;t seen it yet, I&amp;#8217;d encourage you to head on over to the site and &lt;a href="http://pragmaticprogrammer.com/titles/"&gt;buy a book or something&lt;/a&gt;!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Introducing Serve: Now With Gemmi Goodness!</title>
   <link href="http://recursivecreative.com/blog/2007/09/25/introducing-serve"/>
   <updated>2007-09-25T00:00:00-04:00</updated>
   <id>http://recursivecreative.com/blog/2007/09/25/introducing-serve</id>
   <content type="html">&lt;p&gt;Based on my &lt;a href="http://wiseheartdesign.com/2007/9/4/a-haml-server-for-web-designers/"&gt;&lt;span class="caps"&gt;HAML&lt;/span&gt; Server for Web Designers&lt;/a&gt; article, I&amp;#8217;ve created a small gem &amp;#8220;serve&amp;#8221; which makes it extremely easy for a Web Designer to get up and running with Haml and Sass:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;sudo gem install haml redcloth bluecloth serve
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/Workspaces/prototype
&lt;span class="nv"&gt;$ &lt;/span&gt;ls . * 
.:
index.haml

images:
logo.gif

javascripts:
prototype.js        dialogs.js         tabset.js

stylesheets:
application.sass        dialogs.sass
&lt;span class="nv"&gt;$ &lt;/span&gt;serve
&lt;span class="o"&gt;[&lt;/span&gt;2007-09-25 02:11:42&lt;span class="o"&gt;]&lt;/span&gt; INFO  WEBrick 1.3.1
&lt;span class="o"&gt;[&lt;/span&gt;2007-09-25 02:11:42&lt;span class="o"&gt;]&lt;/span&gt; INFO  ruby 1.8.5 &lt;span class="o"&gt;(&lt;/span&gt;2006-12-25&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;2007-09-25 02:11:42&lt;span class="o"&gt;]&lt;/span&gt; INFO  Serve::Server#start: &lt;span class="nv"&gt;pid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1626 &lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3000
...
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And voila! I can now access the files in ~/Workspaces/prototype at:&lt;/p&gt;
&lt;blockquote&gt;&lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Serve isn&amp;#8217;t just a &lt;span class="caps"&gt;HAML&lt;/span&gt; or &lt;span class="caps"&gt;SASS&lt;/span&gt; server.&lt;/strong&gt; With the proper gems it can also handle Textile and Markdown (not to mention plain Jane &lt;span class="caps"&gt;HTML&lt;/span&gt;!).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Serve also plays nicely with Rails.&lt;/strong&gt; If you have a file named &amp;#8220;script/server&amp;#8221; in the current directory, Serve will execute that script instead of launching the normal WEBrick server.&lt;/p&gt;
&lt;p&gt;Complete usage information is available with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;serve --help
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="http://rubyforge.org/projects/serve/"&gt;Learn more about the project over at Ruby Forge&amp;#8230;&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>A HAML Server for Web Designers</title>
   <link href="http://recursivecreative.com/blog/2007/09/04/a-haml-server-for-web-designers"/>
   <updated>2007-09-04T00:00:00-04:00</updated>
   <id>http://recursivecreative.com/blog/2007/09/04/a-haml-server-for-web-designers</id>
   <content type="html">&lt;p&gt;I have a script named &lt;tt&gt;serve&lt;/tt&gt; in my &lt;tt&gt;bin&lt;/tt&gt; directory that let&amp;#8217;s me quickly startup a Webrick server in any directory. This is handy for serving &lt;span class="caps"&gt;HTML&lt;/span&gt; mockups or other files. Today, updated it to work with &lt;span class="caps"&gt;HAML&lt;/span&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#!/usr/bin/env ruby&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;webrick&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;haml&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HamlHandler&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;WEBrick&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTPServlet&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;AbstractServlet&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;
    &lt;span class="vi"&gt;@script_filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;begin&lt;/span&gt;
      &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@script_filename&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parse_haml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;content-type&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;text/html&amp;#39;&lt;/span&gt;
    &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt;
    &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;
      &lt;span class="vi"&gt;@logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;HTTPStatus&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;InternalServerError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="n"&gt;do_POST&lt;/span&gt; &lt;span class="n"&gt;do_GET&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_haml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Haml&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;:attr_wrapper&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;:filename&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@script_filename&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;WEBrick&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTPServlet&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FileHandler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;haml&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;HamlHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ARGV&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gsub!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;%r{^http://}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[ :]/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compact&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;WEBrick&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTPServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;:Port&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:BindAddress&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;0.0.0.0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:DocumentRoot&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;trap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;INT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shutdown&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Just an Experiment</title>
   <link href="http://recursivecreative.com/blog/2007/08/26/just-an-experiment"/>
   <updated>2007-08-26T00:00:00-04:00</updated>
   <id>http://recursivecreative.com/blog/2007/08/26/just-an-experiment</id>
   <content type="html">&lt;p&gt;&lt;img src="http://recursivecreative.com/images/game.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;OK, this has nothing to do with what I&amp;#8217;m working on in &lt;a href="http://basement.thewilliams.ws"&gt;Adam&amp;#8217;s basement&lt;/a&gt;, but &lt;a href="http://johnwlong.com/game.html"&gt;here&amp;#8217;s a starfield simulation&lt;/a&gt; I&amp;#8217;ve been working on for a small game in Javascript. It&amp;#8217;s an interesting example of what is possible in Javascript on a modern Web browser (tested on Safari 3 and Firefox 2). Be sure to check out the source. Prototype makes this type of thing extremely easy.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Constraints, Frameworks, and Adam’s Basement</title>
   <link href="http://recursivecreative.com/blog/2007/08/25/constraints-frameworks-and-adam-s-basement"/>
   <updated>2007-08-25T00:00:00-04:00</updated>
   <id>http://recursivecreative.com/blog/2007/08/25/constraints-frameworks-and-adam-s-basement</id>
   <content type="html">&lt;p&gt;It&amp;#8217;s official. Adam Williams and I are now working feverishly &lt;a href="http://basement.thewilliams.ws"&gt;in his basement&lt;/a&gt; on our little idea for a web app. We&amp;#8217;re both pushing off other obligations for the next 3 months so that we can concentrate on building a quality product.&lt;/p&gt;
&lt;p&gt;One of the fun things about building your own application is that you can truly make it whatever you want it to be. If you&amp;#8217;ve been in an environment (like me) where you are constantly building things for other people, working on your own project can be liberating. As a creative person I love this! The sky is the limit. No idea is a bad one. Every idea is worth considering.&lt;/p&gt;
&lt;p&gt;But wait a minute! Even though we are now working on our own project we still have constraints. We don&amp;#8217;t have an unlimited amount of time or money that we can devote to this. We eventually need to ship a working product even if it isn&amp;#8217;t everything we initially visualized it would be. In fact, we have to be brutal about what we allow into the app and what we throw out. If we aren&amp;#8217;t brutal we&amp;#8217;ll end up with something sub-par. Either the app will lack the really useful features when it ships or it will never ship.&lt;/p&gt;
&lt;p&gt;This week we&amp;#8217;ve worn our creative hat a lot. One of the mistakes I think that we have made is that we have focused a lot on system architecture issues and not enough on application features. I&amp;#8217;m beginning to realize that on the front end of this process it is extremely important to focus on application features. We can always refactor the application in the future when we know more about what the system architecture issues are. The features will help clarify that.&lt;/p&gt;
&lt;p&gt;Extract a framework from your application. Resist the urge to invent a framework before working on features.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Better Modularization for Rails 2.0 (or What Rails Can Learn from Django)</title>
   <link href="http://recursivecreative.com/blog/2007/06/15/better-modularization-for-rails-2-0"/>
   <updated>2007-06-15T00:00:00-04:00</updated>
   <id>http://recursivecreative.com/blog/2007/06/15/better-modularization-for-rails-2-0</id>
   <content type="html">&lt;p&gt;In my previous post about &lt;a href="http://recursivecreative.com/2006/12/06/rails-needs-something-better-than-engines/"&gt;Rails and Engines&lt;/a&gt;, I talked about some of the issues I&amp;#8217;d like to see resolved in Rails 2.0. Specifically, it seems that we need to rethink modularization in Rails and make it easier for people to share complete slices of applications.&lt;/p&gt;
&lt;p&gt;One of the primary hinderances of the present Rails architecture to modularization is the directory structure.&lt;/p&gt;
&lt;p&gt;Consider the typical rails &lt;tt&gt;app&lt;/tt&gt; directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;app/
  controllers/
    application.rb
    account_controller.rb
    blog_controller.rb
    comments_controller.rb
  helpers/
    application_helper.rb
    account_helper.rb
    blog_helper.rb
  models/
    user.rb
    blog.rb
    post.rb
    comment.rb
  views/
    account/
      signup.rhtml
      login.rhtml
      edit.rhtml
    blog/
      index.rhtml
      archive.rhtml
      post.rhtml
    comments/
      view.rhtml
      remove.rhtml
    layouts/
      application.rhtml
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now at first glance, the Rails directory structure seems quite helpful. There is a place for everything and everything is in its place. Models go here, views here, controllers here&amp;#8230; The entire &lt;span class="caps"&gt;MVC&lt;/span&gt; in 3 different directories. Wait a minute! Compare this to the &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; directory structure for the same application:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;account/
  __init__.py
  urls.py
  models.py
  views.py
  templates/
    account/
      account_login.html
      account_signup.html
      account_edit.html
blog/
  __init__.py
  urls.py
  models.py
  views.py
  templates/
    blog/
      blog_list.html
      blog_archive.html
      blog_detail.html
    comment/
      comment_view.html
      comment_remove.html
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Wow! See the difference? Django divides the application up not according to file type, but according to &lt;i&gt;logical structure&lt;/i&gt;. Related files are together. This makes it easy to share entire chunks of an application. All you have to do is create an svn:external to the appropriate directory of another app and instantly you have access to an entire slice of the other application.&lt;/p&gt;
&lt;p&gt;Imagine if Rails took the same approach. The new app directory could look something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;app/
  application/
    application_controller.rb
    application_layout.rhtml
  account/
    _config.rb
    _routes.rb
    account_controller.rb
    account_helper.rb
    account_edit.rhtml
    account_login.rhtml
    account_signup.rhtml
    user.rb
    user_migrations.rb
  blog/
    _config.rb
    _routes.rb
    blog_controller.rb
    blog_helper.rb
    blog_index.rhtml
    blog_archive.rhtml
    blog_post.rhtml
    comment.rb
    comment_migrations.rb
    comments_controller.rb
    comments_helper.rb
    comments_view.rhtml
    post.rb
    post_migrations.rb
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now I&amp;#8217;ve changed things around just a bit to accommodate the new directory structure and support better modularization. Views are now prefixed with the name of the controller that they are associated with (this allows us to avoid having to put them in a separate directory). I&amp;#8217;ve also changed migrations around so that all the migrations for a particular model are in the same file (we would probably need a new domain language for this). Also note that the &lt;tt&gt;&lt;em&gt;config.rb&lt;/tt&gt; and &lt;tt&gt;&lt;/em&gt;routes.rb&lt;/tt&gt; files give us a convenient place to store configuration for a particular slice of our application (the underscore prefix would sort them to the top of a directory listing).&lt;/p&gt;
&lt;p&gt;So that&amp;#8217;s my big idea for Rails 2.0. It would be a radical departure from the present directory structure. So radical that it would effectively make Rails 2.0 applications incompatible with Rails 1.0 apps. But we are already dropping support for deprecated features in Rails 2.0, so perhaps it&amp;#8217;s time to rethink the directory structure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; There is some &lt;a href="http://groups.google.com/group/rubyonrails-core/browse_thread/thread/45685895778b1357/"&gt;interesting discussion&lt;/a&gt; going on about this on the Rails-Core mailing list.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Two Rails Testing Plugins</title>
   <link href="http://recursivecreative.com/blog/2007/05/03/two-rails-testing-plugins"/>
   <updated>2007-05-03T00:00:00-04:00</updated>
   <id>http://recursivecreative.com/blog/2007/05/03/two-rails-testing-plugins</id>
   <content type="html">&lt;p&gt;I just released two Rails plugins that should make testing a little easier for some of you.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;The &lt;a href="http://faithfulcode.rubyforge.org/svn/plugins/trunk/test_helpers/"&gt;test_helpers&lt;/a&gt; plugin makes it easy to &lt;span class="caps"&gt;DRY&lt;/span&gt; up your test cases by moving shared code into modules. It includes the handy dandy  &amp;#8220;test_helper&amp;#8221; class method to make requiring and including a snap.&lt;/li&gt;
	&lt;li&gt;The &lt;a href="http://faithfulcode.rubyforge.org/svn/plugins/trunk/abstract_testcases/"&gt;abstract_testcases&lt;/a&gt; plugin makes it easy to create abstract test cases that don&amp;#8217;t complain about tests not being defined. If you&amp;#8217;d rather not go the module route, this is the plugin for you.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Installation is just like any other Rails plugin:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;script/plugin &lt;span class="nb"&gt;source &lt;/span&gt;http://wiseheartdesign.com/svn/plugins/
&lt;span class="nv"&gt;$ &lt;/span&gt;script/plugin install test_helpers
&lt;span class="nv"&gt;$ &lt;/span&gt;script/plugin install abstract_testcases
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Comments and feedback are welcome.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Setting Up Ubuntu for Rails</title>
   <link href="http://recursivecreative.com/blog/2007/05/03/setting-up-ubuntu-for-rails"/>
   <updated>2007-05-03T00:00:00-04:00</updated>
   <id>http://recursivecreative.com/blog/2007/05/03/setting-up-ubuntu-for-rails</id>
   <content type="html">&lt;p&gt;&lt;a href="http://showmedo.com/videos/video?name=rubyGrosenbachDeprec&amp;amp;fromSeriesID=48"&gt;&lt;img src="http://farm1.static.flickr.com/198/482613727_d250389253_m.jpg" class="float-right" alt="" /&gt;&lt;/a&gt; I just found a wonderful little screencast by &lt;a href="http://nubyonrails.com/"&gt;Geoffrey Grosenbach&lt;/a&gt; of &lt;a href="http://peepcode.com/"&gt;Peep Code Screencasts&lt;/a&gt; on setting up the full Rails stack on Ubuntu. He&amp;#8217;s uploaded it so that &lt;a href="http://showmedo.com/videos/video?name=rubyGrosenbachDeprec&amp;amp;fromSeriesID=48"&gt;anyone can watch it over on the ShowMeDo website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;From the description:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This 10 minute demo shows how easy it is to install Ruby, Rails, Apache, Mongrel, Subversion, and MySQL on an Ubuntu server. Capistrano and the deprec gem (deployment recipes) are used to automate the installation process with only a few commands. It finishes with a deployment of a Rails app to the newly built server!&lt;/p&gt;
&lt;p&gt;The demo is done with Parallels on a Mac, but would work with any machine that can boot from the Ubuntu 6.06 Live CD.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Props to Geoffrey for his great work with helping Rails newbies (and even &amp;#8220;old timers&amp;#8221; like me) get their feet wet.&lt;/p&gt;</content>
 </entry>
 
 
</feed>