<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en-us">
  <id>http://wiseheartdesign.com/</id>
  <title type="text">Wiseheart Design</title>
  <updated>
    2010-07-19T15:54:44Z
  </updated>
  <author>
    <name>John W. Long</name>
    <uri>http://wiseheartdesign.com/</uri>
  </author>
  
  <link rel="alternate" type="text/html" href="http://wiseheartdesign.com" />
  <generator>Radiant CMS</generator>
  
    
      
        <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/WiseheartDesign" /><feedburner:info uri="wiseheartdesign" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
          <id>http://wisheartdesign.com//articles/2010/07/19/radiant-cms-add-child-menu//</id>
          <title type="html">Radiant CMS: Add Child Menu</title>
          <updated>2010-07-19T15:54:44Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://wiseheartdesign.com/articles/2010/07/19/radiant-cms-add-child-menu/"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0086/page-children.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://github.com/joshfrench"&gt;Josh French&lt;/a&gt; and I have just committed a series of changes to Radiant that will change the way page children are created (you must be &lt;a href="http://wiki.github.com/radiant/radiant/running-on-edge"&gt;running on edge&lt;/a&gt; to see the changes). Instead of creating a child page immediately, the &amp;#8220;Add Child&amp;#8221; button will now present you with a list of page types. The goal of this change is to move the selection of page type to page creation. This change is essential for a number of other ideas that we are considering.&lt;/p&gt;
&lt;p&gt;One benefit of this approach is that it allows a custom page type to change the way a page is initialized. For example, a page type could determine the initial values of fields or page parts.&lt;/p&gt;
&lt;p&gt;In the future, this could also allow custom page types to easily make modifications to the page editing interface. So a Blog Post page type could add a dropdown to select the post author, or even list the comments on the post. Or an Event page type could add fields for the location and date.&lt;/p&gt;
&lt;p&gt;We are looking for feedback on this change from the Radiant community. Add your thoughts in the comments below.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/DsjbI2D5jvU" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/DsjbI2D5jvU/" />
          <published>2010-07-19T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/07/19/radiant-cms-add-child-menu//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/06/07/compass-with-serve-and-rack//</id>
          <title type="html">Compass with Serve and Rack</title>
          <updated>2010-06-07T18:36:15Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://wiseheartdesign.com/articles/2010/06/07/compass-with-serve-and-rack/"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0084/compass.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I talked briefly about racking up your &lt;a href="http://github.com/jlong/serve"&gt;Serve&lt;/a&gt; projects in my &lt;a href="http://wiseheartdesign.com/articles/2010/05/26/racking-up-a-serve-project-on-phusion-passenger/"&gt;previous article&lt;/a&gt;. But apart from the benefit of being able to deploy Serve on Passenger or Mongrel, why is &lt;a href="http://rack.rubyforge.org/"&gt;Rack&lt;/a&gt; integration cool?&lt;/p&gt;
&lt;p&gt;One benefit is that you get access to all kinds of &lt;em&gt;middleware&lt;/em&gt;. Middleware is a software module that extends your server or web application with additional functionality. It&amp;#8217;s called middleware because it sits between your application and the web server software. When a request for a file or resource comes into the server it first travels through each layer of middleware before reaching your application. Your application then sends a response back which again travels each layer of middleware before being served up to the user. As the request and response travel through each layer of middleware, the middleware can make changes to or even serve up something totally different. This is useful for adding features like logging, custom error handling, or gzip compression.&lt;/p&gt;
&lt;p&gt;I my original article I showed you how to use &lt;a href="http://github.com/rack/rack/blob/master/lib/rack/showstatus.rb"&gt;Rack::ShowStatus&lt;/a&gt; and &lt;a href="http://github.com/rack/rack/blob/master/lib/rack/showexceptions.rb"&gt;Rack::ShowExceptions&lt;/a&gt; to get handy error messages for your project. Today, I&amp;#8217;d like to show you how to add Compass integration.&lt;/p&gt;
&lt;p&gt;Never heard of &lt;a href="http://compass-style.org/"&gt;Compass&lt;/a&gt;? Compass is a fancy new &lt;span class="caps"&gt;CSS&lt;/span&gt; framework built on &lt;a href="http://sass-lang.com/"&gt;Sass&lt;/a&gt; and it&amp;#8217;s awesome. Among other things it provides a number of handy CSS3 modules that allow you to easily use a number of advanced &lt;span class="caps"&gt;CSS&lt;/span&gt; features. Without Compass and Sass this kind of stuff becomes pretty labor intensive to write.&lt;/p&gt;
&lt;p&gt;Now Serve comes with built in support for serving Sass files, but it doesn&amp;#8217;t know anything about Compass. To use Serve with Compass you will need to add the following lines to your &lt;code&gt;config.ru&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;sass/plugin/rack&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;compass&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="constant"&gt;Compass&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;add_project_configuration&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;root&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;/compass.config&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;&lt;br /&gt;&lt;span class="constant"&gt;Compass&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;configure_sass_plugin!&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;use&lt;/span&gt; &lt;span class="constant"&gt;Sass&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Plugin&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Rack&lt;/span&gt;    &lt;span class="comment"&gt;# Compile Sass on the fly&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first two lines are necessary so that the Sass Rack middleware is installed and the Compass framework is loaded. The next two lines tell Compass where your configuration file is located (in this case I&amp;#8217;ve put it in the project root) and configure Sass using the configuration values stored there. The last line loads the Sass plugin as middleware.&lt;/p&gt;
&lt;p&gt;Your &lt;code&gt;compass.config&lt;/code&gt; should look something like this:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="ident"&gt;http_path&lt;/span&gt;       &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;/&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;css_dir&lt;/span&gt;         &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;public/stylesheets&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;sass_dir&lt;/span&gt;        &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;public/stylesheets/sass&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;images_dir&lt;/span&gt;      &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;images&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;javascripts_dir&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;javascripts&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;relative_assets&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Your actual values will vary depending on how you are using Compass, but the key variables for the purposes of this tutorial are &lt;code&gt;css_dir&lt;/code&gt; and &lt;code&gt;sass_dir&lt;/code&gt;. In this case I&amp;#8217;ve chosen to have the plugin generate my &lt;span class="caps"&gt;CSS&lt;/span&gt; in the &lt;code&gt;public/stylesheets&lt;/code&gt; directory and store my Sass (much like Rails does) in the &lt;code&gt;public/stylesheets/sass&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;ve separated your dynamic and static assets into the &lt;code&gt;views&lt;/code&gt; and &lt;code&gt;public&lt;/code&gt; directories (like I suggested in my previous article) you will notice that I&amp;#8217;ve chosen to put my Sass and &lt;span class="caps"&gt;CSS&lt;/span&gt; in the directory for static assets (&lt;code&gt;public&lt;/code&gt;). This is because the Sass plugin is designed to generate your &lt;span class="caps"&gt;CSS&lt;/span&gt; when the first request is made to your Serve application. Generated files are nice in production environments because they can be served directly by the Web server instead of by your application. This is in contrast to the way that Sass files are normally used with a Serve project. Normally, you would put your Sass files in &lt;code&gt;views/stylesheets&lt;/code&gt; and they would be processed by the Serve Rack adapter on each request.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://gist.github.com/416035"&gt;Here&amp;#8217;s a Gist&lt;/a&gt; of the source code for this entire tutorial along with a couple of other goodies. Enjoy!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Hat tip to &lt;a href="http://chriseppstein.github.com/"&gt;Chris Eppstein&lt;/a&gt; for his help with this.&lt;/em&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/jW3yKUCrOI4" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/jW3yKUCrOI4/" />
          <published>2010-06-07T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/06/07/compass-with-serve-and-rack//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/05/26/racking-up-a-serve-project-on-phusion-passenger//</id>
          <title type="html">Racking Up A Serve Project On Phusion Passenger</title>
          <updated>2010-05-26T18:34:01Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://wiseheartdesign.com/articles/2010/05/26/racking-up-a-serve-project-on-phusion-passenger/"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0082/serve_passenger.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://github.com/jlong/serve"&gt;Serve&lt;/a&gt; is a rapid prototyping framework that I have been building for Web applications. It is specifically designed to make it easy to prototype Rails applications, but it can easily be used to prototype applications for any other framework. I&amp;#8217;ve talked about the benefits of using Serve before, so I won&amp;#8217;t cover that here, but if you are interested in learning more about Serve read, &lt;a href="http://dev.wiseheartdesign.com/articles/2009/04/21/reintroducing-serve-a-rapid-prototyping-framework-for-designers/"&gt;&lt;em&gt;Serve: A Rapid Prototyping Framework for Designers&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yesterday I released &lt;a href="http://rubygems.org/gems/serve"&gt;Serve 0.11.2&lt;/a&gt; which adds built-in support for &lt;a href="http://github.com/rack/rack"&gt;Rack&lt;/a&gt;. Rack allows a Ruby application to be deployed in any number of environments (Mongrel, &lt;span class="caps"&gt;CGI&lt;/span&gt;, Passenger, etc.). The good news for Serve users is that you can now deploy Serve projects much like any other Rails application.&lt;/p&gt;
&lt;p&gt;Today, I&amp;#8217;d like to talk about setting up your Serve project for deployment on &lt;a href="http://www.modrails.com/"&gt;Passenger&lt;/a&gt; (a.k.a. mod_rails). Passenger is an Apache/Nginx module that allows you easily deploy Rack-based applications in production environments. The benefit for Serve users is that with Rack and Passenger, Serve is much easier to deploy on a modern Web server. This will allow you to put your prototype project on a Web server that is easily accessible by your clients. Or, if you are on a Mac and you prefer to stay away from the command line, you can use Passenger and the &lt;a href="http://www.fngtps.com/passenger-preference-pane"&gt;Passenger Preference Pane&lt;/a&gt; to handle your Serve projects.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not going to cover the setting up Passenger in this tutorial. That is already &lt;a href="http://www.modrails.com/install.html"&gt;well documented&lt;/a&gt; on the Passenger web site. Instead I&amp;#8217;m going to talk about how to convert your Serve project so that it works well with Passenger.&lt;/p&gt;
&lt;p&gt;Passenger requires that Rack applications have a certain structure for performance and security reasons.&lt;/p&gt;
&lt;h4&gt;The Basics&lt;/h4&gt;
&lt;p&gt;We learn from the &lt;a href="http://www.modrails.com/documentation/Users%20guide%20Apache.html#_deploying_a_rack_based_ruby_application"&gt;Passenger User Guide&lt;/a&gt; that Rack applications must have three things:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;A &lt;code&gt;tmp&lt;/code&gt; directory&lt;/li&gt;
	&lt;li&gt;A &lt;code&gt;public&lt;/code&gt; directory&lt;/li&gt;
	&lt;li&gt;A &lt;code&gt;config.ru&lt;/code&gt; file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The tmp directory is used by Passenger for the &lt;code&gt;restart.txt&lt;/code&gt; file. You can notify Passenger that your Rack application should be restarted by updating the Last-Modified timestamp on the restart.txt file. The public directory is needed for static assets like images, javascripts, and stylesheets &amp;#8212; in this case anything that is not processed by Serve directly. The config.ru file is a Ruby-based configuration file for Rack.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m going to suggest that we add one more directory:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;A &lt;code&gt;views&lt;/code&gt; directory&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the views directory we&amp;#8217;ll put all of the &lt;span class="caps"&gt;ERB&lt;/span&gt;, &lt;span class="caps"&gt;HAML&lt;/span&gt;, and special Serve files that are necessary for the prototype. Anything that does not need to be processed by Serve should go in the public directory. This includes all images, javascripts, etc. &lt;span class="caps"&gt;CSS&lt;/span&gt; files should also go in the public directory, but &lt;span class="caps"&gt;SASS&lt;/span&gt; or &lt;span class="caps"&gt;SCSS&lt;/span&gt; files should go in the views directory.&lt;/p&gt;
&lt;p&gt;To create these directories and files, you can execute the following commands from the command line in the root of your project:&lt;/p&gt;
&lt;pre class="code bash-code"&gt;&lt;code&gt;$ mkdir tmp&lt;br /&gt;$ touch tmp/restart.txt&lt;br /&gt;$ mkdir public&lt;br /&gt;$ mkdir views&lt;br /&gt;$ touch config.ru&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now move all of your existing Serve files into the views directory (&lt;span class="caps"&gt;ERB&lt;/span&gt;, &lt;span class="caps"&gt;HAML&lt;/span&gt;, &lt;span class="caps"&gt;SASS&lt;/span&gt;, Redirects, etc&amp;#8230;). Be sure to preserve the existing directory structure. If you have a &lt;code&gt;view_helpers.rb&lt;/code&gt; file that should also go in the root of views directory.&lt;/p&gt;
&lt;p&gt;Once that is complete, move images, javascripts, and other static assets into the &lt;code&gt;public&lt;/code&gt; directory. Again, be sure to preserve the existing directory structure. (If a file was in &lt;code&gt;images/icons&lt;/code&gt; it should now be in &lt;code&gt;public/images/icons&lt;/code&gt;.)&lt;/p&gt;
&lt;h4&gt;Rack Configuration&lt;/h4&gt;
&lt;p&gt;Now open up &lt;code&gt;config.ru&lt;/code&gt; in your favorite text editor and insert the following code:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="ident"&gt;gem&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;activesupport&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;2.3.5&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="comment"&gt;# version required by Serve&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;gem&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;serve&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;serve&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;serve/rack&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;# Middleware&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;use&lt;/span&gt; &lt;span class="constant"&gt;Rack&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;ShowStatus&lt;/span&gt;      &lt;span class="comment"&gt;# Nice looking 404s and other messages&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;use&lt;/span&gt; &lt;span class="constant"&gt;Rack&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;ShowExceptions&lt;/span&gt;  &lt;span class="comment"&gt;# Nice looking errors&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;# The project root directory&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;root&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;dirname&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;__FILE__&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;# Rack Application&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="constant"&gt;ENV&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;SERVER_SOFTWARE&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;passenger&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="comment"&gt;# Passenger only needs the adapter&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;run&lt;/span&gt; &lt;span class="constant"&gt;Serve&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;RackAdapter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;root&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;/views&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;else&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="comment"&gt;# We use Rack::Cascade and Rack::Directory on other platforms to&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="comment"&gt;# handle static assets&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;run&lt;/span&gt; &lt;span class="constant"&gt;Rack&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Cascade&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;([&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="constant"&gt;Serve&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;RackAdapter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;root&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;/views&lt;/span&gt;&lt;span class="punct"&gt;'),&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="constant"&gt;Rack&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Directory&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;root&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;/public&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;])&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Advanced users may want to modify this a bit to include other middleware or applications, but this configuration should suffice for the basic Serve project. I&amp;#8217;ve included the Rack::ShowStatus and Rack::ShowExceptions middleware to provide pretty 404s, messages, and error handling. To turn off either of these features just comment out the appropriate line. Rack::Cascade and Rack::Directory are used to handle files in the public directory if Passenger is not used. This is useful if you are using Rack from the command line via the &lt;code&gt;rackup&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;So that&amp;#8217;s it! Everything you need to know to rackup a Serve project on Passenger.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/KgZKE2-b2y4" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/KgZKE2-b2y4/" />
          <published>2010-05-26T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/05/26/racking-up-a-serve-project-on-phusion-passenger//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/05/15/full-stack-iphone-development//</id>
          <title type="html">Full-Stack iPhone Development</title>
          <updated>2010-05-15T22:16:03Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://fullstackiphone.com?referer=WiseheartDesign"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0080/full-stack-iphone.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Last week I helped my friends at &lt;a href="http://terralien.com/?referer=WiseheartDesign"&gt;Terralien&lt;/a&gt; launch &lt;a href="http://fullstackiphone.com/?referer=WiseheartDesign"&gt;fullstackiphone.com&lt;/a&gt;. Full-Stack iPhone is a long-standing service from Terralien under a new name. Terralien has been doing iPhone interfaces for Web applications for some time now so we thought it would be appropriate to begin promoting the service in a more public way.&lt;/p&gt;
&lt;p&gt;Terralien can deliver a lot of value to potential clients. Nathaniel Talbott has done a great job assembling a hand-picked team of top-notch developers and designers that are passionate about building successful businesses. If you are looking for a team that can build an iPhone application with an incredible Web-based backend, be sure to &lt;a href="http://fullstackiphone.com/"&gt;check us out&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/lFFuCmaxYR4" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/lFFuCmaxYR4/" />
          <published>2010-05-15T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/05/15/full-stack-iphone-development//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/04/30/radiant-cms-layout-tricks//</id>
          <title type="html">Radiant CMS Layout Tricks</title>
          <updated>2010-04-30T18:02:11Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://wiseheartdesign.com/articles/2010/04/30/radiant-cms-layout-tricks/"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0078/radiant-layouts.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Page layouts are one of the most powerful features of Radiant. Layouts allow you to encapsulate much of the common &lt;span class="caps"&gt;HTML&lt;/span&gt; of a website into a template of sorts that is filled in with the information unique to each page.&lt;/p&gt;
&lt;p&gt;Today, I&amp;#8217;d like to share a couple of tips and tricks for making the best use of this powerful feature. These aren&amp;#8217;t hard and fast rules, just a couple of the best practices that I&amp;#8217;ve picked up over the years as I&amp;#8217;ve worked with Radiant.&lt;/p&gt;
&lt;h4&gt;Use One Layout If Possible&lt;/h4&gt;
&lt;p&gt;Radiant allows you to create as many layouts as you want for your website. At first glance you may be tempted to create multiple layouts for your site that have a one-to-one relationship with the type of page you are creating. For instance, you may want to have a layout for your home page, one for your portfolio, one for your blog, etc. Resist this urge if you can. Depending on how your &lt;span class="caps"&gt;HTML&lt;/span&gt; and &lt;span class="caps"&gt;CSS&lt;/span&gt; are written, you may be able to get away with just one layout &amp;#8212; even if the page that you are working on has a vastly different look and feel. The trick is to use conditional tags to switch parts of the layout on and off depending on the page.&lt;/p&gt;
&lt;p&gt;Why is this helpful? It keeps all of the common code in one place and allows you to keep things &lt;span class="caps"&gt;DRY&lt;/span&gt;. It also minimizes user error and ensures that each page has the proper design, because a content editor never has to worry about selecting the proper layout. You set the layout once on the root page, and all the other pages inherit it.&lt;/p&gt;
&lt;h4&gt;Use Conditional Tags To Build Flexible Layouts&lt;/h4&gt;
&lt;p&gt;Radiant provides a number of conditional tags that make it easy to build smart layouts. Use them.&lt;/p&gt;
&lt;p&gt;The most commonly used is tag is probably &lt;code&gt;if_url&lt;/code&gt; (and its sister &lt;code&gt;unless_url&lt;/code&gt;). This tag allows you to test the &lt;span class="caps"&gt;URL&lt;/span&gt; of the current page and show or hide content based on the condition. You can do an exact match on the &lt;span class="caps"&gt;URL&lt;/span&gt; by using the &lt;code&gt;equals&lt;/code&gt; attribute, but I mostly use the &lt;code&gt;matches&lt;/code&gt; attribute because it allows me to use regular expressions to match an array of URLs.&lt;/p&gt;
&lt;p&gt;For instance, on WiseheartDesign.com I insert code for comments using the &lt;code&gt;if_url&lt;/code&gt; tag with the &lt;code&gt;matches&lt;/code&gt; attribute like this:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;if_url &lt;span class="attribute"&gt;matches&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;^/articles/.+&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;
...code to display comments here...
&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;if_url&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you are not familiar with regular expressions, this may look a little convoluted, but it is really quite simple. It basically reads, if the &lt;span class="caps"&gt;URL&lt;/span&gt; starts with &amp;#8220;/articles/&amp;#8221; and is followed by at least one character, then insert the following code. That last part is necessary so that the articles index page (which has the &lt;span class="caps"&gt;URL&lt;/span&gt; of &amp;#8220;/articles/&amp;#8221;), is not matched by the expression.&lt;/p&gt;
&lt;p&gt;As you can see, the &lt;code&gt;if_url&lt;/code&gt; tag is quite powerful for adding conditions to your layouts, but it has one significant weakness. Since it relies on the &lt;span class="caps"&gt;URL&lt;/span&gt; of the page, if you change the &lt;span class="caps"&gt;URL&lt;/span&gt; scheme for your website, you will need to remember to come back and update your layout. If your layouts are riddled with calls to &lt;code&gt;if_url&lt;/code&gt; this may prove to be a bit of a headache.&lt;/p&gt;
&lt;p&gt;Another tag that may be useful here is the &lt;code&gt;if_content&lt;/code&gt; tag. You can use the &lt;code&gt;if_content&lt;/code&gt; tag to test if a page has certain parts (or the &lt;code&gt;unless_content&lt;/code&gt; tag to test that it does not). With clever naming of page parts you can get a lot of mileage out of this simple tag.&lt;/p&gt;
&lt;p&gt;For instance, suppose you have two basic page designs for your web site. One is a standard two-column design with content and sidebar. Another is a simple single column design with no sidebar. By testing for the existence of the sidebar, you can actually handle both cases with a single layout:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;if_content &lt;span class="attribute"&gt;part&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;sidebar&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;div &lt;span class="attribute"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;content&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;content &lt;span class="punct"&gt;/&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;div&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;div &lt;span class="attribute"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;sidebar&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;content &lt;span class="attribute"&gt;part&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;sidebar&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;div&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;if_content&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;unless_content &lt;span class="attribute"&gt;part&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;sidebar&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;div &lt;span class="attribute"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;content&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="attribute"&gt;class&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;no_sidebar&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;content &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;div&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;unless_content&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The code above checks for the existence of the &amp;#8220;sidebar&amp;#8221; part. If it exists it renders two divs, one for the content and one for the sidebar. If the &amp;#8220;sidebar&amp;#8221; part does not exist, only the content div is rendered &amp;#8211; this time with the &amp;#8220;no_sidebar&amp;#8221; class so that the single column version can be styled differently.&lt;/p&gt;
&lt;p&gt;With a little a little imagination, I&amp;#8217;m sure that you can see how the same technique can be used to achieve one-column, two-column, and three-column designs &amp;#8211; all within the context of a single Radiant layout.&lt;/p&gt;
&lt;h4&gt;Use Snippets To Simplify Complex Layouts&lt;/h4&gt;
&lt;p&gt;Radiant snippets are designed to make it easy to share share common code between layouts and/or pages, but they are also useful for other purposes. The more complicated your layouts become the more you will find it makes sense to extract meaningful parts into Radiant snippets.&lt;/p&gt;
&lt;p&gt;One purpose is to isolate complex or verbose code. For instance, you may want to put your Google Analytics code in a snippet. You will probably only enter this code once during the lifetime of your site, and there is no reason that it should clutter up your layout code.&lt;/p&gt;
&lt;p&gt;Another purpose is to make content more accessible. I often put my navigation code in a snippet because as I update a site it is easier to maintain in isolation.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/VIt2cKlZwy4" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/VIt2cKlZwy4/" />
          <published>2010-04-30T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/04/30/radiant-cms-layout-tricks//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/04/08/togglejs-unobtrusively-show-and-hide-elements-with-effects//</id>
          <title type="html">ToggleJS: Unobtrusively Show and Hide Elements With Effects</title>
          <updated>2010-04-08T21:03:08Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://wiseheartdesign.com/articles/2010/04/08/togglejs-unobtrusively-show-and-hide-elements-with-effects/"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0076/unobtrusive-toggling.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Today I would like to announce the release of &lt;a href="http://github.com/fivepointssolutions/togglejs"&gt;ToggleJS&lt;/a&gt; &amp;#8211; a &lt;a href="http://github.com/danwrong/low-pro"&gt;LowPro&lt;/a&gt; and &lt;a href="http://prototypejs.org/"&gt;Prototype&lt;/a&gt;-based solution for unobtrusively toggling elements with effects. ToggleJS makes it easy to create an advanced section on a form that slides out when the &amp;#8220;Advanced&amp;#8221; link is clicked, or to show more options when a certain check box is checked. And it does all of this with beautiful effects (complements of script.aculo.us).&lt;/p&gt;
&lt;p&gt;&lt;a href="http://wiseheartdesign.com/page_attachments/0000/0075/demo.html"&gt;View the online demo.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The way ToggleJS works is you select an element to be the &amp;#8220;Trigger&amp;#8221; element that will cause another another element revealed. You can chose a link, a checkbox, a select box, or a group of radio buttons as your trigger. You then add a &lt;code&gt;rel&lt;/code&gt; attribute to the element that identifies an ID or group of IDs for the elements that should be revealed.&lt;/p&gt;
&lt;h4&gt;Using a Link as a Trigger&lt;/h4&gt;
&lt;p&gt;For example, the following code will create an advanced section that will only be revealed when the &amp;#8220;Advanced&amp;#8221; link is clicked:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&amp;lt;p&amp;gt;&amp;lt;a class=&amp;quot;toggle&amp;quot; href=&amp;quot;#advanced&amp;quot; rel=&amp;quot;toggle[advanced]&amp;quot;&amp;gt;Advanced&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;div id=&amp;quot;advanced&amp;quot;&amp;gt;&lt;br /&gt;... advanced options here ...&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note that I&amp;#8217;ve set the &lt;code&gt;rel&lt;/code&gt; attribute to &amp;#8220;toggle[advanced]&amp;#8221;. This is a special syntax that identifies the list of IDs that should be toggled when the trigger is clicked. (IDs appear between the brackets. To toggle multiple IDs separate them with commas.) In this case we are telling ToggleJS that the &amp;#8220;Advanced&amp;#8221; link is a trigger for the &amp;#8220;advanced&amp;#8221; div. By convention, toggle triggers are also identified with the &amp;#8220;toggle&amp;#8221; class (this is configurable). Also note that ToggleJS will take care of hiding the &amp;#8220;advanced&amp;#8221; div when the page loads.&lt;/p&gt;
&lt;h4&gt;A Checkbox Trigger&lt;/h4&gt;
&lt;p&gt;To create a checkbox toggle trigger, the syntax is almost identical:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&amp;lt;p&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;input type=&amp;quot;checkbox&amp;quot; class=&amp;quot;toggle&amp;quot; name=&amp;quot;remind&amp;quot; id=&amp;quot;remind&amp;quot; value=&amp;quot;1&amp;quot; rel=&amp;quot;toggle[remind_on]&amp;quot; /&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;label for=&amp;quot;remind&amp;quot;&amp;gt;Remind me&amp;lt;/label&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;span id=&amp;quot;remind_on&amp;quot;&amp;gt;on &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;date&amp;quot; /&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the example above, if the user checks the &amp;#8220;Remind me&amp;#8221; checkbox a date field will appear where they can enter a date for the reminder. ToggleJS is smart enough to recognize whether the checkbox is checked on page load and will hide or show the related element as needed.&lt;/p&gt;
&lt;h4&gt;Selects and Options&lt;/h4&gt;
&lt;p&gt;The code necessary to make this work with a select box is a little different. Instead of setting the &lt;code&gt;rel&lt;/code&gt; attribute on the select box, you should set it on each of the options:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&amp;lt;select class=&amp;quot;toggle&amp;quot;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;option&amp;gt;- none -&amp;lt;/option&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;option value=&amp;quot;1&amp;quot; rel=&amp;quot;toggle[one]&amp;quot;&amp;gt;One&amp;lt;/option&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;option value=&amp;quot;2&amp;quot; rel=&amp;quot;toggle[two]&amp;quot;&amp;gt;Two&amp;lt;/option&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;option value=&amp;quot;1,2&amp;quot; rel=&amp;quot;toggle[one,two]&amp;quot;&amp;gt;One and Two&amp;lt;/option&amp;gt;&lt;br /&gt;&amp;lt;/select&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;div id=&amp;quot;one&amp;quot;&amp;gt;1&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div id=&amp;quot;two&amp;quot;&amp;gt;2&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this example, the select box is used to toggle the visibility of divs &amp;#8220;one&amp;#8221; and &amp;#8220;two&amp;#8221;, based on selection. Note that the last option, &amp;#8220;One and Two&amp;#8221;, displays both divs by specifying both IDs in the &lt;code&gt;rel&lt;/code&gt; attribute.&lt;/p&gt;
&lt;h4&gt;Radio Buttons&lt;/h4&gt;
&lt;p&gt;The fourth and final way that you can use ToggleJS, is with a group of radio buttons. The code is actually strikingly similar to the code used for the select boxes:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&amp;lt;div class=&amp;quot;radio_group toggle&amp;quot;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;input type=&amp;quot;radio&amp;quot; name=&amp;quot;numbers&amp;quot; id=&amp;quot;numbers_none&amp;quot;/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;label for=&amp;quot;numbers_none&amp;quot;&amp;gt;None&amp;lt;/label&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;input type=&amp;quot;radio&amp;quot; name=&amp;quot;numbers&amp;quot; id=&amp;quot;numbers_one&amp;quot; value=&amp;quot;1&amp;quot; rel=&amp;quot;toggle[one]&amp;quot; /&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;label for=&amp;quot;numbers_one&amp;quot;&amp;gt;One&amp;lt;/label&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;input type=&amp;quot;radio&amp;quot; name=&amp;quot;numbers&amp;quot; id=&amp;quot;numbers_two&amp;quot; value=&amp;quot;2&amp;quot; rel=&amp;quot;toggle[two]&amp;quot; /&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;label for=&amp;quot;numbers_two&amp;quot;&amp;gt;Two&amp;lt;/label&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;input type=&amp;quot;radio&amp;quot; name=&amp;quot;numbers&amp;quot; id=&amp;quot;numbers_three&amp;quot; value=&amp;quot;1,2&amp;quot; rel=&amp;quot;toggle[one,two]&amp;quot; /&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;label for=&amp;quot;numbers_three&amp;quot;&amp;gt;One and Two&amp;lt;/label&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;div id=&amp;quot;one&amp;quot;&amp;gt;1&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div id=&amp;quot;two&amp;quot;&amp;gt;2&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;The Wiring&lt;/h4&gt;
&lt;p&gt;Apart from the standard script tags for LowPro and Prototype, you will also need to wire in the appropriate LowPro behaviors. If you are building a Rails application, I&amp;#8217;d recommend that you put this in &amp;#8220;application.js&amp;#8221;:&lt;/p&gt;
&lt;pre class="code javascript-code"&gt;&lt;code&gt;Event.addBehavior({&lt;br /&gt;&amp;nbsp;&amp;nbsp;'a.toggle': Toggle.LinkBehavior(),&lt;br /&gt;&amp;nbsp;&amp;nbsp;'input[type=checkbox].toggle': Toggle.CheckboxBehavior(),&lt;br /&gt;&amp;nbsp;&amp;nbsp;'div.radio_group.toggle': Toggle.RadioGroupBehavior(),&lt;br /&gt;&amp;nbsp;&amp;nbsp;'select.toggle': Toggle.SelectBehavior()&lt;br /&gt;});&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What this code does is associate the LowPro behaviors with the correct elements based on &lt;span class="caps"&gt;CSS&lt;/span&gt; selectors. You can customize the rules above if you want to use different class names or if you would like to tweak the behaviors with custom options.&lt;/p&gt;
&lt;p&gt;For example, you can create an inverted toggle checbox by adding the following line to the Event.addBehavior call:&lt;/p&gt;
&lt;pre class="code javascript-code"&gt;&lt;code&gt;'a.inverted_toggle': Toggle.LinkBehavior({inverted: true}),&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;An inverted toggle link would hide the associated div the first time it was clicked instead of showing it.&lt;/p&gt;
&lt;p&gt;You can also customize the effect used and handle custom before and after toggle events for the &lt;code&gt;Toggle.LinkBehavior&lt;/code&gt;. For full details on the different options that you can pass the LowPro behaviors, consult the &lt;a href="http://github.com/fivepointssolutions/togglejs/blob/master/dist/toggle.js"&gt;inline documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are also two configuration variables that can be used to customize the default settings for all toggle behaviors:&lt;/p&gt;
&lt;pre class="code javascript-code"&gt;&lt;code&gt;Toggle.DefaultEffect = 'appear';    # a string; the default is 'slide'&lt;br /&gt;Toggle.DefaultEffectDuration = 0.5; # in seconds; the default is 0.25&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;ToggleJS removes the need to write custom code to toggle the visibility of other elements for many of the common use cases. And it does all of this in a clean unobtrusive way. You can learn more about ToggleJS, over at the &lt;a href="http://github.com/fivepointssolutions/togglejs"&gt;GitHub project&lt;/a&gt; or view the online demo &lt;a href="http://wiseheartdesign.com/page_attachments/0000/0075/demo.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before closing, I&amp;#8217;d like to thank the kind folks at &lt;a href="http://memberhub.com"&gt;MemberHub&lt;/a&gt; who sponsored the initial development of ToggleJS and have allowed me to release it as open source. MemberHub is a group communications platform for churches and other organizations.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/3fnkj-eKYro" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/3fnkj-eKYro/" />
          <published>2010-04-08T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/04/08/togglejs-unobtrusively-show-and-hide-elements-with-effects//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/03/11/proposal-generic-conditionals-for-radiant-cms//</id>
          <title type="html">Proposal: Generic Conditionals for Radiant CMS</title>
          <updated>2010-03-11T18:12:32Z</updated>
          <content type="html">&lt;p&gt;Over the years we have had many requests on the &lt;a href="http://radiantcms.org/mailing-list"&gt;Radiant &lt;span class="caps"&gt;CMS&lt;/span&gt; Mailing List&lt;/a&gt; to add better support for conditional tags of some kind. Right now we have an array of tags for making conditional statements that are included in the standard distribution. The following is an incomplete list:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;if_children&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;           &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;unless_children&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;if_content&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;            &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;unless_content&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;if_url&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;                &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;unless_url&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;if_ancestor_or_self&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;unless_ancestor_or_self&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;if_self&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;               &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;unless_self&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;if_parent&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;             &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;unless_parent&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;if_dev&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;                &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;unless_dev&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When Radiant was first released, we only had &lt;tt&gt;if_content&lt;/tt&gt; and the rest were added as the need arose. We have considered adding generic support for conditionals, but every proposal thus far seems to require additional syntax of some kind. Chris Parish took a stab at adding generic support for conditionals at one point. &lt;a href="http://ext.radiantcms.org/extensions/65-conditional-tags"&gt;His extension&lt;/a&gt; allows a user to type expressions like:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;if &lt;span class="attribute"&gt;cond&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;breadcrumb matches /your regexp/&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;or even,&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r&lt;span class="punct"&gt;:&lt;/span&gt;if &lt;span class="attribute"&gt;cond&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;parts includes-any ['body', 'other part']&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To date we have avoided adding something like this to the core because of quibbles over the precise syntax. We also value the rigidity that the Radius attribute syntax provides. To be effective with tags in Radiant, a designer only has to understand tags, attributes, and nesting. Adding another strange comparison syntax on top of this seems needlessly complex.&lt;/p&gt;
&lt;h4&gt;Towards A Generic Syntax for Conditionals&lt;/h4&gt;
&lt;p&gt;While thinking about some of this today, it occurred to me that there might be a reasonable compromise that preserves &lt;span class="caps"&gt;HTML&lt;/span&gt;-like, attribute-oriented syntax while allowing a high degree of flexibility.&lt;/p&gt;
&lt;p&gt;So without further ado, I would like to propose that we add generic support for conditionals to Radiant with the following basic syntax:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&amp;lt;r&lt;span class="punct"&gt;:&lt;/span&gt;if &lt;span class="attribute"&gt;property&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="attribute"&gt;matches&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;regexp&lt;span class="punct"&gt;"&lt;/span&gt;&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;or &lt;tt&gt;unless&lt;/tt&gt;,&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&amp;lt;r&lt;span class="punct"&gt;:&lt;/span&gt;unless &lt;span class="attribute"&gt;property&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="attribute"&gt;matches&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;regexp&lt;span class="punct"&gt;"&lt;/span&gt;&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Above, the &lt;tt&gt;property&lt;/tt&gt; attribute indicates a property on a page that a conditional operates on. (I will talk about properties in detail in a minute.) The &lt;tt&gt;matches&lt;/tt&gt; attribute indicates that the property should match the given regular expression if the tag is going to expand. Additional attributes would include &lt;tt&gt;equals&lt;/tt&gt;, &lt;tt&gt;nequals&lt;/tt&gt; (for not equals), and &lt;tt&gt;nmatches&lt;/tt&gt; (for not matches).&lt;/p&gt;
&lt;p&gt;Now what exactly are properties? Properties would be a new first class concept in Radiant. There would be properties for all of the default page attributes (&lt;tt&gt;title&lt;/tt&gt;, &lt;tt&gt;slug&lt;/tt&gt;, &lt;tt&gt;url&lt;/tt&gt;, etc.), but you would also be able to define your own properties with a class method on &lt;tt&gt;Page&lt;/tt&gt;. So subclasses of &lt;tt&gt;Page&lt;/tt&gt; could define their own properties or extensions could add properties to &lt;tt&gt;Page&lt;/tt&gt; to declare properties that are accessible to all pages.&lt;/p&gt;
&lt;p&gt;To declare a property you would define it within the &lt;strong&gt;class definition&lt;/strong&gt; of a page like this:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="ident"&gt;property&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;By default, with no additional parameters this would assume that the property &amp;#8216;name&amp;#8217; is a reference to the ActiveRecord attribute &amp;#8216;name&amp;#8217;. But you could also pass a block to calculate properties on the fly:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="comment"&gt;# Under the covers, properties are just augmented method&lt;/span&gt;&lt;br /&gt;&lt;span class="comment"&gt;# declarations so you still have access to other methods on&lt;/span&gt;&lt;br /&gt;&lt;span class="comment"&gt;# the page, like &amp;quot;url&amp;quot; below.&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;property&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;full_url&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;http://wiseheartdesign.com&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;url&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This would allow you to create constructs like:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="ident"&gt;property&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;author.name&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;author&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Of course, some additional sugar would make this much easier:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="ident"&gt;property&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;author&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:method&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;author&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:attributes&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:email&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:website&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This would declare three properties, &amp;#8216;author.name&amp;#8217;, &amp;#8216;author.email&amp;#8217;, and &amp;#8216;author.website&amp;#8217;.&lt;/p&gt;
&lt;p&gt;Once properties are declared you could access them within tag definitions like this:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="comment"&gt;# A basic implementation of the if tag&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;tag&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;if&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;tag&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;page&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;tag&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;locals&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;page&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;property&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;tag&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;attr&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;property&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;value&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;page&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;properties&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;property&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;equals&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;tag&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;attr&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;equals&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;tag&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expand&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;value&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="ident"&gt;equals&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The bracket syntax would give tag authors easy access to properties on a page and make properties a first class concept in Radiant that extension authors can take to another level.&lt;/p&gt;
&lt;h4&gt;A Generic Case Statement&lt;/h4&gt;
&lt;p&gt;I would also suggest that there is room for a third type of conditional statement. We already have &lt;tt&gt;if&lt;/tt&gt; and &lt;tt&gt;unless&lt;/tt&gt;, why not &lt;tt&gt;case&lt;/tt&gt;?&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&amp;lt;r&lt;span class="punct"&gt;:&lt;/span&gt;case &lt;span class="attribute"&gt;property&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;author.name&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;r&lt;span class="punct"&gt;:&lt;/span&gt;when &lt;span class="attribute"&gt;equals&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;John&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&amp;gt;Lead Designer&amp;lt;/r&lt;span class="punct"&gt;:&lt;/span&gt;when&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;r&lt;span class="punct"&gt;:&lt;/span&gt;when &lt;span class="attribute"&gt;equals&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;Sean&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&amp;gt;Lead Developer&amp;lt;/r&lt;span class="punct"&gt;:&lt;/span&gt;when&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;r&lt;span class="punct"&gt;:&lt;/span&gt;else&amp;gt;Core Developer&amp;lt;/r&lt;span class="punct"&gt;:&lt;/span&gt;else&amp;gt;&lt;br /&gt;&amp;lt;/r&lt;span class="punct"&gt;:&lt;/span&gt;case&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And yes did you see that? &lt;tt&gt;case&lt;/tt&gt;, &lt;tt&gt;when&lt;/tt&gt;, and &lt;tt&gt;else&lt;/tt&gt; allow us to avoid &lt;tt&gt;if&lt;/tt&gt;, &lt;tt&gt;then&lt;/tt&gt;, and &lt;tt&gt;else&lt;/tt&gt; &amp;#8211; another one of the commonly suggested features. We can keep it clean with single tags for &lt;tt&gt;if&lt;/tt&gt; and &lt;tt&gt;unless&lt;/tt&gt;, and allow &lt;tt&gt;case&lt;/tt&gt;, &lt;tt&gt;when&lt;/tt&gt;, and &lt;tt&gt;else&lt;/tt&gt; for complex conditionals.&lt;/p&gt;
&lt;h4&gt;Suggestions, Addendums, Thoughts?&lt;/h4&gt;
&lt;p&gt;So there you have it. My proposal for adding a generic syntax for Radiant conditionals to the standard tag library. Any thoughts or comments from the Radiant community? Is this a can of worms or a powerful, much needed addition? Put your thoughts in the comments below.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/gn8ihUDo0Cs" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/gn8ihUDo0Cs/" />
          <published>2010-03-11T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/03/11/proposal-generic-conditionals-for-radiant-cms//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/03/02/all-designers-are-not-equal-how-to-hire-the-right-designer//</id>
          <title type="html">All Designers Are Not Equal: How to Hire the Right Designer</title>
          <updated>2010-03-02T05:10:45Z</updated>
          <content type="html">&lt;p&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0068/mugshots.jpg" tile="" height="250" alt="mugshots" width="520" /&gt;&lt;/p&gt;
&lt;p&gt;With all the buzz on the Web today about the necessity of good design for success, there has been very little discussion about matching the right designer to the right project. The way the word &amp;#8220;designer&amp;#8221; is used today is a bit ambiguous. It can refer to any one of a broad range of professions. From usability experts, to illustrators, to &lt;span class="caps"&gt;HTML&lt;/span&gt; and &lt;span class="caps"&gt;CSS&lt;/span&gt; specialists, to typographers, to user experience people.&lt;/p&gt;
&lt;p&gt;To make matters worse, this confusion about the word &amp;#8220;designer&amp;#8221; and what it actually means often leads to hiring decisions that set projects up for failure. Hiring the wrong designer for your project can be akin to asking the wrong type of doctor operate on you. You would never ask a foot doctor to do brain surgery. Or, an eye doctor to remove your appendix. But the same kind of thing happens all the time in the design world and nobody blinks.&lt;/p&gt;
&lt;p&gt;The truth is there are many different kinds of designers, and each is good at different things. Yes, some designers are generalists and their value lies in their ability to deliver consistently across multiple disciplines, but generalists rarely deliver the highest quality work.&lt;/p&gt;
&lt;p&gt;So how do you find the right designer for your project? Especially if you don&amp;#8217;t know a lot about design? Where do you start?&lt;/p&gt;
&lt;h4&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0070/paint.jpg" tile="" height="150" alt="paint" align="left" width="180" /&gt; Recognize Different Designers Work Better In Different Mediums&lt;/h4&gt;
&lt;p&gt;One of the rookie mistakes you want to avoid when choosing a designer for your website is picking a print designer to do a Web designer&amp;#8217;s job. There is a huge difference in the skills necessary to pull off a successful website design and the skills necessary to operate well in print. And the opposite is also true!&lt;/p&gt;
&lt;p&gt;Since I primarily do Web design for a living I probably wouldn&amp;#8217;t be the best person to design an album cover for your new CD or to create a brochure for your business. Could I do it for you? Absolutely! But again, I wouldn&amp;#8217;t be the best choice. There are other people who can do this kind of work in less time and with better results than I can currently offer.&lt;/p&gt;
&lt;p&gt;Why is this true? Because the medium that you ask an artist to operate in is just as important as the artist you choose. What do I mean by medium? The medium is the method or materials through which a work of art is presented. As this applies to design we generally use terms like print, web, or motion graphics (Flash).&lt;/p&gt;
&lt;p&gt;Why is the medium so important? Because the medium that a designer is working in makes a huge difference in the quality of work that he is able to produce. You wouldn&amp;#8217;t ask a sculptor to design a skyscraper, or painter to compose a symphony. All of these people can create beautiful things if you put them in their element, but get it wrong and you won&amp;#8217;t get good results.&lt;/p&gt;
&lt;h4&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0072/strength.jpg" tile="" height="260" alt="paint" align="right" style="margin-right: 1em" width="200" /&gt; Recognize Designers Have Different&amp;nbsp;Strengths&lt;/h4&gt;
&lt;p&gt;Along the same lines, the other mistake you want to avoid is selecting a designer that does not have a strong skillset for the types of things that will be necessary to complete your project successfully. Some designers are really good at illustration, use of photos, or color. Some designers are great at branding and logo design. Some at usability or total user experience (UX). Some are amazing at marketing and message.&lt;/p&gt;
&lt;p&gt;On the same token, while a designer may be really good at one thing (say illustration), he or she may be terrible at another (say usability).&lt;/p&gt;
&lt;p&gt;Why is this? A lot of it is about experience. Some of it, natural gifting. But a huge part of it is related to the designer&amp;#8217;s personal passions. Designers tend to do well at the things they enjoy. Or, to enjoy the things that they do well. A good question to ask a potential designer is does your project fall into the category of the things that he or she enjoys? If it does you will probably find them quite knowledgeable about the things that are necessary for your project to be a success.&lt;/p&gt;
&lt;p&gt;The last thing you want is to end up paying someone a lot of money to do something that they are not good at. Consider a potential designer&amp;#8217;s strengths and weaknesses when matching them up with your project.&lt;/p&gt;
&lt;h4&gt;Recognize Some Designers Have&amp;nbsp;Different&amp;nbsp;Appeal&lt;/h4&gt;
&lt;p&gt;Another thing to consider in your search for the right designer for your project is the appeal that their personal style has to your target audience. Some designers are good at tailoring their style to the audience, but others are not. This isn&amp;#8217;t necessarily a bad thing. Many designers are very successful at producing a certain look that their clients value. As you are evaluating a designer consider the diversity of his portfolio, or, conversely, the consistency. Is their personal style something that would appeal to your target audience? If the answer is no, move on.&lt;/p&gt;
&lt;h4&gt;Other Things To Consider&lt;/h4&gt;
&lt;p&gt;Of course, there are many other things to consider as you look to hire a designer for your own project. How well do they communicate? Do they connect with you personally? How responsible and honest are they? But the points listed above should give you a framework for considering the value that they may be able to deliver in terms of design.&lt;/p&gt;
&lt;p&gt;If you can afford it you may want to engage multiple designers. One to work on each of the individual components of the project. For example you could engage one designer to help you develop a good logo and brand for your company (or project), another to work on the marketing and emotional appeal of your website, and another to work on the user experience.&lt;/p&gt;
&lt;p&gt;If money is tight, you may want to engage a designer that is more of a generalist rather than a specialist. After all, there are times when it&amp;#8217;s just more economical to go to a family doctor instead of a specialist. But know the difference and hire accordingly.&lt;/p&gt;
&lt;p&gt;And don&amp;#8217;t forget to ask probing questions like the ones mentioned in this article. It is your money, business, and reputation that is on the line.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/uyw-iOyR8EU" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/uyw-iOyR8EU/" />
          <published>2010-03-02T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/03/02/all-designers-are-not-equal-how-to-hire-the-right-designer//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/02/24/brandon-mathis-fancy-avatars//</id>
          <title type="html">Brandon Mathis: Fancy Avatars</title>
          <updated>2010-02-24T20:23:40Z</updated>
          <content type="html">&lt;p&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0066/brandon.jpg" src="" height="150" alt="Brandon Mathis" align="left" width="150" /&gt; My good friend and fellow designer &lt;a href="http://brandonmathis.com"&gt;Brandon Mathis&lt;/a&gt; has put together a wonderful little default avatar package that is available &lt;em&gt;for free&lt;/em&gt; on his website.&lt;/p&gt;
&lt;p&gt;Brandon and I had the good fortune of being able to work together on &lt;a href="http://memberhub.com"&gt;MemberHub.com&lt;/a&gt; back in 2008. MemberHub&amp;#8217;s design needs were growing beyond what I could handle at the time so we needed someone to help us power through many of the features we were working on. An all around great guy and extremely competent designer, Brandon was just the sort of person we were looking for to assist us.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0062/default-avatar.png" height="128" alt="Default Avatar (male)" align="right" width="128" /&gt; So it was while we were in the midst of things working on MemberHub that Brandon took the time to improve the MemberHub default avatar. The default avatar is the picture that every user gets to represent them if they haven&amp;#8217;t uploaded a photo on MemberHub.com. At the time we were using a lame question mark avatar reminiscent of the old Facebook default avatar. We wanted to make the avatar a little more personal. As we looked around for a good free option we discovered to our chagrin that there really weren&amp;#8217;t any. We both thought this was a shame, so Brandon spent his own time to create a default avatar set that we could use on MemberHub.com that he could also release for anyone to use.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://brandonmathis.com/projects/fancy-avatars/"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0060/fancy-avatars.png" height="200" alt="Fancy Avatars" width="520" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The result was &lt;em&gt;&lt;a href="http://brandonmathis.com/projects/fancy-avatars/"&gt;Fancy Avatars&lt;/a&gt;&lt;/em&gt;. A default avatar set that can be easily customized to suit your needs. The set includes male and female avatars, and the orignal vector source image (a Fireworks &lt;span class="caps"&gt;PNG&lt;/span&gt;). &lt;em&gt;Fancy Avatars&lt;/em&gt; is licensed under a &lt;em&gt;&lt;a href="http://creativecommons.org/licenses/by/3.0/"&gt;Creative Commons Attribution&lt;/a&gt;&lt;/em&gt; license so it is free to use on both commercial and personal projects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://brandonmathis.com/projects/fancy-avatars/demo/"&gt;Check out the demo page&lt;/a&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;a href="http://brandonmathis.com/projects/fancy-avatars/fancy-avatars.zip"&gt;download the set now&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/HG-Ew-mgrj8" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/HG-Ew-mgrj8/" />
          <published>2010-02-24T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/02/24/brandon-mathis-fancy-avatars//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/02/17/open-source-design-help-needed//</id>
          <title type="html">Open Source Design Help Needed!</title>
          <updated>2010-02-17T22:51:39Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://github.com/radiant/radiant-prototype"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0056/radiant-editor.png" alt="Radiant CMS Prototype Project" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t know if this is even possible, but I wanted to put it out there to at least stimulate some discussion and perhaps even jolt some of you to action. I&amp;#8217;m issuing a public call for designers interested in contributing to &lt;a href="http://radiantcms.org"&gt;Radiant &lt;span class="caps"&gt;CMS&lt;/span&gt;&lt;/a&gt;. Effective immediately.&lt;/p&gt;
&lt;p&gt;No, I&amp;#8217;m not looking for resumes, portfolios, or recommendations. I&amp;#8217;m looking for people who are good at what they do and get it done. Opinionated, kind-hearted folk who communicate well and can handle criticism. If that sounds like you, here&amp;#8217;s how you can get involved&amp;#8230;&lt;/p&gt;
&lt;h4&gt;Fork the Radiant Prototype Project on GitHub&lt;/h4&gt;
&lt;p&gt;&lt;a href="http://github.com/radiant/radiant-prototype"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0050/radiant-prototype.png" alt="Radiant CMS Prototype Project" align="right" style="margin-top: 0.75em" /&gt;&lt;/a&gt; We&amp;#8217;ve created a &lt;a href="http://github.com/radiant/radiant-prototype"&gt;prototype project&lt;/a&gt; on GitHub for Radiant that makes it easy to jump in and contribute. To get started, &lt;a href="http://help.github.com/forking/"&gt;fork the project on GitHub&lt;/a&gt;, clone it onto your local box and use &lt;strong&gt;Serve&lt;/strong&gt; to get it running so that you can start making changes.&lt;/p&gt;
&lt;p&gt;New to Git or GitHub? Check out the GitHub &lt;a href="http://learn.github.com/"&gt;learning site&lt;/a&gt; and &lt;a href="http://help.github.com/"&gt;help system&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;New to Serve? Read the &lt;a href="http://wiseheartdesign.com/articles/2009/04/21/reintroducing-serve-a-rapid-prototyping-framework-for-designers/"&gt;introductory article&lt;/a&gt; and watch the screencast at the end. The great part about using Serve for the prototype is that it allows us to focus on just the &lt;span class="caps"&gt;HTML&lt;/span&gt;, &lt;span class="caps"&gt;CSS&lt;/span&gt;, and Javascript. Once we get things worked out in the prototype they can easily be ported over into the application.&lt;/p&gt;
&lt;h4&gt;Pick An Issue&lt;/h4&gt;
&lt;p&gt;There are a number of issues related to the interface on the GitHub &lt;a href="http://github.com/radiant/radiant/issues"&gt;issue tracker&lt;/a&gt;, if you are looking for something simple start there. There&amp;#8217;s not currently a lot of design related issues, but here&amp;#8217;s the low hanging fruit:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://github.com/radiant/radiant/issues#issue/27"&gt;Extensible settings interface&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://github.com/radiant/radiant/issues#issue/33"&gt;Add a drop down menu for adding snippets to page&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://github.com/radiant/radiant/issues/issue/81/#comment_137581"&gt;Explore autosizing textareas&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://github.com/radiant/radiant/issues#issue/26"&gt;Toolbars for filters&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://github.com/radiant/radiant/issues#issue/28"&gt;Add Javascripts and Stylesheets tabs&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://github.com/radiant/radiant/issues#issue/21"&gt;Allow a user to change the order of page parts as displayed in the editor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are also a number of unfinished things in the prototype that are just waiting for someone to polish them off.&lt;/p&gt;
&lt;h4&gt;Or, Work On An Extension&lt;/h4&gt;
&lt;p&gt;&lt;a href="http://ext.radiantcms.org"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0052/extension-registry.png" alt="Radiant CMS Extension Registry" align="right" /&gt;&lt;/a&gt; Maybe you aren&amp;#8217;t interested in working on one of the core features in Radiant, but you would like to work on a Radiant extension. If so this is great! There are over 190 Radiant extensions in the &lt;a href="http://ext.radiantcms.org"&gt;extension registry&lt;/a&gt; that add support for all kinds of things. Things ranging from &amp;#8220;version&amp;#8221; &amp;#8220;control&amp;#8221; to &amp;#8220;asset&amp;#8221; &amp;#8220;management&amp;#8221;. Most of the extensions have been written for 0.8 and below. We are just getting ready to release 0.9 and the lack of polish on some of the extensions is really starting to show. We need folks who are good at design that can help extension developers bring their extensions up to snuff.&lt;/p&gt;
&lt;p&gt;To work on an extension, you can either pull the &lt;span class="caps"&gt;HTML&lt;/span&gt; from the extension into your fork of the Radiant prototype and work on it there, or work on the extension inside of an existing Radiant project. The second option takes a bit of know how, but getting an extension developer to give you a hand with the setup process shouldn&amp;#8217;t be too difficult. I&amp;#8217;ll talk a little more about getting help at the end of this article.&lt;/p&gt;
&lt;h4&gt;Or, Make Something New&lt;/h4&gt;
&lt;p&gt;To date almost all of the work on the Radiant interface has been done by myself and a couple of the of the Radiant developers. I am very interested in hearing other designers ideas about how the interface could be improved and made more user friendly. In particular, I feel like we have a ways to go before we are competitive with products like Wordpress on the UI level. Right now the interface works pretty well for power users, but we need to do a better job reaching out to first time users. More inline help in the interface is important, but we also need to build a real help system. I&amp;#8217;m visualizing something that would open in a separate window.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ext.radiantcms.org/extensions/1-page-attachments"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0054/page-attachments.png" alt="Radiant CMS Prototype Project" align="right" /&gt;&lt;/a&gt; I&amp;#8217;m also interested in any thoughts people have on asset management. I&amp;#8217;m a big fan of the approach that &lt;a href="http://ext.radiantcms.org/extensions/1-page-attachments"&gt;page attachments&lt;/a&gt; takes, but I also see room for the way &lt;a href="http://ext.radiantcms.org/extensions/20-paperclipped"&gt;papperclipped&lt;/a&gt; has implemented the &lt;a href="http://mephistoblog.com/"&gt;Mephisto&lt;/a&gt;-style asset bucket approach. Ultimately, I want something that is a bit of a combination of the two. And I want it to work well even if you don&amp;#8217;t have support for image thumbnailing installed on your server. This means having alternate views without thumbnails. I would love for someone to take a stab at merging all of these concepts on the UI level. It needs to be slick in every way.&lt;/p&gt;
&lt;p&gt;If you are feeling adventurous, you are also welcome to work on something completely new. Redesign an aspect of the interface or even the whole product. Fresh ideas are important if Radiant is going to continue moving forward. Who knows. You might just find yourself at the center of the next major release.&lt;/p&gt;
&lt;h4&gt;Or, Work On The Marketing Side&lt;/h4&gt;
&lt;p&gt;&lt;a href="http://github.com/radiant/radiant-mockups/blob/master/radiant%20homepage%204.png"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0058/new-promo-site.png" alt="Radiant CMS Extension Registry" align="right" /&gt;&lt;/a&gt; I&amp;#8217;ve got &lt;a href="http://github.com/radiant/radiant-mockups/blob/master/radiant%20homepage%204.png"&gt;some ideas&lt;/a&gt; for updating the &lt;a href="http://radiantcms.org"&gt;Radiant site itself&lt;/a&gt; to be more competitive with with other sites. If you are interested in helping here, &lt;a href="http://wiseheartdesign.com/about/"&gt;contact me directly&lt;/a&gt;. The original design for the site is a couple of years old now and it could use an serious update.&lt;/p&gt;
&lt;h4&gt;Not Ready To Work In The Prototype?&lt;/h4&gt;
&lt;p&gt;Maybe jumping right into the &lt;span class="caps"&gt;HTML&lt;/span&gt; is not your thing. I hear ya. I often like to work out my ideas in a graphics editor like Fireworks or Photoshop before getting too far. If that is your thing, check out the &lt;a href="http://github.com/radiant/radiant-mockups/"&gt;Radiant mockups&lt;/a&gt; project on GitHub. You&amp;#8217;ll find the original source images for much of the Radiant interface in there. &lt;strong&gt;You heard me right, the original source images!&lt;/strong&gt; They are in Fireworks &lt;span class="caps"&gt;PNG&lt;/span&gt; format, which means that if you open them in Fireworks you will be able to edit them in all of their vector goodness.&lt;/p&gt;
&lt;p&gt;If you are savvy enough, fork the mockups project on GitHub and add your new mockups to the fork. GitHub is a great way to share your work and it will make it easier for people to view and use what you are working on.&lt;/p&gt;
&lt;p&gt;If working with Git and GitHub is too complicated for you, you can still download the original source images. On GitHub, browse over to the &lt;a href="http://github.com/radiant/radiant-mockups/"&gt;Radiant mockups project&lt;/a&gt;, then open the page for the graphic that you want to use, and click &amp;#8220;raw&amp;#8221; (in the gray bar underneath the filename) to download the image in its original format.&lt;/p&gt;
&lt;h4&gt;Getting Your Changes Approved&lt;/h4&gt;
&lt;p&gt;OK, so we&amp;#8217;ve covered a lot of the technical challenges on contributing to the design effort on Radiant, but I&amp;#8217;d like to address one of the most important aspects this whole process: getting your changes approved and merged into core.&lt;/p&gt;
&lt;p&gt;This is a tricky one to answer.&lt;/p&gt;
&lt;p&gt;On the one hand Radiant can desperately use the help of other designers. On the other, there is no question that Radiant has benefited from the opinionated and sometimes heavy handed oversight of one designer (namely me). I don&amp;#8217;t plan on relinquishing my role of &amp;#8220;Lead Designer&amp;#8221; on the project any time soon, but it&amp;#8217;s also becoming clear that I can&amp;#8217;t do everything that needs to be done.&lt;/p&gt;
&lt;p&gt;So here are some tips for working with me to get your changes approved:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;strong&gt;E-mail the developer list.&lt;/strong&gt; Before you get too far on a feature, send an e-mail to the &lt;a href="http://radiantcms.org/mailing-list/dev/"&gt;Radiant Developers list&lt;/a&gt; and look for feedback from either Sean Cribbs or me. (Sean is the lead developer of Radiant.)&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Blog about what you are doing.&lt;/strong&gt; Help us understand your reasons for wanting to change the Radiant interface. Outline the changes you have made or what you would like to do. And don&amp;#8217;t forget to tell us about your article on the developer mailing list.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Post screenshots.&lt;/strong&gt; I am a very visual person. Posting screenshots will give me a much better idea of what you are working on. Who knows, I may even give you a return volley of screenshots for how I would suggest that a given feature should be implemented.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Work with the existing design.&lt;/strong&gt; If your design departs from the current look and feel it will be very hard for me to sign off on what you have done, no matter how awesome the feature is. I don&amp;#8217;t want to discourage people from seeking to address problems with the current look or feel, but significant departures greatly increase the chances that your changes will not be approved.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Persevere.&lt;/strong&gt; If I don&amp;#8217;t like what you have done on the first or second pass, keep at it. Find a way to work with me. I know I&amp;#8217;m an ornery fellow, but find a way to work with me. I&amp;#8217;ll do my best to do the same on my end.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Also, don&amp;#8217;t forget that even if your changes are not merged into core, someone else within the Radiant community may like what you are doing enough to make an extension out of it. There are plenty of extensions that are extremely valuable that will never be part of the core distribution. This is part of Radiant&amp;#8217;s appeal. It is not the &lt;span class="caps"&gt;CMS&lt;/span&gt; that does everything out of the box. It is the simple &lt;span class="caps"&gt;CMS&lt;/span&gt; with a solid core.&lt;/p&gt;
&lt;h4&gt;A Word On Open Source Design&lt;/h4&gt;
&lt;p&gt;Open source projects have a reputation for being poorly designed, but I don&amp;#8217;t believe it has to be this way. Developers have been working on the problem of &amp;#8220;collaboration with anyone&amp;#8221; for a long while now and have proven that it can work. As designers I think we are behind the curve a little, but I see no reason why we can&amp;#8217;t make it work as well. All it will take is a little commitment, humility from everyone involved, and a lot of hard work.&lt;/p&gt;
&lt;p&gt;So what about you? Do you think this can work for Radiant? Are you willing to give it a try?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/RUHo7uYc3gw" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/RUHo7uYc3gw/" />
          <published>2010-02-17T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/02/17/open-source-design-help-needed//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/02/12/my-current-toolset//</id>
          <title type="html">My Current Toolset</title>
          <updated>2010-02-20T04:46:38Z</updated>
          <content type="html">&lt;p&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0048/toolset.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;I thought I would give my readers a little information on my current toolset. For the sake of the article, I&amp;#8217;d like for you to pretend that we have just started working out of the same office together and you and I are comparing notes about our current tools and processes. Since we can&amp;#8217;t actually do this in person I want to encourage you to share some of the tools that you are using in the comments below (or even better, link to your own blog post on the same topic). The tools that we each use are unique and say a lot about the kind of work that we do and what we value.&lt;/p&gt;
&lt;p&gt;So without further ado, here is my list:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Index Cards&lt;/strong&gt; &amp;#8211; I&amp;#8217;m a big fan of keeping things as simple as possible. I like to have a stack of index cards handy to jot things down on. I like both the &lt;a href="http://www.amazon.com/Oxford-Ruled-Index-Inches-31/dp/B00006IFCX/"&gt;3&amp;times;5&lt;/a&gt; and &lt;a href="http://www.amazon.com/Oxford-Ruled-Index-Inches-41/dp/B00006IFD2/"&gt;4&amp;times;6&lt;/a&gt; varieties. Lined on one side, blank on the other, and preferably college rule. I like to use index cards as story cards when planning releases, to write down ideas for new blog posts (one per card), to keep track of to-do items, and to doodle on ideas for projects. Yes, in my opinion, the index card is the single most valuable piece of writing material for the modern man. Infinitely versatile and so compact. Even better than those &lt;a href="http://www.moleskine.com/"&gt;moleskin notebooks&lt;/a&gt; that everyone carries around, but hardly anyone uses.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Paper&lt;/strong&gt; &amp;#8211; I don&amp;#8217;t often use paper other than index cards (do those qualify?), but when I do, I use plain 8&amp;frac12;&amp;times;11 printer paper. For paper prototyping I like to print out sheets of paper with a box in the center that is useful for keeping illustrations of the web app I&amp;#8217;m working on constrained. I use the margins to jot down implementation details. &lt;a href="http://wiseheartdesign.com/page_attachments/0000/0047/page.pdf"&gt;Here&amp;#8217;s the document that I use.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pencils and Sharpies&lt;/strong&gt; &amp;#8211; I am a longtime user of &lt;a href="http://www.amazon.com/BIC-Mechanical-Pencil-Medium-10-Count/dp/B00260X7F2/"&gt;#2 &lt;span class="caps"&gt;BIC&lt;/span&gt; mechanical pencils&lt;/a&gt;. They are super cheap, write extremely well, and never need sharpening. I like them better than pens because they aren&amp;#8217;t permanent (so they are better for sketching). If only the clip didn&amp;#8217;t break off so easily. (Though I will admit to a certain amount of satisfaction every time I break a clip off.) I&amp;#8217;m also a fan of the &lt;a href="http://www.amazon.com/Sharpie-Point-Permanent-Marker-Canister/dp/B001ELJOOM/"&gt;Sharpie&lt;/a&gt;. It is a great tool to leverage when you want to avoid getting too detailed in your sketches. 37signals has talked about this &lt;a href="http://37signals.com/svn/posts/466-sketching-with-a-sharpie"&gt;before&lt;/a&gt; and I agree. Sharpies are awesome.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A Whiteboard&lt;/strong&gt; &amp;#8211; I don&amp;#8217;t always have a whiteboard handy, but when I am working with a client this is an awesome way to capture ideas, map out complex flow diagrams, and discuss interface changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;My Computer&lt;/strong&gt; &amp;#8211; Of course, no description of the physical things would be complete without talking about my computer. As you may have guessed, I have a &lt;a href="http://www.apple.com/macbookpro/"&gt;MacBook Pro&lt;/a&gt;. I recently exchanged my 15&amp;#8243; for a fully loaded 17&amp;#8243;. I decided to max out the memory and the hard drive this time and I am loving it. I can finally run a graphics program and VMware without the system coming to a crawl. I also have room for all my movies, TV shows, and music. It&amp;#8217;s the perfect work/personal machine. During the day (if I&amp;#8217;m not out galavanting about), I like to plug into my &lt;a href="http://www.apple.com/displays/"&gt;22&amp;#8243; Apple display&lt;/a&gt; (it&amp;#8217;s not one of the newer ones, but it is still pretty classy). I am also currently using a &lt;a href="http://www.microsoft.com/hardware/mouseandkeyboard/productdetails.aspx?pid=043"&gt;Microsoft Natural Keyboard&lt;/a&gt; and the &lt;a href="http://store.apple.com/us/product/MB829"&gt;Apple Magic Mouse&lt;/a&gt; (which may be the first mouse Apple has ever created that is worthwhile). I also have a pair of &lt;a href="http://www.amazon.com/JBL-Duet-Speakers-2-SpeakerS-Aluminum/dp/B0007XU370/"&gt;&lt;span class="caps"&gt;JBL&lt;/span&gt; speakers&lt;/a&gt; (no subwoofer to kick), which are compact and perfect for easy listening during the day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fireworks&lt;/strong&gt; &amp;#8211; My graphics editor of choice is &lt;a href="http://www.adobe.com/products/fireworks/"&gt;Adobe Fireworks&lt;/a&gt; (formerly Macromedia Fireworks). Fireworks is quite simply the best website graphics tool on the market today (in my opinion). I know that there are people who prefer Photoshop, but I&amp;#8217;m of the opinion that most of them aren&amp;#8217;t UX people. They either do a lot of extremely high end design with lots of textures and polish, or more likely they also do print design and are using the tool that they are comfortable with. For my needs Fireworks is more than sufficient. It successfully combines vector and pixel-based editing into one program allowing you to create pixel perfect designs with far less effort than it takes in Photoshop. Oh, and did I mention that it&amp;#8217;s fast? It makes Photoshop look like a 4-ton behemoth. The one caveat is that Adobe and Macromedia have always been a little hit and miss on the releases. I&amp;#8217;m currently using CS3 as it seems to render fonts better.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Illustrator&lt;/strong&gt; &amp;#8211; I don&amp;#8217;t do a lot in &lt;a href="http://www.adobe.com/products/illustrator/"&gt;Adobe Illustrator&lt;/a&gt;, but whenever I&amp;#8217;m working on a logo or a complicated piece of vector art I like to do it in Illustrator. I&amp;#8217;m still not very efficient with it as I&amp;#8217;m mostly a Fireworks man, but Illustrator offers a fantastic array of tools for doing complex stuff with vector art. On Windows, I was an Xara man. Xara is an amazing tool. It beats Illustrator hands down in terms of usability and can create photo realistic vector art. Unfortunately, they have yet to get it going on the Mac. Somebody please help them port it to the Mac. It&amp;#8217;s simply awesome.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Photoshop&lt;/strong&gt; &amp;#8211; I rarely use &lt;a href="http://www.adobe.com/products/photoshop/"&gt;Adobe Photoshop&lt;/a&gt;, but when I do it&amp;#8217;s usually for what it is good at: photo editing. The layer-based approach is simply awesome for this. Most of the time the built-in bitmap editing tools in Fireworks are sufficient for me, but when they are not I drop back and punt. Photoshop rocks for photo editing, but please! Don&amp;#8217;t use it for anything else!!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Textmate&lt;/strong&gt; &amp;#8211; &lt;a href="http://macromates.com/"&gt;Textmate&lt;/a&gt; is my comfortable everyday editor. I like it because it provides pretty good support for whatever language I am working in. And did I mention that it is simply gorgeous? I love its project-based approach and typically launch it in a directory with the `mate` command.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vim&lt;/strong&gt; &amp;#8211; I&amp;#8217;m a &lt;a href="http://www.vim.org/"&gt;Vim&lt;/a&gt; guy on the console or server. I&amp;#8217;d probably use it instead of Textmate as my everyday editor except for the fact that I can&amp;#8217;t get away from Textmate&amp;#8217;s beautiful project drawer. Vim is great because it&amp;#8217;s installed practically everywhere. This means that whenever I &lt;span class="caps"&gt;SSH&lt;/span&gt; into a server I can edit files in the comfort of a familiar editor. I don&amp;#8217;t know a lot of Vim commands, but I know enough to get around.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tweetie&lt;/strong&gt; &amp;#8211; Yup. I love &lt;a href="http://www.atebits.com/tweetie-mac/"&gt;Tweetie&lt;/a&gt;. When it comes to Twitter, there isn&amp;#8217;t a better client on the Mac. And it is simply beautiful. The interface is unique, but very functional. I love the fact that it allows me to easily manage multiple Twitter accounts. This lets me keep &lt;a href="http://twitter.com/johnwlong"&gt;@johnwlong&lt;/a&gt;, &lt;a href="http://twitter.com/rcreative"&gt;@rcreative&lt;/a&gt;, and &lt;a href="http://twitter.com/radiantcms"&gt;@radiantcms&lt;/a&gt; in sync. Oh, and they also have a &lt;a href="http://www.atebits.com/tweetie-iphone/"&gt;similarly awesome product&lt;/a&gt; for the iPhone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gmail&lt;/strong&gt; &amp;#8211; I&amp;#8217;m currently using &lt;a href="http://gmail.com"&gt;Gmail&lt;/a&gt; as my main e-mail client. It&amp;#8217;s taken me a while to warm up to it, but without faster support for &lt;span class="caps"&gt;IMAP&lt;/span&gt; this seems to be the best way to view my mail. I use it with &lt;a href="http://toolbar.google.com/gmail-helper/notifier_mac.html"&gt;Google Notifier&lt;/a&gt; for the Mac to keep me informed about unread messages. I also use Gmail for chat these days and like the fact that I can close it all down if I need to get work done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Skype&lt;/strong&gt; &amp;#8211; &lt;a href="http://skype.com"&gt;Skype&lt;/a&gt; seems to be the best way to screenshare at the moment. It is much more stable than iChat, making it the ideal screensharing tool when I&amp;#8217;m trying to demo things for clients. The only thing it&amp;#8217;s not good for is yielding control of your screen to another user (which is extremely handy when pairing remotely). For that, I do resort to iChat, though it seems to crash every once in a while.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Serve&lt;/strong&gt; &amp;#8211; I&amp;#8217;ve built a couple of tools that help streamline my workflow, but none is more useful than &lt;a href="http://dev.wiseheartdesign.com/articles/2009/04/21/reintroducing-serve-a-rapid-prototyping-framework-for-designers/"&gt;Serve&lt;/a&gt;. Serve is a rapid prototyping framework for Rails applications. It makes it easy for me to throw a bunch of &lt;span class="caps"&gt;HAML&lt;/span&gt;, &lt;span class="caps"&gt;SASS&lt;/span&gt;, and images in a directory and render the content. Serve allows me to use concepts similar to Rails partials and layouts to dry up my &lt;span class="caps"&gt;HTML&lt;/span&gt; mockups of the application, which allows me to quickly build a prototype of any web application. Think of it as Rails without the backend &amp;#8211; just the views directory. Serve is simply awesome. I use it almost every day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shell Scripts&lt;/strong&gt; &amp;#8211; I&amp;#8217;ve written a couple of &lt;a href="http://gist.github.com/198222"&gt;custom shell scripts&lt;/a&gt; that help me fly around the command prompt. I&amp;#8217;m not sure that my scripts are generally useful to anyone outside of myself, because you would have to structure your projects exactly like I do to get the same benefit, but I highly recommend that you take the time to write a couple of commands to make it easy to do your common tasks on the command line. Shell scripting is a bit convoluted, but with a little effort you can save yourself hundreds of hours of typing over the course of your career.&lt;/p&gt;
&lt;p&gt;So there you have it. My list of tools and the reasons I use them. There are a lot of other tools I could list like &lt;a href="http://iconfactory.com/software/xscope"&gt;Xscope&lt;/a&gt;, &lt;a href="http://www.billingsapp.com/"&gt;Billings&lt;/a&gt;, or &lt;a href="http://smileonmymac.com/TextExpander/"&gt;TextExpander&lt;/a&gt;, but these are the ones I can&amp;#8217;t live without. What about you? What are the major tools that you are using on a regular basis? Are there any tools that you would recommend to improve my workflow? What about those of you who do more development than design? What tools are you using?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/Xw4dmsT3S0Y" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/Xw4dmsT3S0Y/" />
          <published>2010-02-12T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/02/12/my-current-toolset//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/02/02/how-to-create-stateful-navigation-in-radiant-cms//</id>
          <title type="html">How to Create Stateful Navigation in Radiant CMS</title>
          <updated>2010-02-20T04:56:00Z</updated>
          <content type="html">&lt;p&gt;In the past, I haven&amp;#8217;t blogged very much about &lt;a href="http://radiantcms.org/"&gt;Radiant &lt;span class="caps"&gt;CMS&lt;/span&gt;&lt;/a&gt; &amp;#8211; the content management system I created. Part of that is due to the fact that a lot of my early documentation efforts were focused on writing information that would appear on RadiantCMS.org itself, either in blog posts or on the project wiki. Part of it is due to feeling self-conscious (for whatever reason) about blogging about my own project. Another part of it, perhaps the largest part, is due to the fact that I haven&amp;#8217;t done a very good job of blogging consistently about anything.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;But no more.&lt;/em&gt; This year I am working hard to turn over a new leaf, and blogging consistently is my #1 priority. For content I&amp;#8217;m going to be pulling from a number of projects I&amp;#8217;ve worked on in the past, and Radiant will be featured prominently.&lt;/p&gt;
&lt;p&gt;For starters I&amp;#8217;d like to kick off this series with a discussion of how to create stateful navigation in Radiant &lt;span class="caps"&gt;CMS&lt;/span&gt;. When I say stateful navigation I mean navigation that indicates where you are on a web site. For instance, in the header of my web site you can see the following links:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0045/stateful-navigation.png" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;#8220;Portfolio&amp;#8221; is a lighter color and is set in bold type instead of normal type like the other two links. This indicates to the user where they are on my site. If they were viewing my weblog, &amp;#8220;Weblog&amp;#8221; would appear bold and the other two links as normal text, and so forth.&lt;/p&gt;
&lt;h4&gt;Approach #1 &amp;#8211; If and Unless&lt;/h4&gt;
&lt;p&gt;To achieve this effect, I have resorted to a couple of Radius tags. Radiant comes packaged with a powerful macro-like language called &lt;a href="http://github.com/jlong/radius"&gt;Radius&lt;/a&gt; that is used to transform snippets of &lt;span class="caps"&gt;HTML&lt;/span&gt; into a working web page. The format is relatively simple. It looks a lot like &lt;span class="caps"&gt;XML&lt;/span&gt; or &lt;span class="caps"&gt;HTML&lt;/span&gt;, except that all of the tags begin with the &lt;tt&gt;r:&lt;/tt&gt; prefix.&lt;/p&gt;
&lt;p&gt;On my site, I have three links and I&amp;#8217;m using a bit of a brute force technique to get it to work for me. This is taken straight from the main layout of my site:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;div &lt;span class="attribute"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;navigation&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;ul&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:if_url &lt;span class="attribute"&gt;matches&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;^/portfolio&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;li &lt;span class="attribute"&gt;class&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;here&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;a &lt;span class="attribute"&gt;href&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;/portfolio/&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;Portfolio&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/a&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/li&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/r:if_url&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:unless_url &lt;span class="attribute"&gt;matches&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;^/portfolio&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;li&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;a &lt;span class="attribute"&gt;href&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;/portfolio/&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;Portfolio&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/a&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/li&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/r: unless_url&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:if_url &lt;span class="attribute"&gt;matches&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;^/(weblog|articles)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;li class&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;here&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;a &lt;span class="attribute"&gt;href&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;/weblog/&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;Weblog&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/a&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/li&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/r:if_url&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:unless_url &lt;span class="attribute"&gt;matches&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;^/(weblog|articles)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;li&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;a &lt;span class="attribute"&gt;href&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;/weblog/&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;Weblog&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/a&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/li&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/r:unless_url&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:if_url &lt;span class="attribute"&gt;matches&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;^/about&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;li class&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;here&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;a &lt;span class="attribute"&gt;href&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;/about/&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;About&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/a&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/li&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/r:if_url&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:unless_url &lt;span class="attribute"&gt;matches&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;^/about&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;li&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;a &lt;span class="attribute"&gt;href&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;/about/&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;About&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/a&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/li&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/r:unless_url&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/ul&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/div&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, I&amp;#8217;m making heavy use of the &lt;tt&gt;&amp;lt;r:if_url&amp;nbsp;/&amp;gt;&lt;/tt&gt; and &lt;tt&gt;&amp;lt;r:unless_url&amp;nbsp;/&amp;gt;&lt;/tt&gt; tags. These tags both use the &lt;tt&gt;matches&lt;/tt&gt; attribute, which matches the &lt;span class="caps"&gt;URL&lt;/span&gt; against a regular expression. (There is a great introduction to regular expressions in the free version of &lt;em&gt;Programming Ruby&lt;/em&gt;, &lt;a href="http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_stdtypes.html#S4"&gt;here&lt;/a&gt;). The &lt;tt&gt;&amp;lt;r:if_url&amp;nbsp;/&amp;gt;&lt;/tt&gt; tag will only output its contents if the &lt;span class="caps"&gt;URL&lt;/span&gt; matches the given regular expression (and the reverse is true for &lt;tt&gt;&amp;lt;r:unless_url&amp;nbsp;/&amp;gt;&lt;/tt&gt;).&lt;/p&gt;
&lt;p&gt;The downside of this technique is that it is extremely verbose. For each link I have to create a set of &lt;tt&gt;&amp;lt;r:if_url /&amp;gt;&lt;/tt&gt; and &lt;tt&gt;&amp;lt;r:unless_url /&amp;gt;&lt;/tt&gt; tags that contain the state of the link when it is selected and when it is not. The advantage of this technique is that it allows me to use regular expressions to match a huge variety of URLs. This works out well, especially for the &amp;#8220;Weblog&amp;#8221; link, which should show itself as selected when the &lt;span class="caps"&gt;URL&lt;/span&gt; starts with either &amp;#8220;/weblog&amp;#8221; or &amp;#8220;/articles&amp;#8221;.&lt;/p&gt;
&lt;h4&gt;Approach #2 &amp;#8211; The Navigation Tag&lt;/h4&gt;
&lt;p&gt;If I hadn&amp;#8217;t needed to use fancy regular expressions to build my navigation correctly I could have used another set of tags that would construct the navigation more efficiently. The &lt;tt&gt;&amp;lt;r:navigation&amp;nbsp;/&amp;gt;&lt;/tt&gt; tag is designed specifically for rendering this kind of navigation:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;div &lt;span class="attribute"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;navigation&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;ul&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:navigation &lt;span class="attribute"&gt;urls&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Portfolio: /portfolio/ | Weblog: /weblog/ | About: /about/&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:here&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;li &lt;span class="attribute"&gt;class&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;here&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;a &lt;span class="attribute"&gt;href&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:url /&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:title /&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/a&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/li&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/r:here&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:selected&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;li &lt;span class="attribute"&gt;class&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;here&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;a &lt;span class="attribute"&gt;href&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:url /&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:title /&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/a&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/li&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/r:selected&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:normal&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;li&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;a &lt;span class="attribute"&gt;href&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:url /&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:title /&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/a&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/li&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/r:normal&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/r:navigation&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/ul&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;/div&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;tt&gt;&amp;lt;r:navigation /&amp;gt;&lt;/tt&gt; tag has one attribute, &lt;tt&gt;urls&lt;/tt&gt;. This attribute contains multiple key/value pairs of the title/&lt;span class="caps"&gt;URL&lt;/span&gt; of each link in the navigation. Inside of the &lt;tt&gt;&amp;lt;r:navigation /&amp;gt;&lt;/tt&gt; tags are three additional tag sets containing the &lt;span class="caps"&gt;HTML&lt;/span&gt; for the three different link states. &lt;tt&gt;here&lt;/tt&gt; is the state of a link when the &lt;span class="caps"&gt;URL&lt;/span&gt; matches exactly. &lt;tt&gt;selected&lt;/tt&gt; is the state of a link when the user is on a child page of the given &lt;span class="caps"&gt;URL&lt;/span&gt;. And &lt;tt&gt;normal&lt;/tt&gt; is the state of a link under normal circumstances.&lt;/p&gt;
&lt;h4&gt;Approach #3 &amp;#8211; Clever Use of the Page Slug&lt;/h4&gt;
&lt;p&gt;There is one final approach that is sometimes useful when dealing with stateful navigation. Ryan Heneise first talked about this approach in an article on ArtOfMission.com. Unfortunately, that article is no longer available so I&amp;#8217;ll outline the general technique here.&lt;/p&gt;
&lt;p&gt;For starters, this approach makes clever use of &lt;span class="caps"&gt;CSS&lt;/span&gt; and the page slug. The page slug is the last part of the &lt;span class="caps"&gt;URL&lt;/span&gt;. It generally follows the page title, but it is lowercase and it replaces all spaces and punctuation with dashes. So for the root level page &amp;#8220;About Us&amp;#8221; the slug is generally &amp;#8220;about-us&amp;#8221;. I say &amp;#8220;generally&amp;#8221; because the end user can customize the page slug to be whatever they want.&lt;/p&gt;
&lt;p&gt;What Ryan realized was that he could use the current page&amp;#8217;s slug to set the body class in his main layout:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;body &lt;span class="attribute"&gt;class&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;r:slug /&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;He could then use a couple of &lt;span class="caps"&gt;CSS&lt;/span&gt; rules to achieve the same effect:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&lt;span class="selector"&gt;body.portfolio li#portfolio,&lt;br /&gt;body.weblog li#weblog,&lt;br /&gt;body.about li#about&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;color&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; white&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;font-weight&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; bold&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;So there you have it: three fantastic ways to achieve stateful navigation with Radiant &lt;span class="caps"&gt;CMS&lt;/span&gt;. Hopefully I&amp;#8217;ve primed the pump a little and your head is already spinning with ways to do cool things with Radiant.&lt;/p&gt;
&lt;p&gt;What are you doing with &lt;a href="http://radiantcms.org"&gt;Radiant &lt;span class="caps"&gt;CMS&lt;/span&gt;&lt;/a&gt;?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/XG2nCvSi8tw" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/XG2nCvSi8tw/" />
          <published>2010-02-02T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/02/02/how-to-create-stateful-navigation-in-radiant-cms//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/01/22/structuring-a-sass-project//</id>
          <title type="html">How to Structure a Sass Project</title>
          <updated>2010-02-20T04:58:36Z</updated>
          <content type="html">&lt;p&gt;When you start out with Sass it is very easy to use it much like you do &lt;span class="caps"&gt;CSS&lt;/span&gt; without leveraging some of the more useful features. For myself I used it for a long time without realizing much of its true power. In this brief article I&amp;#8217;d like to show you how I structure my Sass projects and give you some practical pointers to a couple of open source projects where you can learn more.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://github.com/radiant/radiant-extension-registry/tree/master/public/stylesheets"&gt;&lt;img align="right" src="http://wiseheartdesign.com/page_attachments/0000/0043/sass-structure.png" alt="" style="margin-right: 1em; margin-bottom: 1em" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I typically store my Sass source in &lt;code&gt;stylesheets/sass&lt;/code&gt;. The Haml/Sass plugin for Rails encourages this arrangement. Sass source is stored there and compiled to the &lt;code&gt;stylesheets&lt;/code&gt; directory. You don&amp;#8217;t have to set it up this way (particularly if you are not using Rails), but this setup works pretty well for me.&lt;/p&gt;
&lt;p&gt;In the root of my &lt;code&gt;stylesheets/sass&lt;/code&gt; directory are the main Sass files that will be converted directly into &lt;span class="caps"&gt;CSS&lt;/span&gt; files. Files like &lt;code&gt;screen.sass&lt;/code&gt;, &lt;code&gt;print.sass&lt;/code&gt;, and &lt;code&gt;blog.sass&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Partials&lt;/h4&gt;
&lt;p&gt;I also have a directory for &lt;em&gt;partials&lt;/em&gt;. In my partials directory I store snippets of &lt;span class="caps"&gt;CSS&lt;/span&gt; that are incorporated into other stylesheets through the Sass &lt;code&gt;@import&lt;/code&gt; directive. The &lt;code&gt;@import&lt;/code&gt; directive works somewhat differently in Sass than it does in &lt;span class="caps"&gt;CSS&lt;/span&gt;. Instead of telling the Web browser to download another &lt;span class="caps"&gt;CSS&lt;/span&gt; file, it inserts the source code from the specified file directly into the generated &lt;span class="caps"&gt;CSS&lt;/span&gt;. Sass partials begin with an underscore (&lt;code&gt;_&lt;/code&gt;). This tells Sass that it doesn&amp;#8217;t need to generate a corresponding &lt;span class="caps"&gt;CSS&lt;/span&gt; file in the output directory, but that the code in the Sass source file is used in other Sass files. I typically have partials for each of the major sections of my &lt;span class="caps"&gt;CSS&lt;/span&gt;: header, navigation, main, footer. I also tend to have one called layout where I store layout-oriented rules. The exact names of the partials I choose depend on the project, the main idea is to break your stylesheets down into manageable chunks.&lt;/p&gt;
&lt;h4&gt;Modules&lt;/h4&gt;
&lt;p&gt;The second directory that  I have is reserved for &lt;em&gt;modules&lt;/em&gt;. My modules directory is filled with Sass partials containing &lt;a href="http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#mixins"&gt;mixins&lt;/a&gt;. I reserve modules for highly reusable Sass code and have a great variety that I typically use when getting started on a new project. Some of the modules are customized greatly for each project (like typography and forms), while some of the modules are the same on every project. I&amp;#8217;m doing a lot with CSS3 these days, so I like to have an assortment of CSS3 modules for doing things like gradients and rounded corners. I also have a modified version of a reset module that I stole from Compass which helps me start on the right foot with all browsers.&lt;/p&gt;
&lt;h4&gt;Example Projects&lt;/h4&gt;
&lt;p&gt;The image above is showing the stylesheet directory structure from the Sass for the &lt;em&gt;&lt;a href="http://github.com/radiant/radiant-extension-registry/tree/master/public/stylesheets"&gt;Radiant Extension Registry&lt;/a&gt;&lt;/em&gt;. One of my more recent projects, this is a great example of how to structure your Sass projects. You might also check out the &lt;a href="http://github.com/radiant/radiant-prototype/tree/master/stylesheets/admin/"&gt;prototype project&lt;/a&gt; for Radiant as it uses a similar structure but doesn&amp;#8217;t have as many goodies. And there is also &lt;a href="http://github.com/imathis/octopress/tree/master/stylesheets"&gt;Octopress&lt;/a&gt;, which has a slightly different philosophy but is also an excellent example of a well organized project. I&amp;#8217;d also recommend that you &lt;a href="http://github.com/chriseppstein/compass/tree/master/frameworks/compass/stylesheets/"&gt;browse&lt;/a&gt; &lt;a href="http://github.com/chriseppstein/compass/tree/master/frameworks/blueprint/stylesheets/"&gt;around&lt;/a&gt; in the Compass repository as there are a buch of great ideas there.&lt;/p&gt;
&lt;p&gt;Are there other examples of Sass projects out there that you have found to be particularly helpful? Are you finding that Sass is easy to pick up? Are there things from my experience that you would like to learn more about?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/p31z5TiuQSo" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/p31z5TiuQSo/" />
          <published>2010-01-22T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/01/22/structuring-a-sass-project//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/01/21/better-debugging-with-sass-and-line-comments//</id>
          <title type="html">Line Comments Make Debugging Sass a Breeze</title>
          <updated>2010-02-20T05:03:21Z</updated>
          <content type="html">&lt;p&gt;In response to my &lt;a href="http://wiseheartdesign.com/articles/2010/01/18/the-demise-of-css-why-sass-and-languages-like-it-will-triumph/"&gt;recent article about Sass&lt;/a&gt;, a couple of folks have asked about how easy it is to debug. The question is a good one.&lt;/p&gt;
&lt;p&gt;If Sass is generating your &lt;span class="caps"&gt;CSS&lt;/span&gt; this adds another layer of complexity that you must deal with when something goes wrong. If you use tools like &lt;a href="http://getfirebug.com/"&gt;FireBug&lt;/a&gt;, you can easily inspect an element and see the line number where a particular style was defined. But if you are using Sass, how can you tell the line number of the rule in your source file if the generated &lt;span class="caps"&gt;CSS&lt;/span&gt; file bears little resemblance to your Sass file?&lt;/p&gt;
&lt;p&gt;As it turns out, Sass actually has a solution for this. If you set the &lt;tt&gt;:line_comments&lt;/tt&gt; option to &lt;tt&gt;true&lt;/tt&gt; the generated output will contain the line number and source file where each rule was defined.&lt;/p&gt;
&lt;p&gt;The output looks something like this for each rule:&lt;/p&gt;
&lt;pre&gt;&lt;code class="code css-code"&gt;&lt;span class="comment"&gt;/* line 20, sass/_reset.sass */&lt;/span&gt;&lt;br /&gt;&lt;span class="selector"&gt;body&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;line-height&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; 1&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;color&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; black&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;background&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; white&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&amp;#8217;s my Sass initialization file that I use with Rails to ensure that this only happens in development mode. Drop this in &lt;tt&gt;config/initializers/sass.rb&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;sass&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;production|staging&lt;/span&gt;&lt;span class="punct"&gt;/.&lt;/span&gt;&lt;span class="ident"&gt;match&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="comment"&gt;# Compress CSS (a small file is preferable in production)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="constant"&gt;Sass&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Plugin&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:style&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="symbol"&gt;:compressed&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;else&lt;/span&gt;  &lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="comment"&gt;# Expand CSS&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="constant"&gt;Sass&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Plugin&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:style&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="symbol"&gt;:expanded&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="comment"&gt;# Generate CSS from SASS every time a controller is accessed&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="constant"&gt;Sass&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Plugin&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:always_update&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="comment"&gt;# Insert comments in the CSS about the line numbers of the Sass source&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="constant"&gt;Sass&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Plugin&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:line_comments&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note that the &lt;em&gt;&lt;a href="http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html"&gt;Sass Reference&lt;/a&gt;&lt;/em&gt; currently claims that the key to enable this behavior is &lt;tt&gt;:line_numbers&lt;/tt&gt;, but this is wrong. The correct key name is &lt;tt&gt;:line_comments&lt;/tt&gt;. I suspect that they are updating the docs as we speak.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/AA1ln49qJSg" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/AA1ln49qJSg/" />
          <published>2010-01-21T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/01/21/better-debugging-with-sass-and-line-comments//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/01/18/the-demise-of-css-why-sass-and-languages-like-it-will-triumph//</id>
          <title type="html">The Demise of Plain CSS: Why Sass and Languages Like It Will Triumph</title>
          <updated>2010-02-20T05:03:39Z</updated>
          <content type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;q&gt;It is my opinion that these [tools like Sass] are only really of benefit to people who haven&amp;#8217;t yet mastered writing CSS properly from the outset&amp;#8230;&lt;/q&gt;&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;Harry Roberts (&lt;a href="http://csswizardry.com/quick-tips/#tip-27"&gt;CSSwizardry.com&lt;/a&gt;)&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;&lt;h4&gt;Huh?&lt;/h4&gt;
&lt;p&gt;&lt;a href="http://sass-lang.com"&gt;&lt;img align="right" src="http://wiseheartdesign.com/page_attachments/0000/0041/sass.png" alt="Sass - Syntactically Awesome Stylesheets" title="" width="257" height="272" /&gt;&lt;/a&gt; &lt;a href="http://sass-lang.com/"&gt;Sass&lt;/a&gt; only really benefits people who haven&amp;#8217;t mastered writing &lt;span class="caps"&gt;CSS&lt;/span&gt; properly? Excuse me? I am a very experienced &lt;span class="caps"&gt;CSS&lt;/span&gt; developer and I find Sass quite valuable, having written &lt;span class="caps"&gt;CSS&lt;/span&gt; for a living for many years now. While I won&amp;#8217;t claim the level of mastery that an artist like Michelangelo achieved in painting, I can say that I wasn&amp;#8217;t born yesterday either. I write all my &lt;span class="caps"&gt;CSS&lt;/span&gt; and &lt;span class="caps"&gt;HTML&lt;/span&gt; by hand. I haven&amp;#8217;t used tools like Dreamweaver in nearly a decade.&lt;/p&gt;
&lt;p&gt;I can only assume that Mr. Roberts has not done enough Sass to see the utility of the language. Perhaps he&amp;#8217;s had to deal with someone else&amp;#8217;s Sass or only muddled around with it for a short period of time. At first glance Sass may seem like too much software, but in the hands of a competent designer it is truly wonderful. Having written Sass professionally for almost two years now I can say with confidence that Mr. Roberts is clearly missing something.&lt;/p&gt;
&lt;h4&gt;Sass &amp;#8211; A Programming Language for Designers&lt;/h4&gt;
&lt;p&gt;Sass is essentially a programming language for designers. It is extremely limited when compared with other languages, but it does a magnificent job of translating the core concepts of a programming language in a way that makes sense for styling a document.&lt;/p&gt;
&lt;p&gt;Right now folks that use Sass primarily use it as a Rails plugin, but the Ruby gem also makes it possible to use it from the command line. This makes it easy to use Sass with any language (&lt;span class="caps"&gt;PHP&lt;/span&gt;, Python, even plain-jane &lt;span class="caps"&gt;HTML&lt;/span&gt;).&lt;/p&gt;
&lt;p&gt;To use, you need to install the Haml gem. On a Mac you can do this from the command line like this:&lt;/p&gt;
&lt;pre class="code bash-code"&gt;&lt;code&gt;sudo gem install haml&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will the give you access to the &lt;tt&gt;sass&lt;/tt&gt; command, which you can use to generate &lt;span class="caps"&gt;CSS&lt;/span&gt; from Sass source files.&lt;/p&gt;
&lt;h4&gt;Nesting&lt;/h4&gt;
&lt;p&gt;So let&amp;#8217;s talk about what I love about Sass.&lt;/p&gt;
&lt;p&gt;At first blush, Sass looks like a better &lt;span class="caps"&gt;CSS&lt;/span&gt;. Instead of requiring you to repetitively list selectors, Sass allows you to nest selectors and rules:&lt;/p&gt;
&lt;pre class="code sass-code"&gt;&lt;code&gt;&lt;span class="selector"&gt;form&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="selector"&gt;p label&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;display&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; block&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;font-weight&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; bold&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="selector"&gt;input.textbox&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;background&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; white&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;color&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; #666&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="selector"&gt;button&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;color&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; white&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;background&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; red&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;padding&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; 10px 20px&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The example above would generate:&lt;/p&gt;
&lt;pre class="code css-code"&gt;&lt;code&gt;&lt;span class="selector"&gt;form p label&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;display&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; block&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;font-weight&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; bold&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="selector"&gt;form input.textbox&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;background&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; white&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;color&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; #666&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="selector"&gt;form button&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;color&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; white&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;background&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; red&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;padding&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; 10px 20px&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note the absence of brackets and semi-colons in the input. If this seems strange or ugly to you, consider how many times a misplaced bracket or semicolon has caused a rule to render incorrectly. In practice, this bracket-less form of &lt;span class="caps"&gt;CSS&lt;/span&gt; keeps code clean and makes it much easier to write. Believe me. It may look strange at first, but it leads to cleaner and less error-prone code. Of course, the code will be a lot easier to read if you use an editor with good syntax highlighting. (I recommend &lt;a href="http://macromates.com/"&gt;Textmate&lt;/a&gt; with the &lt;a href="http://github.com/charlesr/ruby-sass-tmbundle"&gt;Sass bundle&lt;/a&gt; installed.)&lt;/p&gt;
&lt;p&gt;But have no fear, if you prefer brackets, a future version of Sass will allow for a bracketed syntax as well (check out the &lt;a href="http://github.com/nex3/haml/tree/scss"&gt;scss branch&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The ability to nest rules is extremely powerful. Especially when you use it to combine selectors:&lt;/p&gt;
&lt;pre class="code sass-code"&gt;&lt;code&gt;&lt;span class="selector"&gt;#content&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="selector"&gt;#sidebar&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="selector"&gt;p&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;margin&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; 1em 0&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;This would generate:&lt;/p&gt;
&lt;pre class="code css-code"&gt;&lt;code&gt;&lt;span class="selector"&gt;#content p&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="selector"&gt;#sidebar p&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;margin&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; 1em 0&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;The amount of typing that this can save is marvelous. Of course, all of this added power comes with a price. If you aren&amp;#8217;t careful about your use of nesting and the comma operator, you can generate a huge &lt;span class="caps"&gt;CSS&lt;/span&gt; file.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;d recommend that you avoid nesting your rules more than three levels deep and that you use the comma operator sparingly. This will minimize the number of lines in the output.&lt;/p&gt;
&lt;p&gt;One day if Sass is supported by the browser this won&amp;#8217;t be an issue, but as long as Sass is converted to &lt;span class="caps"&gt;CSS&lt;/span&gt; you will need to be conscientious about the output.&lt;/p&gt;
&lt;h4&gt;Variables&lt;/h4&gt;
&lt;p&gt;Another powerful feature that Sass borrows from programming languages is the concept of variables. Sass variables always begin with an exclamation point. Variable assignment looks like this:&lt;/p&gt;
&lt;pre class="code sass-code"&gt;&lt;code&gt;&lt;span class="variable"&gt;!text_color&lt;/span&gt; &lt;span class="operator"&gt;=&lt;/span&gt; #666&lt;br /&gt;&lt;span class="variable"&gt;!background&lt;/span&gt; &lt;span class="operator"&gt;=&lt;/span&gt; #f5f5f5&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can then use variables in your rules like this:&lt;/p&gt;
&lt;pre class="code sass-code"&gt;&lt;code&gt;&lt;span class="selector"&gt;table&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;color&lt;/span&gt;&lt;span class="operator"&gt;=&lt;/span&gt; &lt;span class="variable"&gt;!text_color&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="selector"&gt;tr.even td&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;background&lt;/span&gt;&lt;span class="operator"&gt;=&lt;/span&gt; &lt;span class="variable"&gt;!background&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note the use of the &lt;tt&gt;=&lt;/tt&gt; operator on the &lt;tt&gt;color&lt;/tt&gt; and &lt;tt&gt;background&lt;/tt&gt; rules. This is necessary so that Sass knows that you are using a calculated value for a rule (in this case, a variable).&lt;/p&gt;
&lt;p&gt;The above would generate the following &lt;span class="caps"&gt;CSS&lt;/span&gt;:&lt;/p&gt;
&lt;pre class="code css-code"&gt;&lt;code&gt;&lt;span class="selector"&gt;table&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;color&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; #666&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="selector"&gt;table tr.even td&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;background&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; #f5f5f5&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Sass even allows you to do math on variables. Need a darker gray for odd rows? No problem:&lt;/p&gt;
&lt;pre class="code sass-code"&gt;&lt;code&gt;&lt;span class="selector"&gt;table tr.odd td&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;background&lt;/span&gt;&lt;span class="operator"&gt;=&lt;/span&gt; &lt;span class="variable"&gt;!background&lt;/span&gt; &lt;span class="operator"&gt;-&lt;/span&gt; #333&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Output:&lt;/p&gt;
&lt;pre class="code css-code"&gt;&lt;code&gt;&lt;span class="selector"&gt;table tr.odd td&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;background&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; #c2c2c2&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Variables can store font names, numbers, colors, you name it. If you can write it in &lt;span class="caps"&gt;CSS&lt;/span&gt; you can store it in a variable.&lt;/p&gt;
&lt;h4&gt;Mixins&lt;/h4&gt;
&lt;p&gt;This brings me to my favorite thing about Sass: mixins. Sass mixins are the stylesheet equivalent of functions. They allow you define a series of rules that can be mixed in to another ruleset with ease.&lt;/p&gt;
&lt;p&gt;Here is an example of a simple clear fix mixin:&lt;/p&gt;
&lt;pre class="code sass-code"&gt;&lt;code&gt;&lt;span class="mixin"&gt;=clearfix&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;overflow&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; hidden&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;display&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; inline-block&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This mixin can then be applied to a ruleset like this:&lt;/p&gt;
&lt;pre class="code sass-code"&gt;&lt;code&gt;&lt;span class="selector"&gt;#content&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="mixin"&gt;+clearfix&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Which would generate:&lt;/p&gt;
&lt;pre class="code css-code"&gt;&lt;code&gt;&lt;span class="selector"&gt;#content&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;overflow&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; hidden&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;display&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; inline-block&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Mixins can also accept arguments. Here is one of my favorite CSS3 mixins:&lt;/p&gt;
&lt;pre class="code sass-code"&gt;&lt;code&gt;&lt;span class="mixin"&gt;=round-corners&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="variable"&gt;!amount&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;border-radius&lt;/span&gt;&lt;span class="operator"&gt;=&lt;/span&gt; &lt;span class="variable"&gt;!amount&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;-moz-border-radius&lt;/span&gt;&lt;span class="operator"&gt;=&lt;/span&gt; &lt;span class="variable"&gt;!amount&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;-webkit-border-radius&lt;/span&gt;&lt;span class="operator"&gt;=&lt;/span&gt; &lt;span class="variable"&gt;!amount&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This would allow you to write:&lt;/p&gt;
&lt;pre class="code sass-code"&gt;&lt;code&gt;&lt;span class="selector"&gt;.box&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="mixin"&gt;+round-corners&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;5px&lt;span class="punct"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Which would output:&lt;/p&gt;
&lt;pre class="code sass-code"&gt;&lt;code&gt;&lt;span class="selector"&gt;.box&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;border-radius&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; 5px&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;-moz-border-radius&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; 5px&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;-webkit-border-radius&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; 5px&lt;span class="punct"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But mixins aren&amp;#8217;t just about limiting the amount of typing that you have to do to create a certain effect. I have mixins for default form styles, base typography, resetting a stylesheet, etc&amp;#8230; Mixins give you the ability to build a reusable library of styles that you can incorporate into your projects as needed.&lt;/p&gt;
&lt;p&gt;It is important to note that mixin definitions do not impact the &lt;span class="caps"&gt;CSS&lt;/span&gt; output unless they are used in a ruleset. This means you can have potentially hundreds of mixins defined and only use a couple of them on a given project. For the first time it is now possible to build a viable &lt;span class="caps"&gt;CSS&lt;/span&gt; framework. (&lt;a href="http://wiki.github.com/chriseppstein/compass/"&gt;Compass&lt;/a&gt; is a powerful example of this.)&lt;/p&gt;
&lt;h4&gt;Other Features&lt;/h4&gt;
&lt;p&gt;There are a number of other features that Sass offers that make it a formidable tool in the designer&amp;#8217;s arsenal, but these are features that I love. If you want familiarize yourself with all of Sass&amp;#8217;s loveliness, I recommend reading the &lt;a href="http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html"&gt;&lt;em&gt;Sass Reference&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;A Little Programing History&lt;/h4&gt;
&lt;p&gt;Now, it is my opinion that one reason designers have been slow to embrace languages like Sass is that these languages appeal to people that think more like programmers than designers. Programmers have almost made code simplicity an art form, while designers are known for spending vast amounts of time doing very tedious and repetitive work to get the effect that they want. Thankfully, this is not always the case with web developers, but in this case we are still a bit behind the curve.&lt;/p&gt;
&lt;p&gt;Programmers haven&amp;#8217;t always been this way. There was a time when programmers stuck to assembler like newborn babes cling to their mommies. They objected to the output of compilers and preferred writing assembler by hand. (Sound familiar?) They could write better assembler themselves, they said. They didn&amp;#8217;t need the productivity boost that higher level languages offered. They were just fine, thank you.&lt;/p&gt;
&lt;p&gt;And then something marvelous happened. Compilers got to the point that they were able (as a general rule) to produce more efficient assembler than most coders could by hand. With compiled languages, people found that they were able to tackle more complicated programming work because they could think less about the machine and more about the problem they were trying to tackle.&lt;/p&gt;
&lt;p&gt;Surprisingly, it was assembler that got the boot as higher-level languages began to dominate.&lt;/p&gt;
&lt;p&gt;And this trend in programming has continued. Interpreted languages like Ruby, Python, Perl, and yes, even &lt;span class="caps"&gt;PHP&lt;/span&gt;, are now replacing compiled languages. I am not saying that the need for compiled languages will be completely eliminated by interpreted languages, but it is clear that as computers have gotten faster the need for compiled code (for many applications) is diminishing. (Yes I am aware Ruby, Python, Perl, and &lt;span class="caps"&gt;PHP&lt;/span&gt; can now be compiled, but they will always retain their dynamic, uncompiled heritage.)&lt;/p&gt;
&lt;p&gt;Programmers are used to this kind of progress. Every couple of years the dominant programming language is replaced by another. Code is getting leaner, meaner, and easier to understand.&lt;/p&gt;
&lt;h4&gt;The Moral of the Story&lt;/h4&gt;
&lt;p&gt;Does anyone else spot the trend here? Just like higher-level programming languages compile to assembler, so Sass compiles to &lt;span class="caps"&gt;CSS&lt;/span&gt;. And just as higher-level programming languages eventually replaced the regular usage of assembler, so Sass (or a language like it) will eventually replace &lt;span class="caps"&gt;CSS&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Now, don&amp;#8217;t get me wrong. I am sure &lt;span class="caps"&gt;CSS&lt;/span&gt; has many more years ahead of it, but Sass and languages like it are &lt;em&gt;the future&lt;/em&gt;. Yes, you can complain about the syntax. You can complain about the generated code. But ultimately, the productivity and simplicity that languages like Sass offer will win over the masses. Of that you can be sure.&lt;/p&gt;
&lt;p&gt;One day, &lt;a href="http://sass-lang.com/"&gt;Sass&lt;/a&gt; (or &lt;a href="http://lesscss.org/"&gt;a language&lt;/a&gt; &lt;a href="http://xcss.antpaw.org/"&gt;like it&lt;/a&gt;) will be more common than &lt;span class="caps"&gt;CSS&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update!&lt;/strong&gt; Based on feedback I&amp;#8217;ve tweaked the title of this post a little. The original title began, &lt;em&gt;The Demise of &lt;span class="caps"&gt;CSS&lt;/span&gt;: Why Sass&amp;#8230;&lt;/em&gt; Apparently, some people thought I was saying that Sass would replace &lt;span class="caps"&gt;CSS&lt;/span&gt;. While that may happen, it is probably more likely that features of Sass will be incorporated into &lt;span class="caps"&gt;CSS&lt;/span&gt;. Either way &lt;span class="caps"&gt;CSS&lt;/span&gt; will certainly remain in one form or another. Sass doesn&amp;#8217;t replace &lt;span class="caps"&gt;CSS&lt;/span&gt;. It adds a cleaner syntax and additional functionality.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/cD8OSw4UvPg" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/cD8OSw4UvPg/" />
          <published>2010-01-18T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/01/18/the-demise-of-css-why-sass-and-languages-like-it-will-triumph//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/01/15/out-with-the-old-on-with-the-new//</id>
          <title type="html">Out With the Old, On With the New</title>
          <updated>2010-06-12T18:48:51Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://wiseheartdesign.com"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0037/old-wiseheartdesign-com.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Today, I&amp;#8217;m officially retiring the old design above in favor of a new design. For the benefit of my &lt;span class="caps"&gt;RSS&lt;/span&gt; readers, here&amp;#8217;s a screenshot of the new design:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://wiseheartdesign.com"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0039/new-wiseheartdesign-com.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The new design uses a number of CSS3 techniques, including gradients, drop shadows, rounded corners, and rotation. In order to get the best results, you will need to use a Webkit-based browser (Safari or Google Chrome). The site degrades gracefully though, so you shouldn&amp;#8217;t have any problem reading the site if your browser doesn&amp;#8217;t support theses features of CSS3. You just won&amp;#8217;t be able to view the site in all of its glory.&lt;/p&gt;
&lt;p&gt;I am very pleased with how the whole site has turned out. I have spent a significant amount of time tuning the message of the different pages. I&amp;#8217;m quite fond of my &lt;a href="http://wiseheartdesign.com/about/"&gt;about me&lt;/a&gt; page, and the new &lt;a href="http://wiseheartdesign.com/hire/"&gt;hire me&lt;/a&gt; page is a worthy addition. Cream turns out to be a wonderful background color. It adds extra pop to each of my images.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/Qw_uQO13lX8" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/Qw_uQO13lX8/" />
          <published>2010-01-15T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/01/15/out-with-the-old-on-with-the-new//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2010/01/08/radiant-extension-registry-updated//</id>
          <title type="html">Radiant Extension Registry Updated!</title>
          <updated>2010-02-20T05:15:14Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://ext.radiantcms.org"&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0027/radiant-extension-registry.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My holiday project for the last couple of weeks was to rework the &lt;a href="http://ext.radiantcms.org"&gt;Radiant Extension Registry&lt;/a&gt;. Sean Cribbs did a wonderful job a couple of years ago banging out the initial code, but we never had the opportunity to polish it off really well.&lt;/p&gt;
&lt;p&gt;The extension registry was originally a huge step forward for us. Before Sean&amp;#8217;s work we had a wiki page and that was it. But as more and more extensions were added to the registry it was becoming increasingly clear that we needed to rework it a little. The extension listing wasn&amp;#8217;t alphabetical or paginated. It was just one long list of extensions listed in the order that they happened to have been added to the registry. If you wanted to find something, Ctrl+F was your only friend.&lt;/p&gt;
&lt;p&gt;The dire need of the extension registry became especially apparent to me when I sat down with &lt;a href="http://www.ultrasaurus.com/"&gt;Sarah Allen&lt;/a&gt; and a couple of her friends in San Francisco in November. Sarah had contacted me about Radiant a couple of weeks before asking about the best way that she and a couple of like-minded developers could contribute to the Radiant community. When I mentioned that I was going to be out in San Francisco for Ruby Conf we decided to meet to talk about things in person.&lt;/p&gt;
&lt;p&gt;As we talked I kept mentioning this extension or that extension. Some of the extensions they had heard of, but some of the extensions they didn&amp;#8217;t even know existed. As we talked further I discovered that they did not even know that the Radiant Extension Registry existed. To my great shame I realized that a link to it had never been added to the navigation of the Radiant web site! A huge oversight on my part. What this meant was that Sarah and other newcomers to the Radiant community had assumed that the only way to find extensions was to search for them on GitHub or Google!&lt;/p&gt;
&lt;p&gt;We were able to remedy the navigation problem pretty quickly, but the apparent flaws of the existing extension registry were beginning to weigh on me.&lt;/p&gt;
&lt;p&gt;I had the good fortune this year of being able to be at home with my parents in Pennsylvania for a couple of weeks over Christmas. The holidays are always an important family time for us. I have two brothers and a sister. Three of us are still unmarried, so we typically try and spend as much time together during Christmas as we can. I decided to choose the extension registry as my holiday project &amp;#8211; between all of the games and activities, it would provide something to pour my mind into.&lt;/p&gt;
&lt;p&gt;After a day or two I had a couple mockups done. Soliciting some help from the Radiant community I continued the project shortly after Christmas, and we made great progress. &lt;a href="http://www.joeloliveira.com/"&gt;Joel Oliveira&lt;/a&gt; helped me turn my mockups into &lt;span class="caps"&gt;HTML&lt;/span&gt; and got paperclip going so that extension authors could upload screenshots. I spent some time reworking the extension listing and authors listing, adding pagination and a couple of additional fields. I also made a simple search page and reworked the home page.&lt;/p&gt;
&lt;p&gt;One of the features that we added that I&amp;#8217;m particularly excited about is the &amp;#8220;Available for Hire&amp;#8221; checkbox. When selected, a big &amp;#8220;Available for Hire&amp;#8221; badge will be displayed on your profile and next to your name in the authors listing, &lt;a href="http://ext.radiantcms.org/authors/9"&gt;like this&lt;/a&gt;. I&amp;#8217;m hoping that this concept will help turn the author&amp;#8217;s listing into a bit of a professional directory for people who do Radiant projects. Hopefully if you need work on custom Radiant extensions for your web site will you will be able to find the right folks here.&lt;/p&gt;
&lt;p&gt;Believe it or not, one of the highlights of the project was reworking the &amp;#8220;New Extension&amp;#8221; screen. Form design is one of the hardest aspects of modern web application design. Your forms need to communicate clearly to the user what needs to be done. It is a great challenge to put the right elements on the form and to organize it in a way that makes sense to the user. It easy to be too brief or, on the other hand, to be too wordy. Striking the right balance so that what you have written will be read and clearly understood is tricky. I think I came pretty close to striking that balance, but judge for yourself. You can see the old form &lt;a href="http://wiseheartdesign.com/page_attachments/0000/0029/add-extension-old.png"&gt;here&lt;/a&gt; and the updated form &lt;a href="http://wiseheartdesign.com/page_attachments/0000/0031/add-extension-new.png"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ve got a number of things that we would like to see added to the extension registry in the near future. If you are interested in helping out, fork &lt;a href="http://github.com/radiant/radiant-extension-registry"&gt;the project on GitHub&lt;/a&gt;, write some code and tests, and submit a pull request. (You can also submit feature requests or bug reports on the &lt;a href="http://github.com/radiant/radiant-extension-registry/issues"&gt;issue tracker&lt;/a&gt;.) I would love to see someone take on the challenge of adding reviews and ratings to the system. I&amp;#8217;m also playing around with the idea of making extension pages more like wiki pages with versioning and multi-author editing.&lt;/p&gt;
&lt;p&gt;You can visit the new extension registry &lt;a href="http://ext.radiantcms.org/"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/umXXurCzJGE" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/umXXurCzJGE/" />
          <published>2010-01-08T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2010/01/08/radiant-extension-registry-updated//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2009/12/19/dateinputjs-the-fantastic-date-control//</id>
          <title type="html">DateInputJS: The Fantastic Date Control</title>
          <updated>2010-02-20T05:16:25Z</updated>
          <content type="html">&lt;p&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0023/dateinput.png" title="DateInputJS in action" alt="DateInputJS in action" /&gt;&lt;/p&gt;
&lt;p&gt;One of the nice things I put together while I was working on&lt;br /&gt;
&lt;a href="http://memberhub.com"&gt;MemberHub.com&lt;/a&gt; was a &lt;a href="http://www.danwebb.net/lowpro"&gt;LowPro&lt;/a&gt;&lt;br /&gt;
and Prototype-based date input control. Today, Five Points Solutions (aka&lt;br /&gt;
MemberHub) has released it as open source:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://github.com/fivepointssolutions/dateinputjs"&gt;http://github.com/fivepointssolutions/dateinputjs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s fairly easy to use. Just wire it on to text field that you would like to&lt;br /&gt;
turn into a date input control and the DateInputBehavior does the rest. A&lt;br /&gt;
simple line like this:&lt;/p&gt;
&lt;pre class="code javascript-code"&gt;&lt;code&gt;Event.addBehavior({'input.date': DateInputBehavior()});&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;#8230;will &lt;a href="http://en.wikipedia.org/wiki/Unobtrusive_JavaScript"&gt;unobtrusively&lt;/a&gt;&lt;br /&gt;
wire it onto all input controls with a class of &amp;#8220;date&amp;#8221;. It&amp;#8217;s pretty slick. I&amp;#8217;m&lt;br /&gt;
sure you will like it.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.danwebb.net"&gt;Dan Webb&lt;/a&gt; (of LowPro fame) actually wrote a good portion of the code. We&lt;br /&gt;
discovered&lt;br /&gt;
&lt;a href="http://github.com/danwrong/low-pro/blob/master/behaviours/date_selector.js"&gt;date_selector.js&lt;/a&gt;&lt;br /&gt;
in the LowPro repository, found that it was about half of what we wanted, and&lt;br /&gt;
were able to modify it to suit our needs. Dan&amp;#8217;s original version didn&amp;#8217;t allow&lt;br /&gt;
the calendar portion to drop down or provide easy access for jumping forward&lt;br /&gt;
to another year or month. We added these features, styled it up rather nicely,&lt;br /&gt;
and have packaged the whole thing up in a nice little project on GitHub.&lt;/p&gt;
&lt;p&gt;I, for one, am very grateful that Five Points has released their version as open&lt;br /&gt;
source. I have plans to see that it gets integrated into a &lt;a href="http://radiantcms.org"&gt;little&lt;br /&gt;
&lt;span class="caps"&gt;CMS&lt;/span&gt;&lt;/a&gt; that I&amp;#8217;m working on.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/pVXw1z_oI6c" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/pVXw1z_oI6c/" />
          <published>2009-12-19T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2009/12/19/dateinputjs-the-fantastic-date-control//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2009/12/16/statusjs-work-well-with-messages//</id>
          <title type="html">StatusJS: Work Well With Messages</title>
          <updated>2010-02-16T01:10:56Z</updated>
          <content type="html">&lt;p&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0011/statusjs.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;I talked briefly about my javascript library &lt;a href="http://github.com/jlong/statusjs"&gt;StatusJS&lt;/a&gt; in the article &lt;em&gt;&lt;a href="http://wiseheartdesign.com/articles/2009/10/14/tech-notes-radiant-0-9-0-rc1/"&gt;Tech Notes: Radiant 0.9.0 RC1&lt;/a&gt;&lt;/em&gt; but thought that it would be good to take the time to introduce it in more detail as it is such a useful library.&lt;/p&gt;
&lt;p&gt;We live in a time where Rails-style flash messages have become so common and annoying in web applications that they litter the webscape like confetti in the annual &lt;a href="http://en.wikipedia.org/wiki/Macy&amp;#39;s_Thanksgiving_Day_Parade"&gt;Thanksgiving day parade&lt;/a&gt;. Enough already! I know I just deleted that object! I know I just created a message!&lt;/p&gt;
&lt;p&gt;Now a couple of folks have come up with creative ways to automatically hide flash messages after a certain period of time or allow the user to manually close the message, but both solutions have the annoying effect of causing the content underneath to &amp;#8220;slide up&amp;#8221; once the message disappears. This can be jarring for users that are working with content below.&lt;/p&gt;
&lt;p&gt;Perhaps we need to rethink this whole concept. Maybe it is less important to tell the user &lt;em&gt;what they have just done&lt;/em&gt; and more important to tell them &lt;em&gt;about the work that is being done&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is where StatusJS comes in. StatusJS provides a robust solution for displaying progress messages to users &lt;em&gt;while the work is being done&lt;/em&gt;. So instead of displaying &amp;#8220;Changes saved.&amp;#8221; in a flash message after the form is submitted, you display &amp;#8220;Saving changes&amp;#8230;&amp;#8221; &lt;em&gt;while&lt;/em&gt; the form is submitting.&lt;/p&gt;
&lt;p&gt;A bit of a paradigm shift mind you but something that Web applications should have borrowed from desktop applications a long time ago.&lt;/p&gt;
&lt;p&gt;So how does it work?&lt;/p&gt;
&lt;p&gt;StatusJS defines a couple of global functions that make it easy to control the status overlay, as the following code sample demonstrates:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;showStatus("Initializing...");
setStatus("Loading graphics...");
setStatus("Finished!");
hideStatus();&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;tt&gt;showStatus()&lt;/tt&gt; function displays and centers a new status overlay, &lt;tt&gt;setStatus()&lt;/tt&gt; changes the status message and re-centers the overlay, and &lt;tt&gt;hideStatus()&lt;/tt&gt; hides the status overlay completely.&lt;/p&gt;
&lt;p&gt;StatusJS also includes a &lt;a href="http://www.danwebb.net/lowpro"&gt;LowPro behavior&lt;/a&gt; for forms that makes it easy to add &lt;tt&gt;onsubmit&lt;/tt&gt; status messages when a user clicks a submit button.&lt;/p&gt;
&lt;p&gt;To automatically connect the behavior with your forms, add the following line to your &lt;tt&gt;application.js&lt;/tt&gt; file (assuming you are doing Rails development):&lt;/p&gt;
Event.addBehavior({&amp;#8217;form&amp;#8217;: Status.FormBehavior()});
&lt;p&gt;This allows you to add a custom attribute to each of your forms that contains the &lt;tt&gt;onsubmit&lt;/tt&gt; status message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;form action="/controller/action" onsubmit_status="Saving Changes..."&amp;gt;
  ... contents of form ...
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The form above would display a &amp;#8220;Saving Changes&amp;#8230;&amp;#8221; progress message after the user clicked the submit button.&lt;/p&gt;
&lt;p&gt;There are a couple of additional configuration variables that are worth noting. Normally you should set these variables in your &lt;tt&gt;application.js&lt;/tt&gt; file (assuming you are doing Rails development). It is essential that &lt;tt&gt;application.js&lt;/tt&gt; be loaded after &lt;tt&gt;status.js&lt;/tt&gt; so that the variables are not overridden by the defaults. Here is how it works:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// The size of the corner images. A value of 12 means square
// 12x12 pixel corners.
Status.CornerThickness = 12;

// The path, width, and height of the spinner image
Status.SpinnerImage       = "/images/status_spinner.gif";
Status.SpinnerImageWidth  = 32;
Status.SpinnerImageHeight = 33;

// The background and corner image paths
Status.BackgroundImage  = "/images/status_background.png";
Status.TopLeftImage     = "/images/status_top_left.png";
Status.TopRightImage    = "/images/status_top_right.png";
Status.BottomLeftImage  = "/images/status_bottom_left.png";
Status.BottomRightImage = "/images/status_bottom_right.png";

// Dim the background when a status message is displayed. Also
// prevents stray mouse clicks from having any effect.
Status.Modal = true;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At the moment, StatusJS requires &lt;tt&gt;prototype.js&lt;/tt&gt;, &lt;tt&gt;effect.js&lt;/tt&gt;, and &lt;tt&gt;lowpro.js&lt;/tt&gt; (all included in the GitHub project), but Sean Cribbs is working on a JQuery port. It will be added to the main project once it is ready for general use.&lt;/p&gt;
&lt;p&gt;You can download StatusJS from GitHub &lt;a href="http://github.com/jlong/statusjs"&gt;here&lt;/a&gt;. The project includes a small demo in the test directory that requires &lt;a href="http://github.com/jlong/serve"&gt;Serve&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/zWN8jBK2Tq4" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/zWN8jBK2Tq4/" />
          <published>2009-12-16T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2009/12/16/statusjs-work-well-with-messages//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2009/12/04/if-email-had-a-baby-notification-messages//</id>
          <title type="html">If E-mail Had a Baby: Notification Messages</title>
          <updated>2010-02-20T05:22:20Z</updated>
          <content type="html">&lt;p&gt;I&amp;#8217;ve been noticing recently that a lot of my e-mail of late is notification&lt;br /&gt;
related. I get a lot of e-mail from applications like Twitter and Facebook&lt;br /&gt;
that falls into this category. &amp;#8220;Someone added you as their friend&amp;#8221;, &amp;#8220;X is now&lt;br /&gt;
following you&amp;#8221;, &amp;#8220;There is a new message in your Facebook inbox&amp;#8221;, &amp;#8220;A photo was&lt;br /&gt;
uploaded with you in it&amp;#8221;, etc&amp;#8230; These messages can normally be expressed in a&lt;br /&gt;
single line.&lt;/p&gt;
&lt;p&gt;I often sort messages from different web services into their own folders.&lt;br /&gt;
Here&amp;#8217;s an example of how my Twitter &amp;#8220;inbox&amp;#8221; looked earlier today:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0009/twitter-inbox.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;As you can see, each of these notification messages can be displayed on a&lt;br /&gt;
single line. In fact, an entire summary of each e-mail message is expressed in&lt;br /&gt;
the subject line.&lt;/p&gt;
&lt;h4&gt;The Big Idea&lt;/h4&gt;
&lt;p&gt;So here is my big idea: What if a notification e-mail message like this was&lt;br /&gt;
formatted so that it would allow e-mail clients to handle them as a special&lt;br /&gt;
case?&lt;/p&gt;
&lt;p&gt;This would allow an e-mail client to have a special pane that would show&lt;br /&gt;
recent notifications. You could also build rules that would do certain things&lt;br /&gt;
when a site sent you a notification. Like download the photo you were last&lt;br /&gt;
seen in to a special folder or display a small notification window (like a&lt;br /&gt;
Growl notification) or forward the notification to you as an &lt;span class="caps"&gt;SMS&lt;/span&gt; message on&lt;br /&gt;
your cell phone.&lt;/p&gt;
&lt;p&gt;If the body of the e-mail contained a special part tailored for display, you&lt;br /&gt;
could even get a feed view that would look much like Facebook&amp;#8217;s news feed&lt;br /&gt;
or perhaps your Twitter stream.&lt;/p&gt;
&lt;p&gt;Probably the biggest win here in treating notification messages differently is&lt;br /&gt;
that normal messages begin to take center stage again. Your inbox would no&lt;br /&gt;
longer be filled with notifications from Twitter and Facebook. It would&lt;br /&gt;
contain the real stuff you need to deal with for your work or personal life.&lt;/p&gt;
&lt;p&gt;The possibilities here are mind boggling. This could change the way we&lt;br /&gt;
communicate with each other.&lt;/p&gt;
&lt;p&gt;All it would take would be for a major e-mail client like G-mail or Yahoo to&lt;br /&gt;
start handling messages this way and promoting the concept.&lt;/p&gt;
&lt;h4&gt;The Technical Jargon&lt;/h4&gt;
&lt;p&gt;I&amp;#8217;m not familiar enough with the e-mail spec to completely outline how this&lt;br /&gt;
should be done, but I do have a couple of suggestions for how this could work&lt;br /&gt;
in practice.&lt;/p&gt;
&lt;p&gt;First of all, I&amp;#8217;d suggest that web services begin marking notification&lt;br /&gt;
messages with a special &amp;#8220;X-Notification&amp;#8221; e-mail header. The header could&lt;br /&gt;
include information about whether the message required some action from the&lt;br /&gt;
user or not. Other things that could possibly be included here would be flags&lt;br /&gt;
that would be read by mail servers as the message is passed along that would&lt;br /&gt;
determine the priority that it should be delivered. Lower-priority&lt;br /&gt;
notifications would not need to be delivered immediately.&lt;/p&gt;
&lt;p&gt;Secondly, I&amp;#8217;d suggest that the subject of the message be treated as a one-line&lt;br /&gt;
summary of the notification. Web services seem to be doing this already.&lt;/p&gt;
&lt;p&gt;Thirdly, I&amp;#8217;d also suggest that we add a new alternative part to a &lt;span class="caps"&gt;MIME&lt;/span&gt; encoded&lt;br /&gt;
message that would contain the compact rich notification summary suitable for&lt;br /&gt;
display in a feed of some kind (I&amp;#8217;m thinking &lt;span class="caps"&gt;HTML&lt;/span&gt; here). The new part type is&lt;br /&gt;
essential because it would allow messages to be displayed in the new format&lt;br /&gt;
only if the e-mail client supported it, whereas older clients could continue&lt;br /&gt;
to display them as normal e-mail messages.&lt;/p&gt;
&lt;p&gt;So this is my big idea. What do you think?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/kQjRUKdg81U" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/kQjRUKdg81U/" />
          <published>2009-12-04T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2009/12/04/if-email-had-a-baby-notification-messages//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2009/10/14/tech-notes-radiant-0-9-0-rc1//</id>
          <title type="html">Tech Notes: Radiant 0.9.0 RC1</title>
          <updated>2009-10-14T04:36:55Z</updated>
          <content type="html">&lt;p&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0007/blade-interface.png" alt="The Blade Inteface" /&gt;&lt;/p&gt;
&lt;p&gt;On Friday of last week we did a &lt;a href="http://radiantcms.org/blog/archives/2009/10/09/radiant-0-9-0-release-candidate-1"&gt;release candidate&lt;/a&gt;&lt;br /&gt;
for the next version of Radiant. Radiant 0.9 is the most significant overhaul&lt;br /&gt;
of the adimin interface since Radiant was first released back in 2006.&lt;/p&gt;
&lt;p&gt;Apart from the obvious interface improvements, there have been a number of&lt;br /&gt;
technology changes on the frontend that are worth talking about.&lt;/p&gt;
&lt;h4&gt;We&amp;#8217;ve Climbed Aboard The &lt;span class="caps"&gt;SASS&lt;/span&gt; Bandwagon&lt;/h4&gt;
&lt;p&gt;&lt;a href="http://sass-lang.com/"&gt;&lt;span class="caps"&gt;SASS&lt;/span&gt;&lt;/a&gt; is a new framework to build the cascading stylesheets.&lt;br /&gt;
It&amp;#8217;s the sister of &lt;span class="caps"&gt;HAML&lt;/span&gt; (the indentation cousin of &lt;span class="caps"&gt;ERB&lt;/span&gt;), but in many ways it is&lt;br /&gt;
much more revolutionary than &lt;span class="caps"&gt;HAML&lt;/span&gt;. &lt;span class="caps"&gt;SASS&lt;/span&gt; gives a designer many of the same tools to&lt;br /&gt;
keep stylesheets clean, that programmers have used for decades for their own code.&lt;br /&gt;
It has support for variables, functions (called modules), and basic conditionals.&lt;/p&gt;
&lt;p&gt;For Radiant we are just begining to tap in to the power that &lt;span class="caps"&gt;SASS&lt;/span&gt; provides, but I can show&lt;br /&gt;
you a couple of code snippets that show exactly how it can make stylesheet development easier.&lt;/p&gt;
&lt;p&gt;For example, here is a &lt;span class="caps"&gt;SASS&lt;/span&gt; module that makes declaring opacity for an element easier:&lt;/p&gt;
&lt;pre class="code sass-code"&gt;&lt;code&gt;=opacity(!opacity)&lt;br /&gt;&amp;nbsp;&amp;nbsp;opacity= !opacity&lt;br /&gt;&amp;nbsp;&amp;nbsp;-moz-opacity= !opacity&lt;br /&gt;&amp;nbsp;&amp;nbsp;-khtml-opacity= !opacity&lt;br /&gt;&amp;nbsp;&amp;nbsp;-webkit-opacity= !opacity&lt;br /&gt;&amp;nbsp;&amp;nbsp;filter= &amp;quot;alpha(opacity=&amp;quot; + round(!opacity*100) + &amp;quot;)&amp;quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;-ms-filter= &amp;quot;progid:DXImageTransform.Microsoft.Alpha(Opacity=&amp;quot; + round(!opacity*100) + &amp;quot;)&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then, in the actual stylesheet I can reference the module like this:&lt;/p&gt;
&lt;pre class="code sass-code"&gt;&lt;code&gt;#transparent&lt;br /&gt;&amp;nbsp;&amp;nbsp;+opacity(0.5)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Which will output the following when it is compiled to &lt;span class="caps"&gt;CSS&lt;/span&gt;:&lt;/p&gt;
&lt;pre class="code css-code"&gt;&lt;code&gt;#transparent {&lt;br /&gt;&amp;nbsp;&amp;nbsp;opacity: 0.5;&lt;br /&gt;&amp;nbsp;&amp;nbsp;-moz-opacity: 0.5;&lt;br /&gt;&amp;nbsp;&amp;nbsp;-khtml-opacity: 0.5;&lt;br /&gt;&amp;nbsp;&amp;nbsp;-webkit-opacity: 0.5;&lt;br /&gt;&amp;nbsp;&amp;nbsp;filter:alpha(opacity=50);&lt;br /&gt;&amp;nbsp;&amp;nbsp;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=50)&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Effecively making a div with an ID of &amp;#8220;transparent&amp;#8221; 50% transparent in a browser&lt;br /&gt;
compatible way.&lt;/p&gt;
&lt;p&gt;The great thing about this is I can use the opacity mixin as many times as I want&lt;br /&gt;
across my stylesheets. If I then need to update the technique that I used for creating&lt;br /&gt;
opacity (say, to use transparent PNGs instead) I can redefine the opacity module&lt;br /&gt;
and all of the code that uses it will get updated with the new rules.&lt;/p&gt;
&lt;p&gt;Apart from the opacity module, I have also written or found modules for rounding&lt;br /&gt;
corners, and adding drop shadows. We still have a long way to go in leveraging the&lt;br /&gt;
power of &lt;span class="caps"&gt;SASS&lt;/span&gt; for Radiant, but I am excited about the possibilities that it&lt;br /&gt;
opens up, particularly for extensions.&lt;/p&gt;
&lt;p&gt;I am finding that &lt;span class="caps"&gt;SASS&lt;/span&gt;, when used appropriately, makes &lt;span class="caps"&gt;CSS&lt;/span&gt; much easier to maintain&lt;br /&gt;
and refactor.&lt;/p&gt;
&lt;p&gt;If you are interested in learning more about &lt;span class="caps"&gt;SASS&lt;/span&gt;, the&lt;br /&gt;
&lt;a href="http://github.com/chriseppstein/compass/"&gt;Compass project&lt;/a&gt; on GitHub is a great&lt;br /&gt;
one to explore.&lt;/p&gt;
&lt;h4&gt;The New Javascript Sauce: LowPro + Prototype&lt;/h4&gt;
&lt;p&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0003/popupjs-window.png" class="float-right" alt="A PopupJS Window" style="margin-top: 0.5em" /&gt;&lt;br /&gt;
Another major change in this release is the introduction of &lt;a href="http://www.danwebb.net/lowpro"&gt;LowPro&lt;/a&gt;&lt;br /&gt;
behaviors. Most of the core Javascript has been repurposed to leverage this technology.&lt;br /&gt;
LowPro make it easy to attach objects (called behaviors) to the &lt;span class="caps"&gt;DOM&lt;/span&gt; that respond to&lt;br /&gt;
events. LowPro does all of this &lt;a href="http://en.wikipedia.org/wiki/Unobtrusive_JavaScript"&gt;unobtrusively&lt;/a&gt;&lt;br /&gt;
which also encourages code reuse.&lt;/p&gt;
&lt;p&gt;One example of this is the Popup.TriggerBehavior. The Popup.TriggerBehavior makes it&lt;br /&gt;
possible for extension developers to pop up Facebook-like windows without writing a&lt;br /&gt;
single line of Javascript. LowPro automatically attaches the Popup.TriggerBehavior to&lt;br /&gt;
links with the &amp;#8220;popup&amp;#8221; class, like this:&lt;/p&gt;
&lt;pre class="code html-code"&gt;&lt;code&gt;&amp;lt;a class=&amp;quot;popup&amp;quot; href=&amp;quot;#reference_window&amp;quot;&amp;gt;Reference&amp;lt;/a&amp;gt;&lt;br /&gt;&amp;lt;div id=&amp;quot;reference_window&amp;quot; style=&amp;quot;display: none&amp;quot;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;... contents of window ...&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;em&gt;href&lt;/em&gt; in the code above specifies the ID of the div that should be wrapped&lt;br /&gt;
in a popup window. When the behavior is attached, it removes the div from the &lt;span class="caps"&gt;DOM&lt;/span&gt; and wraps&lt;br /&gt;
it in the chrome of a popup window. Then when the link is clicked the window is centered&lt;br /&gt;
within the view port and shown. All of this without writing a single line of javascript.&lt;/p&gt;
&lt;p&gt;Another very cool example of LowPro behaviors in action is the Status.FormBehavior. This behavior&lt;br /&gt;
is attached to every form and works using a custom attribute.&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="ident"&gt;form&lt;/span&gt; &lt;span class="ident"&gt;action&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;...&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="ident"&gt;onsubmit_status&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Saving Changes...&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;...&lt;/span&gt; &lt;span class="ident"&gt;contents&lt;/span&gt; &lt;span class="ident"&gt;of&lt;/span&gt; &lt;span class="ident"&gt;form&lt;/span&gt; &lt;span class="punct"&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="regex"&gt;form&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src="http://wiseheartdesign.com/page_attachments/0000/0005/saving-changes.png" class="float-right" alt="Saving Changes" style="margin-bottom: 0.5em" /&gt;&lt;br /&gt;
In the code above the status message &amp;#8220;Saving Changes&amp;#8230;&amp;#8221; will be displayed whenever the&lt;br /&gt;
form is submitted. This serves to let the user know that they clicked the right button&lt;br /&gt;
and also gives them a small progress pinwheel so that they know work is being done.&lt;/p&gt;
&lt;p&gt;Both of the behaviors metioned in this article ship with Radiant and are also separate&lt;br /&gt;
projects on GitHub. The first is called &lt;a href="http://github.com/jlong/popupjs"&gt;PopupJS&lt;/a&gt; and the second &lt;a href="http://github.com/jlong/statusjs"&gt;StatusJS&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/t4L5cyIFYPU" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/t4L5cyIFYPU/" />
          <published>2009-10-14T04:36:55Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2009/10/14/tech-notes-radiant-0-9-0-rc1//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2009/04/21/reintroducing-serve-a-rapid-prototyping-framework-for-designers//</id>
          <title type="html">Serve: A Rapid Prototyping Framework for Designers</title>
          <updated>2010-02-20T05:22:44Z</updated>
          <content type="html">&lt;p&gt;&lt;img src="http://wiseheartdesign.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;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/TouWIdV0sYA" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/TouWIdV0sYA/" />
          <published>2009-04-21T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2009/04/21/reintroducing-serve-a-rapid-prototyping-framework-for-designers//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2009/04/03/memberhub-com-in-6-minutes//</id>
          <title type="html">MemberHub.com in Six Minutes</title>
          <updated>2009-09-23T21:31:50Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://memberhub.com"&gt;&lt;img src="http://wiseheartdesign.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;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/seJCmXFVjrM" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/seJCmXFVjrM/" />
          <published>2009-04-03T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2009/04/03/memberhub-com-in-6-minutes//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2008/12/28/html-canvas-test//</id>
          <title type="html">HTML Canvas Test</title>
          <updated>2009-09-23T21:31:50Z</updated>
          <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;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/fVlqoea-_pE" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/fVlqoea-_pE/" />
          <published>2008-12-28T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2008/12/28/html-canvas-test//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2008/12/12/meet-dataset-the-fixture-killing-data-loading-framework//</id>
          <title type="html">Meet Dataset: The Fixture-Killing, Data-Loading Framework</title>
          <updated>2009-09-23T22:13:52Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://github.com/aiwilliams/dataset"&gt;&lt;img src="http://wiseheartdesign.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;pre class="code bash-code"&gt;&lt;code&gt;./script/plugin install git://github.com/aiwilliams/dataset.git&lt;/code&gt;&lt;/pre&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;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;dataset&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Test::Unit::TestCase&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;include&lt;/span&gt; &lt;span class="constant"&gt;Dataset&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;datasets_directory&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{RAILS_ROOT}&lt;/span&gt;/test/datasets&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&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;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="comment"&gt;# in test/datasets/users_dataset.rb&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;UsersDataset&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Dataset&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;load&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;create_record&lt;/span&gt; &lt;span class="symbol"&gt;:user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:john&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;John&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:password&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;doodaht&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;create_record&lt;/span&gt; &lt;span class="symbol"&gt;:user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:cindy&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Cindy&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:password&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;whoot!&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&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;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="comment"&gt;# in test/unit/user_test.rb&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;UserTest&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Test&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Unit&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;TestCase&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;dataset&lt;/span&gt; &lt;span class="symbol"&gt;:users&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test_do_something&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;user&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;users&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:john&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;assert_equal&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;doodaht&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;password&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&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;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="comment"&gt;# in test/datasets/posts_dataset.rb&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;PostsDataset&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Dataset&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;load&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;create_record&lt;/span&gt; &lt;span class="symbol"&gt;:post&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:first&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:title&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;First Post&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;create_record&lt;/span&gt; &lt;span class="symbol"&gt;:post&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:second&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:title&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Second Post&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="comment"&gt;# in test/datasets/comments_dataset.rb&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;CommentsDataset&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Dataset&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;uses&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;load&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;create_record&lt;/span&gt; &lt;span class="symbol"&gt;:comment&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:first&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:body&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Nice post!&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="symbol"&gt;:post_id&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;post_id&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:first&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;create_record&lt;/span&gt; &lt;span class="symbol"&gt;:comment&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:second&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:body&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;I like it.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="symbol"&gt;:post_id&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;post_id&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:first&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;create_record&lt;/span&gt; &lt;span class="symbol"&gt;:comment&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:third&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:body&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;I thoroughly disagree.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="symbol"&gt;:post_id&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;post_id&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:second&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&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;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="comment"&gt;# in test/datasets/users_dataset.rb&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;UsersDataset&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Dataset&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;load&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;create_user&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;John&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="symbol"&gt;:email&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;john@example.com&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;helpers&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;create_user&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;attributes&lt;/span&gt;&lt;span class="punct"&gt;={})&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;defaults&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="symbol"&gt;:email&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;gsub&lt;/span&gt;&lt;span class="punct"&gt;(/&lt;/span&gt;&lt;span class="regex"&gt;[,. ]+&lt;/span&gt;&lt;span class="punct"&gt;/,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;.&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;@example.com&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;create_record&lt;/span&gt; &lt;span class="symbol"&gt;:user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;downcase&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;intern&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;defaults&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;merge&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;attributes&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;login_as&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@request&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;session&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:user_id&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;id&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&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;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="comment"&gt;# in test/integration/projects_test.rb&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ProjectsTest&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActionController&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;IntegrationTest&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;dataset&lt;/span&gt; &lt;span class="symbol"&gt;:users&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:projects&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:todos&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test_should_show_active_projects&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;login_as&lt;/span&gt; &lt;span class="ident"&gt;users&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:john&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;get&lt;/span&gt; &lt;span class="symbol"&gt;:projects&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;assert_tag&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;#active_projects&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&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;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/ByJsyeyWGZ8" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/ByJsyeyWGZ8/" />
          <published>2008-12-12T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2008/12/12/meet-dataset-the-fixture-killing-data-loading-framework//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2008/12/03/radiant-sprint-on-december-13//</id>
          <title type="html">Radiant Sprint on December 13</title>
          <updated>2009-09-23T21:31:50Z</updated>
          <content type="html">&lt;p&gt;&lt;img src="http://wiseheartdesign.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;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/oZVcui1nNCY" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/oZVcui1nNCY/" />
          <published>2008-12-03T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2008/12/03/radiant-sprint-on-december-13//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2008/07/17/create-facebook-like-windows-with-popup-js//</id>
          <title type="html">Create Facebook-like Windows with Popup.js</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <content type="html">&lt;p&gt;&lt;img src ="http://wiseheartdesign.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;pre class="code html-code"&gt;&lt;code&gt;&amp;lt;div class=&amp;quot;popup&amp;quot; id=&amp;quot;test&amp;quot; style=&amp;quot;display: none&amp;quot;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;h3 class=&amp;quot;title&amp;quot;&amp;gt;Popup Window&amp;lt;/h3&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;div class=&amp;quot;popup_content&amp;quot;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;gt;Hello world!&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;javascript: Element.closePopup('test')&amp;quot;&amp;gt;Close&amp;lt;/a&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&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;pre class="code html-code"&gt;&lt;code&gt;&amp;lt;a href=&amp;quot;#test&amp;quot; class=&amp;quot;popup&amp;quot;&amp;gt;Popup&amp;lt;/a&amp;gt;&amp;lt;/code&amp;gt;&lt;/code&gt;&lt;/pre&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;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/km21KyWl4Mg" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/km21KyWl4Mg/" />
          <published>2008-07-17T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2008/07/17/create-facebook-like-windows-with-popup-js//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2007/10/27/pragmatic-programmer-site-live//</id>
          <title type="html">Pragmatic Programmer Site Live!</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://pragprog.com/" title="The Pragmatic Programmers"&gt;&lt;img src ="http://wiseheartdesign.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;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/ylNd7h2V12c" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/ylNd7h2V12c/" />
          <published>2007-10-27T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2007/10/27/pragmatic-programmer-site-live//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2007/09/25/introducing-serve//</id>
          <title type="html">Introducing Serve: Now With Gemmi Goodness!</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <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;pre class="code bash-code"&gt;&lt;code&gt;$ sudo gem install haml redcloth bluecloth serve&lt;br /&gt;$ cd ~/Workspaces/prototype&lt;br /&gt;$ ls . * &lt;br /&gt;.:&lt;br /&gt;index.haml&lt;br /&gt;&lt;br /&gt;images:&lt;br /&gt;logo.gif&lt;br /&gt;&lt;br /&gt;javascripts:&lt;br /&gt;prototype.js        dialogs.js         tabset.js&lt;br /&gt;&lt;br /&gt;stylesheets:&lt;br /&gt;application.sass        dialogs.sass&lt;br /&gt;$ serve&lt;br /&gt;[2007-09-25 02:11:42] INFO  WEBrick 1.3.1&lt;br /&gt;[2007-09-25 02:11:42] INFO  ruby 1.8.5 (2006-12-25)&lt;br /&gt;[2007-09-25 02:11:42] INFO  Serve::Server#start: pid=1626 port=3000&lt;br /&gt;...&lt;/code&gt;&lt;/pre&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;pre class="code bash-code"&gt;&lt;code&gt;$ serve --help&lt;/code&gt;&lt;/pre&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;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/u3DOwguq5Dw" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/u3DOwguq5Dw/" />
          <published>2007-09-25T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2007/09/25/introducing-serve//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2007/09/04/a-haml-server-for-web-designers//</id>
          <title type="html">A HAML Server for Web Designers</title>
          <updated>2009-09-30T03:53:16Z</updated>
          <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, I updated it to work with &lt;span class="caps"&gt;HAML&lt;/span&gt;:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="comment"&gt;#!/usr/bin/env ruby&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;webrick&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;rubygems&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;haml&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;HamlHandler&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;WEBrick&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;HTTPServlet&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;AbstractServlet&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;server&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;super&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@script_filename&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_GET&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;req&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;res&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;begin&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;data&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;open&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="attribute"&gt;@script_filename&lt;/span&gt;&lt;span class="punct"&gt;){|&lt;/span&gt;&lt;span class="ident"&gt;io&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;io&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;read&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;res&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;body&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;parse_haml&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;data&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;res&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;content-type&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;text/html&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;rescue&lt;/span&gt; &lt;span class="constant"&gt;StandardError&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;ex&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;raise&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;rescue&lt;/span&gt; &lt;span class="constant"&gt;Exception&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;ex&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@logger&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;error&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;ex&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;raise&lt;/span&gt; &lt;span class="constant"&gt;HTTPStatus&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;InternalServerError&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;ex&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;message&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;alias&lt;/span&gt; &lt;span class="ident"&gt;do_POST&lt;/span&gt; &lt;span class="ident"&gt;do_GET&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;private&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;parse_haml&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;string&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;engine&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Haml&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Engine&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;string&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:attr_wrapper&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;&amp;quot;&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:filename&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="attribute"&gt;@script_filename&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;engine&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;render&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="constant"&gt;WEBrick&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;HTTPServlet&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;FileHandler&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;add_handler&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;haml&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="constant"&gt;HamlHandler&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;args&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ARGV&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt; &lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;gsub!&lt;/span&gt;&lt;span class="punct"&gt;(%r{&lt;/span&gt;&lt;span class="regex"&gt;^http://&lt;/span&gt;&lt;span class="punct"&gt;},&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;args&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;split&lt;/span&gt;&lt;span class="punct"&gt;(/&lt;/span&gt;&lt;span class="regex"&gt;[ :]&lt;/span&gt;&lt;span class="punct"&gt;/).&lt;/span&gt;&lt;span class="ident"&gt;compact&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;server&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;WEBrick&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;HTTPServer&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:Port&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;pop&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="number"&gt;3000&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:BindAddress&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;pop&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;0.0.0.0&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:DocumentRoot&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;Dir&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;pwd&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;trap&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;INT&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;server&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;shutdown&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;server&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;start&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;Update!&lt;/b&gt; A more powerful version of this script has been packaged up in a gem called &lt;a href="http://wiseheartdesign.com/articles/reintroducing-serve-a-rapid-prototyping-framework-for-designers/"&gt;serve&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/DO9GT86_GIA" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/DO9GT86_GIA/" />
          <published>2007-09-04T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2007/09/04/a-haml-server-for-web-designers//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2007/08/26/just-an-experiment//</id>
          <title type="html">Just an Experiment</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <content type="html">&lt;p&gt;&lt;img src="http://wiseheartdesign.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;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/tsYyubV4l8s" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/tsYyubV4l8s/" />
          <published>2007-08-26T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2007/08/26/just-an-experiment//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2007/08/25/constraints-frameworks-and-adam-s-basement//</id>
          <title type="html">Constraints, Frameworks, and Adam’s Basement</title>
          <updated>2009-09-23T21:31:50Z</updated>
          <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;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/QYmEL6ykd4I" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/QYmEL6ykd4I/" />
          <published>2007-08-25T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2007/08/25/constraints-frameworks-and-adam-s-basement//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2007/06/15/better-modularization-for-rails-2-0//</id>
          <title type="html">Better Modularization for Rails 2.0 (or What Rails Can Learn from Django)</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <content type="html">&lt;p&gt;In my previous post about &lt;a href="http://wiseheartdesign.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;pre class="code text-code"&gt;&lt;code&gt;app/&lt;br /&gt;&amp;nbsp;&amp;nbsp;controllers/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;application.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account_controller.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blog_controller.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;comments_controller.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;helpers/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;application_helper.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account_helper.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blog_helper.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;models/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blog.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;post.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;comment.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;views/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;signup.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;login.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;edit.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blog/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;index.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;archive.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;post.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;comments/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;view.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;remove.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;layouts/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;application.rhtml&lt;/code&gt;&lt;/pre&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;pre class="code text-code"&gt;&lt;code&gt;account/&lt;br /&gt;&amp;nbsp;&amp;nbsp;__init__.py&lt;br /&gt;&amp;nbsp;&amp;nbsp;urls.py&lt;br /&gt;&amp;nbsp;&amp;nbsp;models.py&lt;br /&gt;&amp;nbsp;&amp;nbsp;views.py&lt;br /&gt;&amp;nbsp;&amp;nbsp;templates/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account_login.html&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account_signup.html&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account_edit.html&lt;br /&gt;blog/&lt;br /&gt;&amp;nbsp;&amp;nbsp;__init__.py&lt;br /&gt;&amp;nbsp;&amp;nbsp;urls.py&lt;br /&gt;&amp;nbsp;&amp;nbsp;models.py&lt;br /&gt;&amp;nbsp;&amp;nbsp;views.py&lt;br /&gt;&amp;nbsp;&amp;nbsp;templates/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blog/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blog_list.html&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blog_archive.html&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blog_detail.html&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;comment/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;comment_view.html&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;comment_remove.html&lt;/code&gt;&lt;/pre&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;pre class="code text-code"&gt;&lt;code&gt;app/&lt;br /&gt;&amp;nbsp;&amp;nbsp;application/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;application_controller.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;application_layout.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;account/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_config.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_routes.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account_controller.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account_helper.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account_edit.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account_login.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account_signup.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_migrations.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;blog/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_config.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_routes.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blog_controller.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blog_helper.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blog_index.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blog_archive.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blog_post.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;comment.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;comment_migrations.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;comments_controller.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;comments_helper.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;comments_view.rhtml&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;post.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;post_migrations.rb&lt;/code&gt;&lt;/pre&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;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/fL3sxzF5Cfg" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/fL3sxzF5Cfg/" />
          <published>2007-06-15T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2007/06/15/better-modularization-for-rails-2-0//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2007/05/03/setting-up-ubuntu-for-rails//</id>
          <title type="html">Setting Up Ubuntu for Rails</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <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;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/tem7kiZM5og" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/tem7kiZM5og/" />
          <published>2007-05-03T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2007/05/03/setting-up-ubuntu-for-rails//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2007/05/03/two-rails-testing-plugins//</id>
          <title type="html">Two Rails Testing Plugins</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <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;pre class="code bash-code"&gt;&lt;code&gt;$ script/plugin source http://wiseheartdesign.com/svn/plugins/&lt;br /&gt;$ script/plugin install test_helpers&lt;br /&gt;$ script/plugin install abstract_testcases&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Comments and feedback are welcome.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/311gYkJwNAw" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/311gYkJwNAw/" />
          <published>2007-05-03T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2007/05/03/two-rails-testing-plugins//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2007/03/12/so-you-want-to-write-a-book//</id>
          <title type="html">So You Want to Write a Book?</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <content type="html">&lt;p&gt;Over on &lt;a href="http://pragdave.pragprog.com/"&gt;Dave Thomas&amp;#8217; Blog&lt;/a&gt; he&amp;#8217;s writing a unique series of articles entitled &lt;em&gt;So You Want To Write a Book&lt;/em&gt;. If you&amp;#8217;ve ever thought about writing a technical book, or even a non-technical book you will definitely enjoy the series. Here&amp;#8217;s an excerpt from his second article, &lt;a href="http://pragdave.pragprog.com/pragdave/2007/03/sywtwab_2_the_h.html"&gt;&lt;em&gt;The Hero&amp;#8217;s Journey&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every Hero&amp;#8217;s Journey follows the same basic plan. We start by meeting the protagonist, an average person living a standard life. Suddenly, something bad happens to them, normally something unimaginable and outside their control. At this point, our character must make a decision. Do they cave, or do they commit to face the challenge—do the take a risk an embark on the journey?&lt;/p&gt;
&lt;p&gt;Once they join the path, they face a series of challenges, often getting harder or more complex as the story progresses. By overcoming each, the hero gradually masters the initial problem.&lt;/p&gt;
&lt;p&gt;But the story never ends there. Once the hero conquers all the problems, they face one last challenge. They must return to the real world, which often feels different to them. However, once back home, they get to apply what they learned on their journey. They are stronger.&lt;/p&gt;
&lt;p&gt;What does this have to do with technical books?&lt;/p&gt;
&lt;p&gt;Everything.&lt;/p&gt;
&lt;p&gt;Because a good technical book is also a hero&amp;#8217;s journey. The reader joins the book already faced with a major challenge—they need to learn some new technique or technology. Thy need to make a commitment to follow the path. Along the way, they need to learn stuff, try things, conquering increasingly difficult concepts and challenges. Eventually they graduate; they&amp;#8217;ve learned what they came to learn. But they journey doesn&amp;#8217;t end there. Like the hero, they then have to come home, bringing back what they learned.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dave really has a talent for connecting with his readers. &lt;a href="http://pragdave.pragprog.com/pragdave/writing_a_book/index.html"&gt;Read More&amp;#8230;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/dgv_aZQmkTc" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/dgv_aZQmkTc/" />
          <published>2007-03-12T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2007/03/12/so-you-want-to-write-a-book//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2007/02/13/johns-essential-css//</id>
          <title type="html">John’s Essential Guide to CSS</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <content type="html">&lt;p&gt;I once taught a workshop on &lt;acronym title="Cascading Style Sheets"&gt;&lt;span class="caps"&gt;CSS&lt;/span&gt;&lt;/acronym&gt; and in the process compiled a list of essential reading for people interested learning &lt;span class="caps"&gt;CSS&lt;/span&gt;. I&amp;#8217;ve revamped the list below, adding a few additional articles, and reorganizing it a bit. Most of the articles are from &lt;a href="http://alistapart.com"&gt;&lt;em&gt;A List Apart&lt;/em&gt;&lt;/a&gt;, but the volume of articles at &lt;em&gt;A List Apart&lt;/em&gt; can can be overwhelming to people just to getting started. Consider this a pocket guide to the best of &lt;em&gt;A List Apart&lt;/em&gt; with a few additional links thrown in to spice it up a bit.&lt;/p&gt;
&lt;h4&gt;The Basics&lt;/h4&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/doctype/"&gt;Fix Your Site with the Right &lt;span class="caps"&gt;DOCTYPE&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/sizematters/"&gt;&lt;span class="caps"&gt;CSS&lt;/span&gt; Design: Font Size Matters&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/practicalcss/"&gt;Practical &lt;span class="caps"&gt;CSS&lt;/span&gt; Layout Tips, Tricks, &amp;amp; Techniques&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.nypl.org/styleguide/"&gt;&lt;span class="caps"&gt;NYPL&lt;/span&gt; Online Style Guide&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/betterliving/"&gt;Better Living Through &lt;span class="caps"&gt;XHTML&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;The Power of Floats and Backgrounds&lt;/h4&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/fauxcolumns/"&gt;Faux Columns&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/negativemargins/"&gt;Creating Liquid Layouts with Negative Margins&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://wellstyled.com/css-2col-fluid-layout.html" title="Fluid"&gt;Two Column Tableless Layout&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/customcorners/"&gt;&lt;span class="caps"&gt;CSS&lt;/span&gt; Design: Creating Custom Corners &amp;amp; Borders&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/mountaintop/"&gt;Mountain Top Corners&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;span class="caps"&gt;CSS&lt;/span&gt; Drop Shadows (&lt;a href="http://www.alistapart.com/articles/cssdropshadows/"&gt;1&lt;/a&gt;, &lt;a href="http://www.alistapart.com/articles/cssdrop2/"&gt;2&lt;/a&gt;, and &lt;a href="http://www.alistapart.com/articles/onionskin/"&gt;3&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Print Stylesheets &amp;amp; Cross-Browser Compatibility&lt;/h4&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/goingtoprint/"&gt;&lt;span class="caps"&gt;CSS&lt;/span&gt; Design: Going to Print&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/printyourway/"&gt;Print It Your Way&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/alternate/"&gt;Alternative Style: Working With Alternate Style Sheets&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.bluerobot.com/web/css/fouc.asp" title="FOUC"&gt;Flash of Unstyled Content&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.positioniseverything.net/explorer/doubled-margin.html"&gt;The IE Doubled Float-Margin Bug&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/emen/" title="and Other Shady Characters"&gt;The Trouble With EM ’n EN&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.tantek.com/CSS/Examples/boxmodelhack.html"&gt;The Box Model Hack&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.positioniseverything.net/"&gt;Position Is Everything&lt;/a&gt; has fixes to bugs in &lt;a href="http://www.positioniseverything.net/explorer.html"&gt;IE&lt;/a&gt;, &lt;a href="http://www.positioniseverything.net/op-omnibus.html"&gt;Opera&lt;/a&gt;, and &lt;a href="http://www.positioniseverything.net/gecko.html"&gt;Firefox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Lists, Rollovers, &amp;amp; Image Replacement Techniques&lt;/h4&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://alistapart.com/articles/taminglists/"&gt;Taming Lists&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.simplebits.com/notebook/2003/06/29/icon_styled_headings.html"&gt;Icon Styled Headings&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://alistapart.com/articles/sprucemaps/"&gt;Spruced-Up Site Maps&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/dropdowns/"&gt;Suckerfish Dropdowns&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.stopdesign.com/articles/replace_text/"&gt;Using Background-Image to Replace Text&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/fir/"&gt;Facts and Opinion About Fahrner Image Replacement&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.digital-web.com/articles/in_defense_of_fahrner_image_replacement/"&gt;In Defense of Fahrner Image Replacement&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Secrets of Absolute Positioning&lt;/h4&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://stopdesign.com/articles/absolute/"&gt;Making Absolute Relative&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.wpdfd.com/editorial/wpd0904news.htm#feature"&gt;Absolutely Relative&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/flexiblelayouts/"&gt;Flexible Layouts with &lt;span class="caps"&gt;CSS&lt;/span&gt; Positioning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Additional Resources&lt;/h4&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.ilovejackdaniels.com/css/css-cheat-sheet/"&gt;&lt;span class="caps"&gt;CSS&lt;/span&gt; Cheat Sheet&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.csszengarden.com/"&gt;&lt;span class="caps"&gt;CSS&lt;/span&gt; Zen Garden&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://thenoodleincident.com/tutorials/box_lesson/boxes.html"&gt;Box Lessons&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/slashdot/"&gt;Retooling Slashdot with Web Standards&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/separationdilemma/"&gt;Separation: The Web Designer’s Dilemma&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/separation/"&gt;Separation Anxiety: The Myth of the Separation of Style from Content&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/6OrDflBheqY" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/6OrDflBheqY/" />
          <published>2007-02-13T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2007/02/13/johns-essential-css//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/12/13/the-terralien-crew//</id>
          <title type="html">The Terralien Crew</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://terralien.com/"&gt;&lt;img src="http://wiseheartdesign.com/images/terralien-com.png" class="float-right" alt="" /&gt;&lt;/a&gt; Nathaniel Talbott (of &lt;a href="http://ruby-doc.org/stdlib/libdoc/test/unit/rdoc/index.html"&gt;Test::Unit&lt;/a&gt; fame) has put together an unbelievable crew that may be just what you need for your next Ruby on Rails project. Crew members include such notables as:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;&lt;a href="http://wiseheartdesign.com/portfolio/"&gt;Myself&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;a href="http://codefluency.com/"&gt;Bruce Williams&lt;/a&gt;&lt;/strong&gt; (a popular blogger, programmer, and designer)&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;a href="http://mattmccray.com/"&gt;Matt McCray&lt;/a&gt;&lt;/strong&gt; (the author of &lt;a href="http://comatose.rubyforge.org/"&gt;Comatose &lt;span class="caps"&gt;CMS&lt;/span&gt;&lt;/a&gt; and the &lt;a href="http://www.mattmccray.com/pivot/archive.php?c=Theme_Support"&gt;Rails Theme Support Plugin&lt;/a&gt;)&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;a href="http://blog.codora.com/"&gt;Duff O&amp;#8217;Melia&lt;/a&gt;&lt;/strong&gt; (the creator of &lt;a href="http://soapadoo.com"&gt;Soapadoo&lt;/a&gt;)&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://terralien.com/about/people/"&gt;And others&amp;#8230;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Terralien is a network of designers and programmers who specialize in developing Web applications with Ruby on Rails. We have a reputation for being able to deliver quality code on a deadline through rapid prototyping and incremental release cycles. Read more about the crew on the &lt;a href="http://terralien.com/"&gt;Terralien  Web site&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/Vvz8TaJnRsE" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/Vvz8TaJnRsE/" />
          <published>2006-12-13T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/12/13/the-terralien-crew//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/12/07/introducing-feedchamp//</id>
          <title type="html">Introducing FeedChamp: A Camping RSS Feed Aggregator</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <content type="html">&lt;p&gt;I went &lt;a href="http://code.whytheluckystiff.net/camping/"&gt;camping&lt;/a&gt; last night and decided to see how easy it would be to create an &lt;span class="caps"&gt;RSS&lt;/span&gt; feed aggregator. After just a short time I had a working app and with some additional tweaking it became FeedChamp:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://github.com/jlong/feedchamp"&gt;http://github.com/jlong/feedchamp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Have a look if you can. And if you want to help with its development I&amp;#8217;ll gladly give you commit rights.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s not much right now, but perhaps with a little love from a few others it will turn into a nice app. For more info see the &lt;a href="http://github.com/jlong/feedchamp/blob/2cfaa11df8169d4df4015a82832e8de71111097e/README"&gt;&lt;span class="caps"&gt;README&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/zcKIK2UlnZs" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/zcKIK2UlnZs/" />
          <published>2006-12-07T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/12/07/introducing-feedchamp//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/12/06/rails-needs-something-better-than-engines//</id>
          <title type="html">Rails Needs Something Better Than Engines</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <content type="html">&lt;p&gt;I need to apologize for exploiting a title like the above to introduce an article like this. The &lt;a href="http://rails-engines.org/"&gt;Rails Engine&lt;/a&gt; guys have &lt;a href="http://rails-engines.org/news/2006/08/30/apparently-engines-are-still-evil/"&gt;taken a lot of flack&lt;/a&gt; for the work that they have done to make it easy to share code between applications and I don&amp;#8217;t want to add to their misery. Instead, I&amp;#8217;d like to use the issue to put the focus on something else.&lt;/p&gt;
&lt;p&gt;The traditional argument against Rails Engines (as I understand it) is that prepackaged components are a pipe-dream. Components, particularly the way Rails Engines implements them are just too big. Every application will require something custom, and Rails Engines are too generic. Sure, they work well for getting you up and running, but what about down the road when you need to tweak something that the engine author hasn&amp;#8217;t thought about yet? And after all, Rails is so easy to use why not take the agile approach and only develop what you need when you need it?&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m interested in the Rails Engine argument because I think it exposes something about the philosophy that is driving Rails which may not be extremely obvious to those of us on the sidelines who are just trying to use Rails to build better Web sites and applications. That is that &lt;strong&gt;Rails is primarily designed for building completely custom green-field Web applications&lt;/strong&gt; and it shows. When it comes to sharing code between applications the best thing Rails has to offer is generators. So instead of offering a login engine Rails offers a login generator.&lt;/p&gt;
&lt;p&gt;Now don&amp;#8217;t get me wrong here, generators are great for getting people up and running quickly. At first glance they offer &lt;strong&gt;exactly&lt;/strong&gt; what Rails engines offer in that they allow you to get up and running quickly with prepackaged code and the added bonus that you can &lt;strong&gt;completely customize&lt;/strong&gt; the generated code. But where they fall down is that they encourage rampant code duplication.&lt;/p&gt;
&lt;p&gt;Take the login generator for example. How many of us use the generated login code nearly &lt;strong&gt;unmodified&lt;/strong&gt; in application after application? Even if we customize the generated code is it not true that we often perform the same modifications again and again as we move from one application to another?&lt;/p&gt;
&lt;p&gt;Folks we need something better. In a nutshell we need standard way to share views, models, controllers, and URLs between applications.&lt;/p&gt;
&lt;h3&gt;Of Snakes and Rubies&lt;/h3&gt;
&lt;p&gt;On December 3rd of last year I helped organize a debate between David Heinemeier Hansson and Adrian Holovaty (the creator of &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt;). We dubbed the event &lt;em&gt;Snakes and Rubies&lt;/em&gt; and the video and audio from it are available &lt;a href="http://www.djangoproject.com/snakesandrubies/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Even though I am an avid Rails user I was favorably impressed by Adrian&amp;#8217;s presentation on Django and I must say that I am sad to see that more of the ideas in Django have not gained greater traction in the Rails community.&lt;/p&gt;
&lt;p&gt;One of the things that Django does better than Rails at the moment is that it encourages you to subdivide your application according to components. In Django terms you don&amp;#8217;t just create an &amp;#8220;application&amp;#8221; you create a Django &amp;#8220;project&amp;#8221; which contains multiple &amp;#8220;apps&amp;#8221;. An app is a full slice of the application and contains models, views, and controllers (actually in Django terms it contains &amp;#8220;models&amp;#8221;, &amp;#8220;templates&amp;#8221;, and &amp;#8220;views&amp;#8221;, but it is essentially the same thing).&lt;/p&gt;
&lt;p&gt;Django&amp;#8217;s model is perfect for Web sites because you can have mini apps for the admin, blog, and forum, and maybe one for that extremely custom event registration system that you have. Of course the great thing about this is that you can share these little mini apps across applications.&lt;/p&gt;
&lt;p&gt;As I was working on this article I wrote Adrian Holovaty to ask him about this very point. He wrote back:&lt;/p&gt;
&lt;blockquote&gt;This was a big design goal when we were first putting together Django, because at our Web operation, we managed several sites&amp;#8212;all of which used bits and pieces of the same functionality, but always a different mix. Indeed, as you point out, Django has a &amp;#8220;batteries included&amp;#8221; philosophy and ships with some apps that you can choose to use in your own projects.&lt;/blockquote&gt;
&lt;p&gt;And how easy is it to use another Django mini app in your own project? All you need to do is include it in the INSTALLED_APPS configuration variable. Here&amp;#8217;s a small configuration snippet from the &lt;a href="http://www.djangoproject.com/documentation/tutorial1/"&gt;Django tutorial&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="code python-code"&gt;&lt;code&gt;INSTALLED_APPS = (&lt;br /&gt;&amp;nbsp;&amp;nbsp;'django.contrib.auth',&lt;br /&gt;&amp;nbsp;&amp;nbsp;'django.contrib.contenttypes',&lt;br /&gt;&amp;nbsp;&amp;nbsp;'django.contrib.sessions',&lt;br /&gt;&amp;nbsp;&amp;nbsp;'django.contrib.sites',&lt;br /&gt;&amp;nbsp;&amp;nbsp;'mysite.polls'&lt;br /&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are four little mini apps there that are installed by default for the standard Django project: auth, contenttypes, sessions, and sites (I&amp;#8217;ll bet you can guess what they do). Django also provides a rather powerful admin mini app that automatically creates an admin interface for your models. This is extremely helpful in that it allows you to concentrate on the Web site part of your application while leaving the admin part to Django. To see all of this in action check out the &lt;a href="http://www.throwingbeans.org/django_screencasts.html"&gt;Django Screencast&lt;/a&gt; at throwingbeans.org.&lt;/p&gt;
&lt;h3&gt;Can Rails Take a Page from the Django Playbook?&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;m interested in all of this because of my work on Radiant (the content management system I developed for the &lt;a href="http://ruby-lang.org"&gt;Ruby Web site&lt;/a&gt;). Over the past several months I have been working on an extension system for Radiant that will allow others to develop mini rails apps that plug straight into a Radiant application. A Radiant extension is like a Rails plugin except that it supports additional models, views, and controllers (much like Rails Engines do, but with added benefits). The directory structure for a Radiant extension looks like this:&lt;/p&gt;
&lt;pre class="code text-code"&gt;&lt;code&gt;vendor/extensions/&lt;br /&gt;&amp;nbsp;&amp;nbsp;my_extension/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;app/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;controllers/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;helpers/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;models/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;views/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lib/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;test/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;my_extension.rb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Rakefile&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The benefit that Radiant Extensions offer over something like Rails Engines is that they integrate into the Radiant administration system. Right now that integration is a little rough, but we hope to make it easier in the future. Even so, the progress that we have made is encouraging. Here&amp;#8217;s a snippet which demonstrates adding a custom tab to the Radiant administration system:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;AssetManagerExtension&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Radiant&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Extension&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;version&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;1.0&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;description&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Provides asset management support for Radiant.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;define_routes&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;connect&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;admin/assets/:action&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:controller&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;admin/asset&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;activate&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;admin&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;tabs&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;add&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Assets&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;/admin/assets&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="symbol"&gt;:after&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Layouts&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;deactivate&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;admin&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;tabs&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;remove&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Assets&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt; &lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the work on the Radiant extension system has been difficult. Rails doesn&amp;#8217;t make it easy to allow views to reside in multiple places (there is only one template_root). Nor does it provide support for defining routes in multiple locations. Model reloading through the dependencies mechanism is also a difficult issue. Time and again I find myself twisting Rails&amp;#8217; arm to let me do what I want to do. I&amp;#8217;ve had to hook into the Rails internals on multiple occasions (just like the Rails Engines people did).&lt;/p&gt;
&lt;p&gt;I can&amp;#8217;t help looking beyond Radiant though to wonder if built in support for this kind of thing would not be a benefit to the Rails community at large? I know &lt;a href="http://techno-weenie.net/"&gt;Rick Olson&lt;/a&gt; is working on something like the Radiant extension system for &lt;a href="http://mephistoblog.com"&gt;Mephisto&lt;/a&gt; and I can see that other apps could be benefited by something similar. We&amp;#8217;ve already seen Rails Engines and now there is also &lt;a href="http://wiki.pluginaweek.org/Appable_plugins/"&gt;Appable Plugins&lt;/a&gt;. How many other approaches are necessary before the Rails community is able to settle on a standard?&lt;/p&gt;
&lt;p&gt;As the Rails-Core team is looking towards Rails 2.0, perhaps it&amp;#8217;s time to start thinking about restructuring Rails applications to take a more modular approach? Maybe there really is something to be learned from Django after all.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/et_jhH5IIm0" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/et_jhH5IIm0/" />
          <published>2006-12-06T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/12/06/rails-needs-something-better-than-engines//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/10/26/the-official-ruby-logo//</id>
          <title type="html">The Official Ruby Logo</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://rubyidentity.org"&gt;&lt;img src="http://static.flickr.com/107/279947192_d298654227_o.png" class="float-left" alt="" /&gt;&lt;/a&gt; It&amp;#8217;s official! Matz now owns the copyright on the Ruby logo the identity team did for the &lt;a href="http://ruby-lang.org"&gt;Ruby Web site&lt;/a&gt;. You can now download the logo and use it on your own projects (T-shirts, Web sites, etc&amp;#8230;)&amp;#8212;free of charge. It&amp;#8217;s available under the &lt;a href="http://creativecommons.org/licenses/by-sa/2.5/"&gt;Creative Commons Attribution-ShareAlike 2.5 License&lt;/a&gt;. Get the complete logo kit at &lt;a href="http://rubyidentity.org"&gt;rubyidentity.org&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/CRPZT6PngpQ" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/CRPZT6PngpQ/" />
          <published>2006-10-26T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/10/26/the-official-ruby-logo//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/10/17/ruby-conf-facebook-2006//</id>
          <title type="html">Ruby Conf Facebook 2006</title>
          <updated>2009-09-23T21:31:50Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://wiki.rubygarden.org/Ruby/page/show/RubyConf2006Facebook"&gt;&lt;img src="http://wiseheartdesign.com/images/ruby-conf-facebook.jpg" class="float-left" alt="" /&gt;&lt;/a&gt; Looking to meet up with an old friend at &lt;a href="http://rubyconf.org/"&gt;Ruby Conf&lt;/a&gt;? Interested in getting together with someone you&amp;#8217;ve never met in the flesh, but know through electronic means? &lt;a href="http://blog.grayproductions.net/"&gt;James Edward Gray&lt;/a&gt; has put together just the thing. If you are planning on attending Ruby Conf, head on over to the &lt;a href="http://wiki.rubygarden.org/Ruby/page/show/RubyConf2006Facebook"&gt;Facebook page&lt;/a&gt; on the Ruby wiki and add your photo.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://wiseheartdesign.com/contact/"&gt;Pop me an e-mail&lt;/a&gt; if you plan to be at the conference and want to get together. I&amp;#8217;d love to talk about &lt;a href="http://radiantcms.org/"&gt;Radiant&lt;/a&gt;, Ruby, Rails, business, or any other topic that might interest you.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;BTW&lt;/span&gt;, if you missed it before, &lt;a href="http://rubyconf.org/agenda.html"&gt;the schedule for Ruby Conf&lt;/a&gt; is now up. Looks like I&amp;#8217;m up to talk about Radiant on Friday afternoon.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/2Huf2fqG1So" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/2Huf2fqG1So/" />
          <published>2006-10-17T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/10/17/ruby-conf-facebook-2006//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/09/22/class-level-instance-variables//</id>
          <title type="html">Class-Level Instance Variables</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <content type="html">&lt;p&gt;I&amp;#8217;ve been doing a lot of metaprograming of late with &lt;a href="http://radiantcms.org"&gt;Radiant&lt;/a&gt; and have gained a deep appreciation for class-level instance variables. If you haven&amp;#8217;t done a lot with class variables, you probably won&amp;#8217;t see much value class-level instance variables.&lt;/p&gt;
&lt;p&gt;Maybe you&amp;#8217;ve been playing around with those neat little class methods on your &lt;a href="http://rubyonrails.org"&gt;Rails&lt;/a&gt; model objects:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Person&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;validates_presence_of&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;validates_numerically_of&lt;/span&gt; &lt;span class="symbol"&gt;:age&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or perhaps you&amp;#8217;ve been experimenting with &lt;a href="http://poignantguide.net/dwemthy/"&gt;Dwemthy&amp;#8217;s Array&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Dragon&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Creature&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="number"&gt;1340&lt;/span&gt;     &lt;span class="comment"&gt;# tough scales&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;strength&lt;/span&gt; &lt;span class="number"&gt;451&lt;/span&gt;  &lt;span class="comment"&gt;# bristling veins&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;charisma&lt;/span&gt; &lt;span class="number"&gt;1020&lt;/span&gt; &lt;span class="comment"&gt;# toothy smile&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;weapon&lt;/span&gt; &lt;span class="number"&gt;939&lt;/span&gt;    &lt;span class="comment"&gt;# fire breath&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ruby makes creating this kind of &lt;a href="http://weblog.jamisbuck.org/2006/4/20/writing-domain-specific-languages/"&gt;Domain Specific Language&lt;/a&gt; a snap, but it&amp;#8217;s not without it&amp;#8217;s&lt;br /&gt;
pitfalls if you&amp;#8217;ve never done it before.&lt;/p&gt;
&lt;p&gt;At first glance you might think that you could store this kind of meta information in a class variable. Let&amp;#8217;s take a simple example. You want to create the &lt;code&gt;Creature&lt;/code&gt; class that &lt;code&gt;Dragon&lt;/code&gt; inherits from. You might define your first attribute like this:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Creature&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.life&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@@life&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="attribute"&gt;@@life&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Class variables are a convenient method of storing information in the class object itself. Since class variables look much like instance variables (in that they are preceded with two @ signs) you might be tempted to think that they are just instance variables for classes, but don&amp;#8217;t be fooled! Class variables are shared variables. Every subclass of a superclass has access to the superclass&amp;#8217;s class variables between superclasses and subclasses. That is, instead of getting a new version of the class variable every time you inherit from the superclass, you get the same version of the variable (not a copy).&lt;/p&gt;
&lt;p&gt;In practice this means that class variables are a poor choice for storing meta data. In the example above if we inherit from Creature more than once we quickly see the problem:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Dragon&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Creature&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="number"&gt;1340&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Gwythaint&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Creature&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="number"&gt;250&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="constant"&gt;Dragon&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;life&lt;/span&gt;  &lt;span class="comment"&gt;#=&amp;gt; 250 !!!!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of getting 1340 for the dragon&amp;#8217;s life, we get 250!! Again this is because class variables are shared between the superclass and every one of its subclasses. It has been suggested that an easy way to work around this problem is to use a hash and store class/value pairs for each of the subclasses:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Creature&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@@lives&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Hash&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.life&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@@lives&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="attribute"&gt;@@lives&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works, but is somewhat verbose. Instead of using a class variable, you can use a class-level instance variable. What?! You thought instance variables were only for instances of the class? Look again:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Creature&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.life&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@life&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="attribute"&gt;@life&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above works because within the context of the class method the instance variable refers to a class-level instance variable&amp;#8212;not a normal instance variable. In fact, any time you reference an instance variable outside a method definition you are working with a class-level instance variable:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;MyObject&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@class_level&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;a class-level instance variable&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@normal&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;a normal instance variable&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="constant"&gt;MyObject&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;instance_variables&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; [&amp;quot;@class_level&amp;quot;]&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="constant"&gt;MyObject&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;instance_variables&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; [&amp;quot;@normal&amp;quot;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don&amp;#8217;t be confused. Classes in Ruby are also objects. Just like other objects they have their own instance variables. The trick with class-level instance variables is that they are defined after the class is created. With a normal object this would look like this:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="ident"&gt;o&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;MyObject&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="ident"&gt;o&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;instance_variables&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; [&amp;quot;@normal&amp;quot;]&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;o&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;instance_eval&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@new_var&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="ident"&gt;o&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;instance_variables&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; [&amp;quot;@normal&amp;quot;, &amp;quot;@new_var&amp;quot;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Most of the time you probably setup instance variables for an object when you initialize it. However, with classes, since instance variables are created after the class is initialized (which happens as soon as you open the class to define methods), instance variables will always be &lt;code&gt;nil&lt;/code&gt; when you create a subclass:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;LargeGwythaint&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Gwythaint&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="constant"&gt;LargeGwythaint&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; nil !!!!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ruby gives us a nice way of working around this problem with a the &lt;code&gt;inherited&lt;/code&gt; class method:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Creature&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.inherited&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;subclass&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;subclass&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;instance_variable_set&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;@life&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="attribute"&gt;@life&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which works as expected:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;LargeDragon&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Dragon&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="constant"&gt;LargeDragon&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; 1340&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, you can package all this logic up in its own module:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;module &lt;/span&gt;&lt;span class="module"&gt;InheritableTraits&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.included&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;base&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;base&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;extend&lt;/span&gt; &lt;span class="constant"&gt;ClassMethods&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;module &lt;/span&gt;&lt;span class="module"&gt;ClassMethods&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;traits&lt;/span&gt;&lt;span class="punct"&gt;(*&lt;/span&gt;&lt;span class="ident"&gt;attrs&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@traits&lt;/span&gt; &lt;span class="punct"&gt;||=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@traits&lt;/span&gt; &lt;span class="punct"&gt;+=&lt;/span&gt; &lt;span class="ident"&gt;attrs&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;attrs&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;attr&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;class_eval&lt;/span&gt; &lt;span class="punct"&gt;%{&lt;/span&gt;&lt;span class="string"&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def self.&lt;span class="expr"&gt;#{attr}&lt;/span&gt;(string = nil)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@&lt;span class="expr"&gt;#{attr}&lt;/span&gt; = string || @&lt;span class="expr"&gt;#{attr}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def self.&lt;span class="expr"&gt;#{attr}&lt;/span&gt;=(string = nil)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="expr"&gt;#{attr}&lt;/span&gt;(string)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@traits&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;inherited&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;subclass&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;([&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;traits&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;traits&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;ivar&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;@&lt;span class="expr"&gt;#{t}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;subclass&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;instance_variable_set&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;ivar&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;instance_variable_get&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;ivar&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And make your life much easier:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Creature&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;include&lt;/span&gt; &lt;span class="constant"&gt;InheritableTraits&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;traits&lt;/span&gt; &lt;span class="symbol"&gt;:life&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:strength&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:charisma&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:weapon&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Dragon&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Creature&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="number"&gt;1340&lt;/span&gt;     &lt;span class="comment"&gt;# tough scales&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;strength&lt;/span&gt; &lt;span class="number"&gt;451&lt;/span&gt;  &lt;span class="comment"&gt;# bristling veins&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;charisma&lt;/span&gt; &lt;span class="number"&gt;1020&lt;/span&gt; &lt;span class="comment"&gt;# toothy smile&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;weapon&lt;/span&gt; &lt;span class="number"&gt;939&lt;/span&gt;    &lt;span class="comment"&gt;# fire breath&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;LargeDragon&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Creature&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="number"&gt;2000&lt;/span&gt;     &lt;span class="comment"&gt;# even tougher&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;strength&lt;/span&gt; &lt;span class="number"&gt;821&lt;/span&gt;  &lt;span class="comment"&gt;# bulging veins&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;charisma&lt;/span&gt; &lt;span class="number"&gt;715&lt;/span&gt;  &lt;span class="comment"&gt;# much more vile&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;weapon&lt;/span&gt; &lt;span class="number"&gt;1213&lt;/span&gt;   &lt;span class="comment"&gt;# scorching flames&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Gwythaint&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Creature&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="number"&gt;250&lt;/span&gt;      &lt;span class="comment"&gt;# a large bird&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;strength&lt;/span&gt; &lt;span class="number"&gt;340&lt;/span&gt;  &lt;span class="comment"&gt;# eats meat&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;charisma&lt;/span&gt; &lt;span class="number"&gt;191&lt;/span&gt;  &lt;span class="comment"&gt;# ugly&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;weapon&lt;/span&gt; &lt;span class="number"&gt;524&lt;/span&gt;    &lt;span class="comment"&gt;# beak &amp;amp; talons&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;LargeGwythaint&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Creature&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;life&lt;/span&gt; &lt;span class="number"&gt;612&lt;/span&gt;      &lt;span class="comment"&gt;# gigantic!&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;strength&lt;/span&gt; &lt;span class="number"&gt;429&lt;/span&gt;  &lt;span class="comment"&gt;# massive wings&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;charisma&lt;/span&gt; &lt;span class="number"&gt;95&lt;/span&gt;   &lt;span class="comment"&gt;# extremely ugly&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;weapon&lt;/span&gt; &lt;span class="number"&gt;842&lt;/span&gt;    &lt;span class="comment"&gt;# razor sharp talons&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now go read Why the Lucky Stiff&amp;#8217;s article &lt;a href="http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html"&gt;&lt;em&gt;Seeing Metaclasses Clearly&lt;/em&gt;&lt;/a&gt; for more metaprogramming madness.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/4ODslRjRgKU" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/4ODslRjRgKU/" />
          <published>2006-09-22T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/09/22/class-level-instance-variables//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/09/12/ruby-site-live//</id>
          <title type="html">Ruby Web Site Goes Live!</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://ruby-lang.org/" title="Ruby Web Site"&gt;&lt;img src ="http://wiseheartdesign.com/assets/2006/12/2/ruby-lang-org-screenshot.png" width="453" height="150" alt="Ruby Web Site" title="Ruby Web Site" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;At long last, &lt;a href="http://ruby-lang.org"&gt;the Ruby site is live&lt;/a&gt;! The site is the collective work of the &lt;a href="http://rubyidentity.org"&gt;Ruby Visual Identity Team&lt;/a&gt; and is powered by &lt;a href="http://radiantcms.org"&gt;Radiant&lt;/a&gt;. Kudos to everyone involved! &lt;a href="http://www.ruby-lang.org/en/news/2006/09/12/site-launch-at-last/"&gt;Full write up here.&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/5WA47khdQgY" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/5WA47khdQgY/" />
          <published>2006-09-12T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/09/12/ruby-site-live//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/07/27/rails-and-vim//</id>
          <title type="html">Rails and Vim</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <content type="html">&lt;p&gt;This week I&amp;#8217;ve been doing some work for a client where the most of the development needs to take place on Linux. It&amp;#8217;s possible that I could have taken the time to stub out most of the code that depends on Linux, but instead I decided to do what I needed to do with with Vim over &lt;span class="caps"&gt;SSH&lt;/span&gt;. Vim is perfect for this kind of work. It&amp;#8217;s not quite as friendly for Rails development as something like &lt;a href="http://macromates.com"&gt;Textmate&lt;/a&gt;, but once you get used to it it can be quite useful. The fact that it works well remotely is a huge plus.&lt;/p&gt;
&lt;p&gt;One of the problems I have with Vim is that it&amp;#8217;s hard to open a bunch of related files. Vim doesn&amp;#8217;t know much about Rails so opening a model and an associated test case is difficult. I often have to type something like this:&lt;/p&gt;
&lt;pre class="code bash-code"&gt;&lt;code&gt;$ vi -o app/models/user.rb test/unit/user_test.rb&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#8217;s even more verbose when I want to open all of the files associated with a controller. Imagine what I have to type when I want to open several controllers!&lt;/p&gt;
&lt;p&gt;Today, I got tired of doing all that typing and created a small command to make this easier for me.  I put it in a file which I named &lt;code&gt;edit&lt;/code&gt; and placed it in my home directory&amp;#8217;s &lt;code&gt;bin&lt;/code&gt; (which is in my environment&amp;#8217;s path). Here&amp;#8217;s the source:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="comment"&gt;#!/usr/bin/env ruby&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="constant"&gt;ARGV&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;empty?&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;usage: &lt;span class="expr"&gt;#{File.basename($0)}&lt;/span&gt; string&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;  Scans related Rails directories for &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;files begining with string &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;  and opens them in vi.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;exit&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;files&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;ignore&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[/&lt;/span&gt;&lt;span class="regex"&gt;CVS$&lt;/span&gt;&lt;span class="punct"&gt;/]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;# Find models or controllers that match args&lt;/span&gt;&lt;br /&gt;&lt;span class="constant"&gt;ARGV&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;arg&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;models&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Dir&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;app/models/&lt;span class="expr"&gt;#{arg}&lt;/span&gt;*&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;controllers&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Dir&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;app/controllers/&lt;span class="expr"&gt;#{arg}&lt;/span&gt;*&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;files&lt;/span&gt; &lt;span class="punct"&gt;+=&lt;/span&gt; &lt;span class="ident"&gt;models&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;controllers&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;# Remove duplicates&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;files&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort!&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;uniq!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;# Add unit tests for models&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;files&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;grep&lt;/span&gt;&lt;span class="punct"&gt;(%r{&lt;/span&gt;&lt;span class="regex"&gt;app/models/(.*?).rb&lt;/span&gt;&lt;span class="punct"&gt;})&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;tests&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Dir&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;test/unit/&lt;span class="expr"&gt;#{$1}&lt;/span&gt;_test.rb&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;files&lt;/span&gt; &lt;span class="punct"&gt;+=&lt;/span&gt; &lt;span class="ident"&gt;tests&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;# Add views and functional tests for controllers&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;files&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;grep&lt;/span&gt;&lt;span class="punct"&gt;(%r{&lt;/span&gt;&lt;span class="regex"&gt;app/controllers/(.*?)_controller.rb&lt;/span&gt;&lt;span class="punct"&gt;})&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;views&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Dir&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;app/views/&lt;span class="expr"&gt;#{$1}&lt;/span&gt;/*&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;tests&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Dir&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;test/functional/&lt;span class="expr"&gt;#{$1}&lt;/span&gt;_controller_test.rb&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;files&lt;/span&gt; &lt;span class="punct"&gt;+=&lt;/span&gt; &lt;span class="ident"&gt;views&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;tests&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;# Add views and fixtures for mailers&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;files&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;grep&lt;/span&gt;&lt;span class="punct"&gt;(%r{&lt;/span&gt;&lt;span class="regex"&gt;app/models/(.*?_mailer).rb&lt;/span&gt;&lt;span class="punct"&gt;})&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;views&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Dir&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;app/views/&lt;span class="expr"&gt;#{$1}&lt;/span&gt;/*&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;fixtures&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Dir&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;test/fixtures/&lt;span class="expr"&gt;#{$1}&lt;/span&gt;/*&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;files&lt;/span&gt; &lt;span class="punct"&gt;+=&lt;/span&gt; &lt;span class="ident"&gt;views&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;fixtures&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;# Again remove duplicates&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;files&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort!&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;uniq!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;# Remove files that match ignore list&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;files&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;delete_if&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;filename&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;result&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;ignore&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;filename&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="ident"&gt;i&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;result&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;break&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;result&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;system&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;vi -o &lt;span class="expr"&gt;#{files.join(' ')}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I can type:&lt;/p&gt;
&lt;pre class="code bash-code"&gt;&lt;code&gt;$ edit account_c&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it will open &lt;code&gt;account_controller.rb&lt;/code&gt;, &lt;code&gt;account_controller_test.rb&lt;/code&gt;, and all of its views. I can also type:&lt;/p&gt;
&lt;pre class="code bash-code"&gt;&lt;code&gt;$ edit account_m&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it will open &lt;code&gt;account_mailer.rb&lt;/code&gt;, &lt;code&gt;account_mailer_test.rb&lt;/code&gt;, all of its views, and all of its fixtures.&lt;/p&gt;
&lt;p&gt;Much, much better.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/TTq4QSGlsLI" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/TTq4QSGlsLI/" />
          <published>2006-07-27T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/07/27/rails-and-vim//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/07/21/speaking-at-ruby-conf-in-october//</id>
          <title type="html">Speaking at Ruby Conf in October!</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <content type="html">&lt;p&gt;My &lt;a href="http://rubyconf.org"&gt;Ruby Conf&lt;/a&gt; talk proposal was accepted! This will give me a chance to show of &lt;a href="http://radiantcms.org"&gt;Radiant&lt;/a&gt; to the rest of the Ruby community in October. From the talk description:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Say the words &amp;#8220;content management&amp;#8221; in the ears of nearly any Web developer and they will likely frown and complain that most content management systems are too complicated, difficult to setup, or not very flexible. They have good reason to complain. Content management systems are notorious for containing every feature, except for the kitchen sink!&lt;/p&gt;
&lt;p&gt;Enter Radiant&amp;#8212;a light-weight content management system designed from the ground up to be simple to use, while remaining flexible and powerful. It&amp;#8217;s a content management system that has borrowed much from Textpattern and MovableType while seeking to be more than a simple a blogging engine.&lt;/p&gt;
&lt;p&gt;Radiant features:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;The ability to arrange pages in a hierarchy&lt;/li&gt;
	&lt;li&gt;Layouts that can be used to apply a common look to a Web site&lt;/li&gt;
	&lt;li&gt;Snippets that are similar to partials or includes&lt;/li&gt;
	&lt;li&gt;Pages which are defined in multiple parts (body, extended, sidebar, etc&amp;#8230;)&lt;/li&gt;
	&lt;li&gt;A custom tagging language (&lt;a href="http://radius.rubyforge.org"&gt;radius&lt;/a&gt;)&lt;/li&gt;
	&lt;li&gt;Special page-oriented plugins called behaviors&lt;/li&gt;
	&lt;li&gt;A simple user management/permissions system&lt;/li&gt;
	&lt;li&gt;Several domain specific languages which make it easy to write plugins&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In his talk John will talk about the design and discovery process he went through while building Radiant and cover the guiding philosophies behind it. He will also demonstrate installation and setup from a Gem and talk about how Radiant can be extended. You will discover the joys of Radiant&amp;#8217;s robust domain languages and revel in the ease with which you can create new content. He will also discuss how Radiant is being used on the new version of the main Ruby web site (&lt;a href="http://new.ruby-lang.org"&gt;http://ruby-lang.org&lt;/a&gt;) and explain how others are using it.&lt;/p&gt;
&lt;/blockquote&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/P2RjsZoBV98" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/P2RjsZoBV98/" />
          <published>2006-07-21T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/07/21/speaking-at-ruby-conf-in-october//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/07/14/reflections-on-rails-conf//</id>
          <title type="html">Reflections on Rails Conf 2006</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <content type="html">&lt;p&gt;It&amp;#8217;s been over two weeks since &lt;a href="http://railsconf.org"&gt;Rails Conf&lt;/a&gt; and I am only now finding time to write about it. Rails Conf is really the first technical conference I&amp;#8217;ve attended and I must say that I found the whole experience invigorating. Watching the Rails community grow over the past two years has been quite an education for me. Getting a chance to meet in Chicago with so many of the people involved in the community will be something I long remember.&lt;/p&gt;
&lt;p&gt;Probably the thing I valued most about the conference was the chance to hear more about the undergirding philosophies of Rails. This is what fascinates me about the Rails community. From the top to the bottom, the community is filled with people who are downright philosophical in their approach to software development. To people involved in the Rails community, software development shouldn&amp;#8217;t be the complicated mess that characterizes so many projects. Code should be beautiful&amp;#8212;-both in its utility and in its aesthetic. Rails developers&amp;#8217; guiding philosophy is a healthy mix of &lt;em&gt;utilitarianism&lt;/em&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;em&gt;idealism&lt;/em&gt;. In the Rails community it is called &lt;em&gt;pragmatism&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://scottraymond.net"&gt;Scott Raymond&lt;/a&gt; touched on this a bit in his talk on his work with Firewheel Design. He spoke about the principles of a man named &lt;a href="http://en.wikipedia.org/wiki/Vitruvius"&gt;Vitruvius&lt;/a&gt; who was an architect in the century before Christ. Vitruvius believed that there were three primary principles that governed good architecture (or design).&lt;/p&gt;
&lt;p&gt;The first was &lt;em&gt;firmitas&lt;/em&gt;. Firmitas is the latin word for &lt;a href="http://catholic.archives.nd.edu/cgi-bin/lookup.pl?stem=firmitas"&gt;firmness, stability; strength of mind, constancy&lt;/a&gt;. Vitruvius believed that the first principle of good design is that it must be structurally sound. What does it matter if the structure was beautiful if it collapsed because of poor construction? No, in order to be good the building must be structurally sound.&lt;/p&gt;
&lt;p&gt;The second principle of Vitruvius was what he called &lt;em&gt;utilitas&lt;/em&gt;. Utilitas is the latin for &lt;a href="http://www.perseus.tufts.edu/cgi-bin/ptext?doc=Perseus%3Atext%3A1999.04.0059%3Aentry%3D%2349997"&gt;usefulness or utility&lt;/a&gt;. Today we might use the word &lt;em&gt;usable&lt;/em&gt; and talk about the importance of usability. According to Vitruvius, a designer should strive to not only make the building structurally sound, but also useful. For if the building lasted a millennium, but was impractical for the purpose for which it was designed, what was the use?&lt;/p&gt;
&lt;p&gt;The final princple of Vitruvius was &lt;em&gt;venustas&lt;/em&gt;. The word venustas is from the same latin root that thename Venus comes from (Venus was the Roman goddess of love and beauty). Venustas means &lt;a href="http://catholic.archives.nd.edu/cgi-bin/lookup.pl?stem=venustas"&gt;loveliness , charm, or attractiveness&lt;/a&gt;. According to Vitruvius a building failed to achieve the ideal if it was not also beautiful.&lt;/p&gt;
&lt;p&gt;These three principles together (firmitas, utilitas, and venustas) form what I would call the Rails &lt;em&gt;world view&lt;/em&gt;. The Rails community has a great focus on the utility of what they are doing. They are very conscious that code, particularly code that is introduced into the core, must have a clear purpose. They don&amp;#8217;t spend a lot of time on features that people visualize as being merely &amp;#8220;nice&amp;#8221;. Every feature must help solve the practical problem at hand. At the same time the Rails community has spent a great deal of time developing a sense for the aesthetics of good design. So while focusing on the utility of what they are doing they don&amp;#8217;t lose site of the ideal.&lt;/p&gt;
&lt;p&gt;David spoke some about this a talk he gave at &lt;a href="http://snakesandrubies.com"&gt;Snakes and Rubies&lt;/a&gt; back in December called &lt;a href="http://media.rubyonrails.org/presentations/pursuitofbeauty.pdf"&gt;&lt;em&gt;Pursuing Beauty with Ruby on Rails&lt;/em&gt;&lt;/a&gt;. I heard echos of this throughout the conference. His &lt;a href="http://www.loudthinking.com/arc/000593.html"&gt;keynote&lt;/a&gt; about incorporating a RESTful approach to Web services into Rails is a great example of this. On the one hand you have the ideal of the &lt;span class="caps"&gt;REST&lt;/span&gt; architecture and on the other you have the utilitarian question: &lt;em&gt;Does it really make my life any easier?&lt;/em&gt; In his talk David discussed how he struggled with these two perspectives only to have it somewhat resolved as he realized that RESTful architecture often did lead to better, more robust design (which he went on to demonstrate).&lt;/p&gt;
&lt;p&gt;I think that the great test for the Rails community in the coming months (and years) will be over whether we are able to maintain a healthy balance between beauty and utility. It was certainly fun to see this played out in the conference. I hope to be able to join in again next year.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/vMUpaPgAxYg" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/vMUpaPgAxYg/" />
          <published>2006-07-14T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/07/14/reflections-on-rails-conf//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/06/18/preparations-for-rails-conf//</id>
          <title type="html">Preparations for Rails Conf 2006</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://wiseheartdesign.com/images/card.gif"&gt;&lt;img src="http://wiseheartdesign.com/images/card_t.gif" class="float-right no-border" alt="" /&gt;&lt;/a&gt; I had fun today working on something I figure I&amp;#8217;ll need at &lt;a href="http://railsconf.org"&gt;Rails Conf&lt;/a&gt;: &lt;strong&gt;business cards!&lt;/strong&gt; Pictured right is the design I came up with. I especially like the tag-line: &lt;em&gt;Beautiful Code. Smart Design.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I decided to go with a pure black and white design because I wanted to print them on my parent&amp;#8217;s laser printer. (We have a bubble jet, but the results are hard to predict as it&amp;#8217;s a Lexmark.)&lt;/p&gt;
&lt;p&gt;The nice thing about the constraint of having to design the business cards in black and white is that it forced me to concentrate on the shapes and balance of the design vs. the color.&lt;/p&gt;
&lt;p&gt;One thing I&amp;#8217;ve been thinking about lately is how constraints can often push you to higher levels of achievement. I thought about this as I worked on a &lt;a href="http://demo.radiantcms.org"&gt;default design for a Radiant blog&lt;/a&gt; last week. The challenge there was to create a design that didn&amp;#8217;t rely on images. Since Radiant doesn&amp;#8217;t support storing images in the database yet, I didn&amp;#8217;t want to add extra clutter to the public directory for an example template that a user may or may not choose to use. Working to keep the style of the template limited to what I could do with borders and backgrounds certainly expanded my mind to some different techniques. Constraints can do that&amp;#8212;if you let them.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.cafepress.com/pulchritude.61223201"&gt;&lt;img src="http://wiseheartdesign.com/images/i-heart-ruby.jpg" class="float-right no-border" alt="" /&gt;&lt;/a&gt; &lt;a href="http://www.cafepress.com/pulchritude.61223201"&gt;Something else&lt;/a&gt; arrived this week that I&amp;#8217;m going to need at Rails Conf (pictured right). Just look at that beautiful ruby from the Ruby-Lang.org design! It makes me proud to be able to wear such a nice T-shirt.&lt;/p&gt;
&lt;p&gt;What are you bringing to Rails Conf?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/mVKn_WG6hjg" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/mVKn_WG6hjg/" />
          <published>2006-06-18T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/06/18/preparations-for-rails-conf//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/05/04/poor-man-s-site-stats//</id>
          <title type="html">Poor Man’s Site Stats</title>
          <updated>2009-09-23T21:31:50Z</updated>
          <content type="html">&lt;p&gt;One of the strange things about the normal TextDrive plan is that they don&amp;#8217;t provide any site statistics. Fooling around on the command line recently I came up with this:&lt;/p&gt;
&lt;pre class="code bash-code"&gt;&lt;code&gt;$ cat logs/access_log | awk '{print $1}' | sort | uniq | wc -l&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;538&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which tells me the number of unique IP addresses that have hit my site in the last day. Without getting too complicated I can also get the total number of unique visitors ever (or at least as far back as my logs go).&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s the code:&lt;/p&gt;
&lt;pre class="code bash-code"&gt;&lt;code&gt;$ (cat logs/access_log &amp;amp;&amp;amp; gzip -dc logs/access_log*.gz) | awk '{ print $1 }' | sort | uniq | wc -l&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3887&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this shows me the total number of unique visitors to &lt;a href="http://radiantcms.org/"&gt;RadiantCMS.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What are you doing on &lt;a href="http://textdrive.com"&gt;TextDrive&lt;/a&gt;?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/bnYpD0oi3Lc" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/bnYpD0oi3Lc/" />
          <published>2006-05-04T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/05/04/poor-man-s-site-stats//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/05/01/radiantcms-org-is-live//</id>
          <title type="html">RadiantCMS.org is Live!</title>
          <updated>2009-09-23T21:31:50Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://radiantcms.org"&gt;&lt;img class="float-left" src="http://static.flickr.com/47/138653223_e8eef6e3fb_m.jpg" width="240" height="228" alt="radiantcms.org" /&gt;&lt;/a&gt; After many months of hard work it&amp;#8217;s wonderful to have something to show you. Today, I released Radiant into the wild with &lt;a href="http://radiantcms.org"&gt;its own Web site&lt;/a&gt;. It&amp;#8217;s actually been around since last week, but only a small group of people have known of its existence.&lt;/p&gt;
&lt;p style="clear:left; padding-top: 1em;"&gt;The site sports a couple of sections that might be of interest to you:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://radiantcms.org/demo/"&gt;A public demo&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://dev.radiantcms.org/"&gt;A Trac powered dev site&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://radiantcms.org/mailing-list/"&gt;A mailing list&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://radiantcms.org/"&gt;A weblog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Oh, and did I mention that the main site is actually powered by Radiant? I&amp;#8217;ve taken a few &lt;a href="http://www.flickr.com/photos/86701100@N00/sets/72057594122572739/"&gt;screen shots&lt;/a&gt; of Radiant and the Web site and have posted them on Flickr.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/MEhM-dFPl5M" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/MEhM-dFPl5M/" />
          <published>2006-05-01T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/05/01/radiantcms-org-is-live//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/04/25/rails-documentation-in-chm-format//</id>
          <title type="html">Rails Documentation in CHM Format</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <content type="html">&lt;p&gt;Delynn Berry just released another version of the Rails Documentation in &lt;span class="caps"&gt;CHM&lt;/span&gt; format:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://delynnberry.com/pages/rails-chm-documentation"&gt;http://delynnberry.com/pages/rails-chm-documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;CHM&lt;/span&gt; format is Microsoft&amp;#8217;s proprietary help format for Windows. It allows them to package up an entire Web site of information in a searchable package.&lt;/p&gt;
&lt;p&gt;Unfortunately&amp;#8212;er&amp;#8212;fortunately, I&amp;#8217;m on a Mac now. This makes viewing files in &lt;span class="caps"&gt;CHM&lt;/span&gt; format a little tricky. After a quick google search I was able to locate a couple of programs:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://xchm.sourceforge.net/"&gt;xCHM&lt;/a&gt; is nice, but doesn&amp;#8217;t display documents using their original stylesheets.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://chmox.sourceforge.net/"&gt;Chmox&lt;/a&gt; allows documents to be displayed with their original stylesheets, yet allows only the viewing of &lt;span class="caps"&gt;CHM&lt;/span&gt; documents, not searching.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://sourceforge.net/projects/chamonix/"&gt;Chamonix&lt;/a&gt; happens to handle both search and display admirably, though the UI isn&amp;#8217;t as spiffy as Chmox&amp;#8217;s.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Are there other options?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/GyIbp2icgA4" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/GyIbp2icgA4/" />
          <published>2006-04-25T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/04/25/rails-documentation-in-chm-format//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/03/11/ruby-blue-textmate-theme//</id>
          <title type="html">Ruby Blue Textmate Theme</title>
          <updated>2009-10-22T12:38:18Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://johnwlong.com/downloads/RubyBlue.tmTheme"&gt;&lt;img src="http://wiseheartdesign.com/images/rubyblue.jpg" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When did the initial design for the Ruby-Lang Web site a year ago I created a Vim theme that mirrored the colors used in the little code window of the design. Times have changed and I am now an avid Mac user. With the change in operating system I&amp;#8217;ve also picked up another text editor called &lt;a href="http://macromates.com"&gt;Textmate&lt;/a&gt;. Today I decided to spend a little time on a theme for Textmate that mirrored the Ruby Lang design in the same way that my Vim theme did.&lt;/p&gt;
&lt;p&gt;To install:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;a href="http://github.com/jlong/rubyblue/raw/master/RubyBlue.tmTheme"&gt;Download the Ruby Blue theme&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Copy it into: &lt;tt&gt;/Applications/TextMate.app/Contents/SharedSupport/Themes/&lt;/tt&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update!&lt;/strong&gt; The RubyBlue theme for various editors (including the RubyBlue Vim theme) is now hosted on &lt;a href="http://github.com/jlong/rubyblue"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/BSE8xAgFzWA" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/BSE8xAgFzWA/" />
          <published>2006-03-11T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/03/11/ruby-blue-textmate-theme//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/03/06/jim-weirich-on-continuations//</id>
          <title type="html">Jim Weirich on Continuations</title>
          <updated>2009-09-23T21:31:50Z</updated>
          <content type="html">&lt;p&gt;I attended a &lt;a href="http://ruby.meetup.com/55/"&gt;Chicago Area Ruby Group&lt;/a&gt; meetup this evening. Joe O&amp;#8217;brien was able to lure &lt;a href="http://onestepback.org"&gt;Jim Weirich&lt;/a&gt; up for the meeting to teach some deep Ruby magic. His topic was &lt;a href="http://onestepback.org/articles/callcc/"&gt;&lt;em&gt;Demystifying Continuations&lt;/em&gt;&lt;/a&gt;. I throughly enjoyed his presentation style. He had a great mix of entertaining illustrations coupled with hands-on coding exercises.&lt;/p&gt;
&lt;p&gt;He started off with a demonstration of the &lt;a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/91023"&gt;Amb library&lt;/a&gt; (Amb is an abbreviation of &amp;#8220;ambiguous&amp;#8221;), followed by a couple of other examples, and then gave us a half hour to pair up and write our own version of &lt;code&gt;catch&lt;/code&gt; and &lt;code&gt;throw&lt;/code&gt; using continuations (which was really invigorating&amp;#8212;none of us finished, but a few people got pretty close). After that he had a lucid explanation of continuations based on &lt;a href="http://zelda.com/universe/game/ocarinatime/"&gt;one of the Zelda games&lt;/a&gt; where the game was completed by going back and forth in time (continuations are a sort of programming &amp;#8220;time-machine&amp;#8221;). He then finished the talk with a nice example of a console application and a similar web application (which used continuations to mimic the feel that you got in the console).&lt;/p&gt;
&lt;p&gt;All in all a very good talk. I have a much better understanding of what continuations are (though I&amp;#8217;m still not sure that I&amp;#8217;m smart enough to know when to use one).&lt;/p&gt;
&lt;p&gt;I had to ask Jim at the end of the talk if he&amp;#8217;d implemented the &lt;a href="http://onestepback.org"&gt;&lt;code&gt;one_step_back&lt;/code&gt;&lt;/a&gt; function using continuations or not! He just laughed.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/qiRI_jimFMk" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/qiRI_jimFMk/" />
          <published>2006-03-06T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/03/06/jim-weirich-on-continuations//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/03/04/xara-open-sourced//</id>
          <title type="html">Xara Open Sourced!</title>
          <updated>2009-09-23T21:31:50Z</updated>
          <content type="html">&lt;p&gt;Wow. This is good news! &lt;a href="http://xara.com"&gt;Xara&lt;/a&gt;, my favorite vector graphics program, &lt;a href="http://www.xaraxtreme.org/news/11-10-05.html"&gt;has been open sourced&lt;/a&gt;. This means that there will one day be a Mac version of Xara!&lt;/p&gt;
&lt;p&gt;My major regret about moving to Mac last fall was having to leave Xara behind. I figured I would have to get used to Adobe Illustrator or another such program. Now it looks like I won&amp;#8217;t have to. Xara, Ltd. has announced plans to open source the product. I&amp;#8217;m not sure what this will mean for Xara (the company), but it sounds like Linux will finally have a decent vector graphics program. They have already started work on the Mac version of the product as well.&lt;/p&gt;
&lt;p&gt;Simply put, Xara is the best graphics program on the market today (in my opinion). It&amp;#8217;s speed and ease of use is unrivaled by any other graphics program (including Illustrator). I haven&amp;#8217;t been able to figure it out, but for some reason Xara has not been able to gain much market share among users in relation to Adobe Illustrator and Freehand. Perhaps it has something to do with the fact that Xara, Ltd.&amp;#8216;s only major program is a vector graphics program. They don&amp;#8217;t have the ability to offer a suite of applications as Adobe and Macromedia have had.&lt;/p&gt;
&lt;p&gt;Hopefully, the move to open source will be good for the program. It will certainly be good for the users.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/OyHIUicZsio" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/OyHIUicZsio/" />
          <published>2006-03-04T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/03/04/xara-open-sourced//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/02/14/radius-0-0-2//</id>
          <title type="html">Radius 0.0.2 Released</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <content type="html">&lt;p&gt;I just released the next version of &lt;a href="http://radius.rubyforge.org"&gt;Radius&lt;/a&gt;. This is a minor update (mainly a little refactoring). From the change log:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Refactored Parser to use &lt;tt&gt;Context#render_tag&lt;/tt&gt; instead of &lt;tt&gt;#send&lt;/tt&gt; when rendering tags defined on a context.&lt;/li&gt;
	&lt;li&gt;&lt;tt&gt;UndefinedTagError&lt;/tt&gt; is now thrown when &lt;tt&gt;Parser&lt;/tt&gt; tries to render a tag which doesn&amp;#8217;t exist on a context.&lt;/li&gt;
	&lt;li&gt;Added &lt;tt&gt;Context#tag_missing&lt;/tt&gt; which works like &lt;tt&gt;#method_method&lt;/tt&gt; missing on &lt;tt&gt;Object&lt;/tt&gt;, but is tag specific.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; If you would like to help with the development of Radius, you can contribute to the project on GitHub: &lt;a href="http://github.com/jlong/radius/"&gt;http://github.com/jlong/radius&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/aPIzCA91bSk" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/aPIzCA91bSk/" />
          <published>2006-02-14T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/02/14/radius-0-0-2//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/01/31/behaviors//</id>
          <title type="html">Radiant CMS Behaviors</title>
          <updated>2009-09-23T21:31:50Z</updated>
          <content type="html">&lt;p&gt;&lt;img src="http://wiseheartdesign.com/images/radiant-multi-lingual.gif" class="float-left" alt="" /&gt; One of the features I&amp;#8217;m really excited about in the &lt;span class="caps"&gt;CMS&lt;/span&gt; I&amp;#8217;m building for &lt;a href="http://ruby-lang.org"&gt;ruby-lang.org&lt;/a&gt; is support for what I am calling &amp;#8220;behaviors&amp;#8221;. A behavior is a Ruby mixin of sorts that alters the way a page behaves on the site. It can do everything from changing the way content is rendered to setting headers on the response. Think of a behavior as a special plugin for pages.&lt;/p&gt;
&lt;p&gt;This morning I finished coding a behavior for the Ruby site that will redirect you to a sub-folder of the site based on your prefered language (a browser configurable setting).&lt;/p&gt;
&lt;p&gt;Above you can see that I&amp;#8217;ve already started testing it. The &lt;span class="caps"&gt;CMS&lt;/span&gt; seems to be handling Japanese rather well.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/gExTLT7d5bA" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/gExTLT7d5bA/" />
          <published>2006-01-31T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/01/31/behaviors//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/01/28/test-helpers-for-rails//</id>
          <title type="html">Test Helpers for Rails</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <content type="html">&lt;p&gt;In Rails, I occasionally find myself needing to share some specific functionality between tests. I usually take advantage of Ruby&amp;#8217;s remarkable modules and make a module which defines the functionality that I need. I then use the &lt;tt&gt;include&lt;/tt&gt; class method to import the functionality into the test case where I need it. When I create a module like this I call it a test helper.&lt;/p&gt;
&lt;p&gt;For example, in my current project I have a &lt;tt&gt;Page&lt;/tt&gt; model object for which I created the following test helper (abbreviated):&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;module &lt;/span&gt;&lt;span class="module"&gt;PageTestHelper&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="constant"&gt;VALID_PAGE_PARAMS&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:title&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;New Page&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:slug&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;page&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;New Page&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:status_id&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:parent_id&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;page_params&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;options&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{})&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;params&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;VALID_PAGE_PARAMS&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;dup&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;merge!&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:title&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="attribute"&gt;@page_title&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="attribute"&gt;@page_title&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;merge!&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:status_id&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;merge!&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a test case, when I need access to the methods on the &lt;tt&gt;PageTestHelper&lt;/tt&gt; module I just include it:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;test/helpers/page_test_helper&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;PageTest&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Test&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Unit&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;TestCase&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;include&lt;/span&gt; &lt;span class="constant"&gt;PageTestHelper&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;setup&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@page&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Page&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt; &lt;span class="ident"&gt;page_params&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="comment"&gt;# etc...&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My naming convention for test helpers is that they always include &lt;tt&gt;TestHelper&lt;/tt&gt; in their module name. Sometimes I forget to include &lt;tt&gt;Test&lt;/tt&gt; in the name when I include it in a test case which causes an error. Sometimes I forget to require the file which the test helper is stored in which also causes an error. This happens quite frequently.&lt;/p&gt;
&lt;p&gt;Recently, I decided to make things easier on myself. In &lt;tt&gt;test_helper.rb&lt;/tt&gt; (found in the &lt;tt&gt;test&lt;/tt&gt; directory of every rails project) I inserted the following code:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;pathname&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;span class="constant"&gt;TEST_ROOT&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Pathname&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expand_path&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;dirname&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;__FILE__&lt;/span&gt;&lt;span class="punct"&gt;))&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;cleanpath&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;true&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;# Auto require test helpers&lt;/span&gt;&lt;br /&gt;&lt;span class="constant"&gt;Dir&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="constant"&gt;TEST_ROOT&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;/helpers/**/*_helper.rb&lt;/span&gt;&lt;span class="punct"&gt;'].&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;helper&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="ident"&gt;helper&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also, amongst the other code that modifies &lt;tt&gt;Test::Unit::TestCase&lt;/tt&gt; in &lt;tt&gt;test_helper.rb&lt;/tt&gt; I added a &lt;tt&gt;test_helper&lt;/tt&gt; class method:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="comment"&gt;# Class method for test helpers&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.test_helper&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="global"&gt;$1&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;^(.*?)_test_helper$&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;constant&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Inflector&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;constantize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;Inflector&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;camelize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="constant"&gt;Inflector&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;singularize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;_test_helper&lt;/span&gt;&lt;span class="punct"&gt;'))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;class_eval&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;include&lt;/span&gt; &lt;span class="ident"&gt;constant&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was my first chance to use the marvelous &lt;tt&gt;Inflector&lt;/tt&gt; class that Rails provides. It certainly makes it much easier to write class methods that work with symbols.&lt;/p&gt;
&lt;p&gt;Now, when I need to use a test helper in a test case I do something like this:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;PageTest&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Test&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Unit&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;TestCase&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;test_helper&lt;/span&gt; &lt;span class="symbol"&gt;:pages&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;setup&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@page&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Page&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt; &lt;span class="ident"&gt;page_params&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="comment"&gt;# etc...&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Meta-programming is marvelous. I no longer need to remember to require my test helpers and the &lt;tt&gt;test_helper&lt;/tt&gt; class method removes the verbosity from the &lt;tt&gt;include&lt;/tt&gt;. Much, much better.&lt;/p&gt;
&lt;p&gt;How are you making testing easier for yourself in Rails?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/hull_T28DeU" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/hull_T28DeU/" />
          <published>2006-01-28T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/01/28/test-helpers-for-rails//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/01/22/introducing-radius//</id>
          <title type="html">Introducing Radius</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <content type="html">&lt;p&gt;I&amp;#8217;m pleased to announce the first release of Radius&amp;#8212;a small, but powerful template language for Ruby similar to the ones used in &lt;a href="http://www.movabletype.org"&gt;MovableType&lt;/a&gt; and &lt;a href="http://www.textpattern.com"&gt;TextPattern&lt;/a&gt;. It uses tags similar to &lt;span class="caps"&gt;HTML&lt;/span&gt;, but can be used to generate any form of plain text (&lt;span class="caps"&gt;XML&lt;/span&gt;, e-mail, etc&amp;#8230;).&lt;/p&gt;
&lt;p&gt;Check out the documentation at:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://radius.rubyforge.org"&gt;http://radius.rubyforge.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Or get started with the gem right away:&lt;/p&gt;
&lt;pre class="code bash-code"&gt;&lt;code&gt;$ gem install radius&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Radius was conceived and coded by the 3 founding members of the Chicago Area Ruby Group (myself, Brian Young, and Ryan Platte).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Radius has moved to Github: &lt;a href="http://github.com/jlong/radius"&gt;http://github.com/jlong/radius&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/PWA8tiCY9U0" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/PWA8tiCY9U0/" />
          <published>2006-01-22T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/01/22/introducing-radius//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/01/16/testing-rails-validations//</id>
          <title type="html">Testing Rails Validations</title>
          <updated>2009-09-23T21:31:48Z</updated>
          <content type="html">&lt;p&gt;Today, I extracted some code from an older &lt;a href="https://secure.iblp.org/iblp/discipleship/dailysuccess/enroll/now/"&gt;&lt;span class="caps"&gt;IBLP&lt;/span&gt; project&lt;/a&gt; and polished it up a bit for use on the Ruby Web site.  It makes it quite easy to test validations on model objects in &lt;a href="http://rubyonrails.com"&gt;Rails&lt;/a&gt;. I present:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://johnwlong.com/downloads/validation_helper.rb"&gt;validation_helper.rb&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When you include &lt;tt&gt;ValidationTestHelper&lt;/tt&gt; into your test case you can access to two additional assertions: &lt;tt&gt;assert_valid&lt;/tt&gt; and &lt;tt&gt;assert_invalid&lt;/tt&gt;. Use them to assert that a model object is valid or invalid when a field is set to a certain value.&lt;/p&gt;
&lt;p&gt;For example, suppose you have a model object that looks like this:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Page&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;validates_presence_of&lt;/span&gt; &lt;span class="symbol"&gt;:title&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:slug&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:status_id&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:message&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;required&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;validates_format_of&lt;/span&gt; &lt;span class="symbol"&gt;:title&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:slug&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:with&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;^.*?&lt;span class="escape"&gt;\S&lt;/span&gt;.*?$&lt;/span&gt;&lt;span class="punct"&gt;/,&lt;/span&gt; &lt;span class="symbol"&gt;:message&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;required&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;validates_format_of&lt;/span&gt; &lt;span class="symbol"&gt;:slug&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:with&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;^[-_.A-Za-z]*$&lt;/span&gt;&lt;span class="punct"&gt;/,&lt;/span&gt; &lt;span class="symbol"&gt;:message&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;invalid format&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To test it, first set the &lt;tt&gt;@model&lt;/tt&gt; instance variable to an object that will validate &lt;em&gt;without&lt;/em&gt; errors:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="attribute"&gt;@model&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Page&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:title&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;New Page&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:slug&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;new-page&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;New Page&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:status_id&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Were you to call &lt;tt&gt;@model.valid?&lt;/tt&gt; at this point, it would return &lt;tt&gt;true&lt;/tt&gt;. But hold steady, you are ready to write your first assertion:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="ident"&gt;assert_invalid&lt;/span&gt; &lt;span class="symbol"&gt;:title&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;required&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt; &lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will assert that when the &lt;code&gt;title&lt;/code&gt; field on your &lt;tt&gt;@model&lt;/tt&gt; object is set to &lt;tt&gt;&amp;quot;&amp;quot;&lt;/tt&gt;, &lt;tt&gt;&amp;quot; &amp;quot;&lt;/tt&gt;, or &lt;tt&gt;nil&lt;/tt&gt; that a validation error occurs and that the error message is set to &amp;#8220;required&amp;#8221;. Note that the first two parameters are for the field name and message, while the parameters at the end are all values to test.&lt;/p&gt;
&lt;p&gt;The next assertion, &lt;tt&gt;assert_valid&lt;/tt&gt;, is useful for testing that an object should be valid when when a field is set to a value or series of values. For example, to test the regular expression that is being used to validate the &lt;tt&gt;slug&lt;/tt&gt; field we can do:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="ident"&gt;assert_valid&lt;/span&gt; &lt;span class="symbol"&gt;:slug&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;abc&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;abcd-efg&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;abcd_efg&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;abc.html&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will set the &lt;tt&gt;slug&lt;/tt&gt; attribute on the &lt;tt&gt;@model&lt;/tt&gt; object to &lt;tt&gt;&amp;#8216;abc&amp;#8217;&lt;/tt&gt;, &lt;tt&gt;&amp;#8216;abcd-efg&amp;#8217;&lt;/tt&gt;, &lt;tt&gt;&amp;#8216;abcd-efg&amp;#8217;&lt;/tt&gt;, and &lt;tt&gt;&amp;#8216;abc.html&amp;#8217;&lt;/tt&gt;. Each time it will check to see if the model is valid with the new value. If it is not for any one of the values, the assertion will fail.&lt;/p&gt;
&lt;p&gt;Pretty nifty, eh?&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s an entire test method for all of the validations shown in the model above:&lt;/p&gt;
&lt;pre class="code ruby-code"&gt;&lt;code&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test_validations&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="attribute"&gt;@model&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Page&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:title&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;New Page&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:slug&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;new-page&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;New Page&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="symbol"&gt;:status_id&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:title&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:slug&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;field&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;assert_invalid&lt;/span&gt; &lt;span class="ident"&gt;field&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;required&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt; &lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="keyword"&gt;end&lt;/span&gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;assert_valid&lt;/span&gt; &lt;span class="symbol"&gt;:slug&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;abc&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;abcd-efg&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;abcd_efg&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;abc.html&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;assert_invalid&lt;/span&gt; &lt;span class="symbol"&gt;:slug&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;invalid format&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;abcd efg&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;abcd/efg&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="ident"&gt;assert_invalid&lt;/span&gt; &lt;span class="symbol"&gt;:status_id&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;required&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Special thanks to Ryan Platte for his part in conceiving and coding &lt;tt&gt;ValidationTestHelper&lt;/tt&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/volqW7G6EWk" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/volqW7G6EWk/" />
          <published>2006-01-16T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/01/16/testing-rails-validations//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/01/12/javascript-bliss//</id>
          <title type="html">Javascript Bliss—Well, Not Exactly!</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <content type="html">&lt;p&gt;&lt;img src="http://wiseheartdesign.com/images/radiant-tabcontrol.gif" class="float-left" alt="" /&gt; After a couple of days hard work I&amp;#8217;ve finally got a tab control built that I like. It has been interesting, but mostly frustrating.&lt;/p&gt;
&lt;p&gt;I haven&amp;#8217;t worked enough with Javascript to be really comfortable with it yet. Each time I do something with it I find it frustrating. My brief brushes with it have been too short for me to attain a good level of proficiency with it.&lt;/p&gt;
&lt;p&gt;The first couple of days with a new language can be very frustrating as you are learning the ins and outs. Much of the frustration comes because of the cryptic error messages that are being thrown your way every time you do something creative. Your frustration lessons substantially as you actually learn what the error messages mean, but alas, that doesn&amp;#8217;t help the beginner.&lt;/p&gt;
&lt;p&gt;One of the blessings for me this time has been delving into &lt;a href="http://conio.net/"&gt;Sam Stephenson&amp;#8217;s&lt;/a&gt; amazing Prototype library. With a little sytatic sugar He almost makes Javascript feel like &lt;a href="http://ruby-lang.org"&gt;Ruby&lt;/a&gt;. He makes clever use of hashes to give you the impression that you are doing Object-Oriented programming and even turns anonymous functions into Ruby-like blocks. Javascript with Prototype is still very verbose compared to Ruby, but it is much, much nicer.&lt;/p&gt;
&lt;p&gt;One of the hard things about Prototype is that it doesn&amp;#8217;t come with any documentation. A &lt;a href="http://www.sergiopereira.com/articles/prototype.js.html"&gt;couple&lt;/a&gt; &lt;a href="http://particletree.com/features/quick-guide-to-prototype/"&gt;of&lt;/a&gt; &lt;a href="http://encytemedia.com/blog/articles/2005/12/07/prototype-meets-ruby-a-look-at-enumerable-array-and-hash"&gt;people&lt;/a&gt; have taken it upon themselves to document the library and there are even some nifty &lt;a href="http://dev.conio.net/repos/prototype/test/"&gt;unit tests&lt;/a&gt;, but the best knowledge still comes from &lt;a href="http://dev.conio.net/repos/prototype/dist/"&gt;reading the source&lt;/a&gt;. If you are anxious for more &lt;a href="http://www.prototypedoc.com/"&gt;this site&lt;/a&gt; may be able to help, or, you can stay on the cutting edge by following the feed on &lt;a href="http://del.icio.us/search/?all=prototype+javascript"&gt;del.icio.us&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/Hu6OFZEsjhE" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/Hu6OFZEsjhE/" />
          <published>2006-01-12T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/01/12/javascript-bliss//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/01/06/rails-badges//</id>
          <title type="html">Rails Badges</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <content type="html">&lt;p&gt;Someone asked for &amp;#8220;I wish this site were powered by Rails&amp;#8221; badges on Ruby-Talk today so I thought I&amp;#8217;d oblige them:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://wiseheartdesign.com/images/i-wish-rails.gif" class="no-border" alt="" /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;img src="http://wiseheartdesign.com/images/i-wish-rails-grayscale.gif" class="no-border" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Enjoy! :-)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/dZT0DVT7bzk" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/dZT0DVT7bzk/" />
          <published>2006-01-06T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/01/06/rails-badges//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/01/05/creating-a-new-page//</id>
          <title type="html">Creating a New Page in Radiant CMS</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <content type="html">&lt;p&gt;&lt;img src="http://wiseheartdesign.com/images/radiant-new-page.gif" class="float-left" alt="" /&gt; Here&amp;#8217;s another comp for the Ruby Web site administration system.&lt;/p&gt;
&lt;p&gt;One of the aspects of a page that I hope to really leverage is this concept of sections. Each page will have multiple sections which contain appropriate content. You can see this on the tabs: &amp;#8220;Body&amp;#8221;, &amp;#8220;Expanded&amp;#8221;, &amp;#8220;Summary&amp;#8221;, and &amp;#8220;Sidebar&amp;#8221;. You will be able to add custom sections or use one of the predefined sections.&lt;/p&gt;
&lt;p&gt;When a page is rendered using a Template, the Template can render the sections however it chooses. Or, when a page&amp;#8217;s content is included in another page, the page will be able to choose to render specific sections and exclude others. For example a blog index could choose to render only the &amp;#8220;Summary&amp;#8221; section for each article.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/XHmjlTMvGvs" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/XHmjlTMvGvs/" />
          <published>2006-01-05T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/01/05/creating-a-new-page//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/01/05/first-look//</id>
          <title type="html">First Look at Radiant CMS</title>
          <updated>2009-09-23T21:31:49Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://wiseheartdesign.com/images/pages.gif"&gt;&lt;img src="http://wiseheartdesign.com/images/pages_t.gif" class="float-right" alt="" /&gt;&lt;/a&gt; I&amp;#8217;ve decided to follow &lt;a href="http://37signals.com/svn/archives2/the_interface_as_a_spec_including_stories_inline.php"&gt;37signals&amp;#8217; advice&lt;/a&gt; and draw out &amp;#8220;screens&amp;#8221; for the admin system of the Ruby site before I do any major coding.&lt;/p&gt;
&lt;p&gt;I spent the afternoon drawing a few screens out on paper. This evening I took one of the screens and fleshed it out in Fireworks. Pictured left is the final result. It&amp;#8217;s a comp of the first page you will see after you login. It reveals the main contours of the way I picture the &lt;span class="caps"&gt;CMS&lt;/span&gt; working.&lt;/p&gt;
&lt;p&gt;The first three tabs across the top are for the three main model objects: Pages, Templates, and Snippets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pages&lt;/strong&gt; are the meat of the system. Each page will store the Textile formated data for a physical page on the Web site. Pages will be able to contain other pages using a simple template language. It will be easy to use the template language to create a blog index which lists the most recent articles.&lt;/p&gt;
&lt;p&gt;Each page will also be able to specify a &lt;strong&gt;Template&lt;/strong&gt; with which it should be rendered. This should make it easy to repeat a look across several pages.&lt;/p&gt;
&lt;p&gt;Pages will also have the ability to include the content from &lt;strong&gt;Snippets&lt;/strong&gt;&amp;#8212;little bits of content that will be repeated accross several pages.&lt;/p&gt;
&lt;p&gt;I also spent some time today thinking about a name for my new &lt;span class="caps"&gt;CMS&lt;/span&gt;. I&amp;#8217;d like to use a term from the gemstone world. Scanning through the terms in a &lt;a href="http://www.zulumoon.com/glossary/R-glossary.htm"&gt;jewelry glossary&lt;/a&gt; I ran accross a couple of words that would make really good names.&lt;/p&gt;
&lt;p&gt;The first one that I liked was &amp;#8220;brilliant&amp;#8221;. Brilliant cut is the superman shaped gemstone. Brillaint &lt;span class="caps"&gt;CMS&lt;/span&gt; has a nice ring to it, but it does sound a little vain.&lt;/p&gt;
&lt;p&gt;The other option that I liked was &amp;#8220;radiant&amp;#8221;. Radiant cut is a squarish shape. I don&amp;#8217;t like the shape as much a brilliant cut, but the name is rather nice. Unless someone has other suggestions I think I am going to call it Radiant &lt;span class="caps"&gt;CMS&lt;/span&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/4GdnS59d1X8" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/4GdnS59d1X8/" />
          <published>2006-01-05T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/01/05/first-look//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/01/05/snakes-and-rubies-audio-and-video//</id>
          <title type="html">Snakes and Rubies Audio and Video</title>
          <updated>2009-09-23T21:31:50Z</updated>
          <content type="html">&lt;p&gt;&lt;a href="http://snakesandrubies.com/"&gt;&lt;img src="http://wiseheartdesign.com/images/snakes-and-rubies.gif" class="float-right no-border" alt="" /&gt;&lt;/a&gt; Jacob Kaplan-Moss just anounced that he has posted the audio and video from the &lt;a href="http://snakesandrubies.com/"&gt;Snakes and Rubies&lt;/a&gt; event!&lt;/p&gt;
&lt;p&gt;If you didn&amp;#8217;t hear about it the first time, Snakes and Rubies was a mini-conference of sorts that I helped coordinate for peole interested in &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt; and &lt;a href="http://rubyonrails.com/"&gt;Rails&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We invited &lt;a href="http://holovaty.com"&gt;Adrian Holovaty&lt;/a&gt; (lead developer of the Django project) and &lt;a href="http://www.loudthinking.com/"&gt;David Heinemeier Hansson&lt;/a&gt; (creator of Rails) to come and share with us about their work and the future of Web application development.&lt;/p&gt;
&lt;p&gt;The event was a blast and much was learned about the differences and similarities of Django and Rails. If you haven&amp;#8217;t already, I&amp;#8217;d encourage you to head on over to the &lt;a href="http://snakesandrubies.com/"&gt;Snakes and Rubies Web site&lt;/a&gt; and download the audio or video from the event.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; The Snakes and Rubies website is no longer online. You can download the audio and the video from the event on the Django project&amp;#8217;s website &lt;a href="http://www.djangoproject.com/snakesandrubies/"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/PsTMVk6_Hxc" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/PsTMVk6_Hxc/" />
          <published>2006-01-05T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/01/05/snakes-and-rubies-audio-and-video//</feedburner:origLink></entry>
      
    
      
        <entry>
          <id>http://wisheartdesign.com//articles/2006/01/02/testing-1-2-3-is-this-thing-on//</id>
          <title type="html">Testing 1-2-3… Is This Thing On?</title>
          <updated>2009-09-23T21:31:50Z</updated>
          <content type="html">&lt;p&gt;Testing 1-2-3&amp;#8230; Is This Thing On?&lt;/p&gt;
&lt;p&gt;Pardon the dust! I&amp;#8217;m in the midst of revamping this very Web site. If you see something out of place this is probably why. (Don&amp;#8217;t let that stop you from letting me know though.)&lt;/p&gt;
&lt;p&gt;You may have noticed that I&amp;#8217;ve added a &lt;a href="http://typo.leetsoft.com"&gt;Typo&lt;/a&gt; powered blog and some &lt;a href="http://wiseheartdesign.com/passion/"&gt;additional&lt;/a&gt; &lt;a href="http://wiseheartdesign.com/contact/"&gt;information&lt;/a&gt;. The old &lt;a href="http://wiseheartdesign.com/portfolio/"&gt;portfolio&lt;/a&gt; is still pretty much intact. I&amp;#8217;d like expand it with more information, but that will have to wait.&lt;/p&gt;
&lt;p&gt;The main reason for this update is the blog. Over the next month or two I&amp;#8217;m going to be working on the backend for the &lt;a href="http://redhanded.hobix.com/redesign2005/"&gt;new Ruby Web site&lt;/a&gt;. I wanted a place to chronicle my progress.&lt;/p&gt;
&lt;p&gt;Stay tuned for more.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/WiseheartDesign/~4/9c6DS5CXtBA" height="1" width="1"/&gt;</content>
          <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/WiseheartDesign/~3/9c6DS5CXtBA/" />
          <published>2006-01-02T00:00:00Z</published>
        <feedburner:origLink>http://wiseheartdesign.com//articles/2006/01/02/testing-1-2-3-is-this-thing-on//</feedburner:origLink></entry>
      
    
  
</feed>
