<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Steve Lorek</title>
 <link href="http://stevelorek.com/atom.xml" rel="self"/>
 <link href="http://stevelorek.com/"/>
 <updated>2015-08-20T16:20:12+00:00</updated>
 <id>http://stevelorek.com/</id>
 <author>
   <name>Steve Lorek</name>
   <email>steve@stevelorek.com</email>
 </author>

 
 <entry>
   <title>Service Objects: What They Are, and When to Use Them</title>
   <link href="http://stevelorek.com/service-objects.html"/>
   <updated>2013-03-13T00:00:00+00:00</updated>
   <id>http://stevelorek.com/service-objects</id>
   <content type="html">&lt;p&gt;There has been a lot of discussion within the Ruby community around the service objects pattern. The term &quot;service objects&quot; may be unfamiliar to even seasoned Rails developers, because Rails itself implements the Model-View-Controller design pattern. There is no concept of a &#39;service&#39; in a new Rails application. So it&#39;s understandable that this concept may seem foreign, and indeed non-obvious. However, I believe that the service objects pattern is well worth considering for any non-trivial Rails application.&lt;/p&gt;

&lt;p&gt;So before I discuss how to implement service objects in Rails, I&#39;ll first describe the concepts so you can decide whether it&#39;s worth doing so.&lt;/p&gt;



&lt;h2&gt;What are services?&lt;/h2&gt;

&lt;p&gt;A &#39;service&#39; describes system interactions. Usually, these will involve more than one business model in our application.&lt;/p&gt;

&lt;p&gt;As an example; we have a &lt;code&gt;User&lt;/code&gt; model and this encapsulates a password. If a user has forgotten their password, the business rules dictate that we have to send them an e-mail with a link to reset it. This functionality is a service.&lt;/p&gt;

&lt;p&gt;There are other scenarios in which the user&#39;s password could be reset. For instance, the system administrator may decide to reset their password on their behalf.&lt;/p&gt;

&lt;p&gt;In the above example, the service behaviour fits into the MVC world as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Model (&lt;code&gt;User&lt;/code&gt;)&lt;/strong&gt; - a user has a password. It must be present and a minimum of 8 characters. The model is a representation of the user and doesn&#39;t really have an opinion about the different circumstances in which the password could be reset.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;View&lt;/strong&gt; - the &#39;forgot password&#39; form and success/failure states&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Controller&lt;/strong&gt; - responds to the form in the view being submitted by attempting to instantiate the &#39;forgotten password&#39; service and then rendering the response (error or success) from the view&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Service&lt;/strong&gt; - responsible for locating the user, sending the reset password e-mail and reporting back to the originator (in this case the controller)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the general definition of a service, so it&#39;s up to you whether you think this makes sense.&lt;/p&gt;


&lt;h2&gt;The options&lt;/h2&gt;

&lt;p&gt;There&#39;s several approaches to encapsulating service logic within a Rails application:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Fat model, skinny controller&lt;/strong&gt; - this principle encourages one to put the service logic in the model. Therefore the model very quickly becomes filled with methods which encapsulate system interactions rather than domain objects. It becomes difficult to identify which methods are domain and which are interactions. Inter-dependancy between model classes can quickly become a problem, which can make refactoring and testing very difficult.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Concerns&lt;/strong&gt; - these attempt to address the &#39;overloaded model&#39; syndrome where you have a very large model file, simply by separating methods into modules which are then mixed into the model. It&#39;s the approach encouraged in Rails 4 with its&#39; &#39;models/concerns&#39; folder which is created by default. This can sometimes make sense, but increases the level of abstraction which can make it difficult to figure out where a method is defined. Additionally, it doesn&#39;t address the potential inter-dependancy issues that can arise, and frequently you can end up with massive methods, or multiple methods doing similar things to handle several different scenarios. In my view, it&#39;s the equivalent of sweeping the dirt under the rug.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Observers and callbacks&lt;/strong&gt; - these hook into the lifecycle of a model object. For instance, we could create and save a ForgottenPassword object, which has a callback or observer which then sends the e-mail. The disadvantage of this approach is that you are restricted to the lifecycle of persistent objects. So not only do you have to create and persist the ForgottenPassword object for it to work (is this necessary?), but the behaviours can very quickly become difficult to track, especially with observers which are running outside of the request cycle, and callbacks can make things very difficult to test or to predict behaviour.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fat controller&lt;/strong&gt; - use the controller to co-ordinate the interactions between the objects. This can be a good approach, but the drawbacks are the controllers can become large enough to be unwieldy, and very difficult to test. Additionally, if you&#39;re using the console or a Rake task or background job you&#39;ll have to duplicate the functionality there as well.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Service objects&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;Service Objects explained&lt;/h2&gt;

&lt;p&gt;Service objects implement individual services, as described above. Following the &#39;forgotten password&#39; scenario, we might have a class called &lt;code&gt;ForgottenPassword&lt;/code&gt;. Here&#39;s what it might look like:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ForgottenPassword&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;UserMailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;password_reset&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@user&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deliver&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a very simple example - as I&#39;m sure you can appreciate this logic can often be far more complex. We might also want to develop an exception handler here and return more logical errors to the controller (or Rake task or whatever is calling it).&lt;/p&gt;

&lt;p&gt;Using this service object, we can remove the equivalent &lt;code&gt;User&lt;/code&gt; model method, breaking the dependancy between &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;UserMailer&lt;/code&gt;, and removing any assumption about how the password can be reset from the model. Our tests on the &lt;code&gt;User&lt;/code&gt; model just got a lot simpler, and our tests on the &lt;code&gt;ForgottenPassword&lt;/code&gt; service are straightforward and segregated too.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ForgottenPasswordController&lt;/code&gt; might look something like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ForgottenPasswordController&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;begin&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;ForgottenPassword&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# render the view&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Handle exceptions and render the view&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Again, our tests on the controller will be very simple and you don&#39;t run the risk of turning them into integration tests.&lt;/p&gt;


&lt;h2&gt;When to use them&lt;/h2&gt;

&lt;p&gt;In my view, the full benefits of service objects are realised when modelling all interactions as discrete service objects. Doing so will enable you to segregate your testing into very discrete and logical areas.&lt;/p&gt;

&lt;p&gt;However, you will see these benefits by adopting the approach for new functionality in an existing application, too. Developing and maintaining that functionality will be easier.&lt;/p&gt;


&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Services are a concept which Rails doesn&#39;t really recognise out of the box. But I feel that the benefits of doing so are well worth it. While it can result in slightly more code in a simple app (although the above example demonstrates this can be fairly trivial), I&#39;ve found it helps write tests faster and produces more maintainable code. I hope you&#39;ll consider using them.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Installing Ruby 2.0.0 and Rails 4.0.0 beta 1 on Mountain Lion with RVM</title>
   <link href="http://stevelorek.com/rails-4-on-mountain-lion.html"/>
   <updated>2013-03-02T00:00:00+00:00</updated>
   <id>http://stevelorek.com/rails-4-on-mountain-lion</id>
   <content type="html">&lt;p&gt;Celebrating &lt;a href=&quot;https://twitter.com/yukihiro_matz/status/305334327938519040&quot;&gt;Ruby&#39;s 20th anniversary&lt;/a&gt;, both &lt;a href=&quot;http://www.ruby-lang.org/en/news/2013/02/24/ruby-2-0-0-p0-is-released/&quot;&gt;Ruby 2.0.0&lt;/a&gt; and &lt;a href=&quot;http://weblog.rubyonrails.org/2013/2/25/Rails-4-0-beta1/&quot;&gt;Rails 4.0.0 beta 1&lt;/a&gt; were released last week. Naturally, we will want to get playing with these new tools right away, but installation has not been straightforward for some.&lt;/p&gt;

&lt;p&gt;Here&#39;s how I (eventually) managed to get the pair running on OS X Mountain Lion:&lt;/p&gt;


&lt;h2&gt;Install dependancies&lt;/h2&gt;

&lt;p&gt;Most of these problems seem to revolve around the openssl dependancy and RVM&#39;s default process for upgrading it. To install and use openssl 1.0.1e successfully, I found homebrew did the trick. Follow these steps to install it (and libyaml, the other dependancy).&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;brew update
...
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;brew install libyaml openssl&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Update RVM&lt;/h2&gt;

&lt;p&gt;We need to upgrade RVM to install Ruby 2.0.0.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rvm get head&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Install Ruby 2.0.0&lt;/h2&gt;

&lt;p&gt;You may be reading this because you&#39;ve already tried installing it, so let&#39;s take some precautionary cleanup measures.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rvm remove ruby 2.0.0
...
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rvm pkg remove&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you should be ready to install and use Ruby 2.0.0:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rvm install ruby
...
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rvm use 2.0.0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Check for any error messages in the log. At this point, there should be none.&lt;/p&gt;


&lt;h2&gt;Install Rails 4&lt;/h2&gt;

&lt;p&gt;As it&#39;s still in beta, you&#39;ll need to specify the version of the Rails gem to install:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install rails --version 4.0.0.beta1 --no-ri --no-rdoc&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Again, this should now install faultlessly. Let me know if you have any problems.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>How to Shrink a Git Repository</title>
   <link href="http://stevelorek.com/how-to-shrink-a-git-repository.html"/>
   <updated>2012-05-11T00:00:00+00:00</updated>
   <id>http://stevelorek.com/how-to-shrink-a-git-repository</id>
   <content type="html">&lt;p&gt;Our main Git repository had suddenly ballooned in size. It had grown overnight to 180MB (compressed) and was taking forever to clone.&lt;/p&gt;

&lt;p&gt;The reason was obvious; somebody, somewhere, somewhen, somehow, had committed some massive files. But we had no idea what those files where.&lt;/p&gt;

&lt;p&gt;After a few hours of trial, error and research, I was able to nail down a process to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Discover the large files&lt;/li&gt;
  &lt;li&gt;Clean them from the repository&lt;/li&gt;
  &lt;li&gt;Modify the remote (GitHub) repository so that the files are never downloaded again&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This process should never be attempted unless you can guarantee that all team members can produce a fresh clone. It involves altering the history and requires anyone who is contributing to the repository to pull down the newly cleaned repository before they push anything to it.&lt;/p&gt;


&lt;h2&gt;Deep Clone the Repository&lt;/h2&gt;

&lt;p&gt;If you don&#39;t already have a local clone of the repository in question, create one now:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone remote-url&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now&amp;mdash;you may have cloned the repository, but you don&#39;t have all of the remote branches. This is imperative to ensure a proper &#39;deep clean&#39;. To do this, we&#39;ll need a little Bash script:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; branch in &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;git branch -a &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; grep remotes &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; grep -v HEAD &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; grep -v master&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    git branch --track &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;##*/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$branch&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;http://stackoverflow.com/a/4754797/513422&quot;&gt;bigfish on StackOverflow&lt;/a&gt; for this script, which is copied verbatim.&lt;/p&gt;

&lt;p&gt;Copy this code into a file, &lt;code&gt;chmod +x filename.sh&lt;/code&gt;, and then execute it with &lt;code&gt;./filename.sh&lt;/code&gt;. You will now have all of the remote branches as well (it&#39;s a shame Git doesn&#39;t provide this functionality).&lt;/p&gt;


&lt;h2&gt;Discovering the large files&lt;/h2&gt;

&lt;p&gt;Credit is due to Antony Stubbs here - &lt;a href=&quot;http://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/&quot;&gt;his Bash script&lt;/a&gt; identifies the largest files in a local Git repository, and is reproduced verbatim below:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#set -x &lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Shows you the largest objects in your repo&amp;#39;s pack file.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Written for osx.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# @see http://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# @author Antony Stubbs&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# set the internal field spereator to line break, so that we can iterate easily over the verify-pack output&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;IFS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;$&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# list all objects including their size, sort by size, take top 10&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;git verify-pack -v .git/objects/pack/pack-*.idx &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; grep -v chain &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; sort -k3nr &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; head&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;All sizes are in kB. The pack column is the size of the object, compressed, inside the pack file.&amp;quot;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;size,pack,SHA,location&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; y in &lt;span class=&quot;nv&quot;&gt;$objects&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# extract the size in bytes&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; cut -f &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt; -d &lt;span class=&quot;s1&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# extract the compressed size in bytes&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;compressedSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; cut -f &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; -d &lt;span class=&quot;s1&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# extract the SHA&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;sha&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; cut -f &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; -d &lt;span class=&quot;s1&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# find the objects location in the repository tree&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;git rev-list --all --objects &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; grep &lt;span class=&quot;nv&quot;&gt;$sha&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;#lineBreak=`echo -e &amp;quot;\n&amp;quot;`&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;${output}\n${size},${compressedSize},${other}&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -e &lt;span class=&quot;nv&quot;&gt;$output&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; column -t -s &lt;span class=&quot;s1&quot;&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Execute this script as before, and you&#39;ll see some output similar to the below:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;All sizes are in kB. The pack column is the size of the object, compressed, inside the pack file.
size     pack    SHA                                       location
&lt;span class=&quot;m&quot;&gt;1111686&lt;/span&gt;  &lt;span class=&quot;m&quot;&gt;132987&lt;/span&gt;  a561d25105c79aa4921fb742745de0e791483afa  08-05-2012.sql
&lt;span class=&quot;m&quot;&gt;5002&lt;/span&gt;     &lt;span class=&quot;m&quot;&gt;392&lt;/span&gt;     e501b79448b9e970ab89b048b3218c2853fdfc88  foo.sql
&lt;span class=&quot;m&quot;&gt;266&lt;/span&gt;      &lt;span class=&quot;m&quot;&gt;249&lt;/span&gt;     73fa731bb90b04dcf79eeea8fdd637ba7df4c089  app/assets/images/fw/iphone.fw.png
&lt;span class=&quot;m&quot;&gt;265&lt;/span&gt;      &lt;span class=&quot;m&quot;&gt;43&lt;/span&gt;      939b31c563bd40b1ca70e4f4a9f7d67c27c936c0  doc/models_complete.svg
&lt;span class=&quot;m&quot;&gt;247&lt;/span&gt;      &lt;span class=&quot;m&quot;&gt;39&lt;/span&gt;      03514d9e84418573f26b205bae7e4e57057c036f  unprocessed_email_replies.sql
&lt;span class=&quot;m&quot;&gt;193&lt;/span&gt;      &lt;span class=&quot;m&quot;&gt;49&lt;/span&gt;      6e601c4067aaddb26991c4bd5fbddef003800e70  public/assets/jquery-ui.min-0424e108178defa1cc794ee24fc92d24.js
&lt;span class=&quot;m&quot;&gt;178&lt;/span&gt;      &lt;span class=&quot;m&quot;&gt;30&lt;/span&gt;      c014b20b6fed9f17a0b2809ac410d74f291da26e  foo.sql
&lt;span class=&quot;m&quot;&gt;158&lt;/span&gt;      &lt;span class=&quot;m&quot;&gt;158&lt;/span&gt;     15f9e56bc0865f4f303deff053e21909661a716b  app/assets/images/iphone.png
&lt;span class=&quot;m&quot;&gt;103&lt;/span&gt;      &lt;span class=&quot;m&quot;&gt;36&lt;/span&gt;      3135e15c5cec75a4c85a0636b154b83221020c97  public/assets/application-c65733a4a64a1a885b1c32694574b12a.js
&lt;span class=&quot;m&quot;&gt;99&lt;/span&gt;       &lt;span class=&quot;m&quot;&gt;85&lt;/span&gt;      c1c80bc4c09e692d5e2127e39c87ecacdb1e816f  app/assets/images/fw/lovethis_logo_sprint.fw.png&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Yep - looks like someone has been pushing some rather unnecessary files somewhere! Including a lovely 1.1GB present in the form of a SQL dump file.&lt;/p&gt;

&lt;h2&gt;Cleaning the files&lt;/h2&gt;

&lt;p&gt;Cleaning the file will take a while, depending on how busy your repository has been. You just need one command to begin the process:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git filter-branch --tag-name-filter cat --index-filter &lt;span class=&quot;s1&quot;&gt;&amp;#39;git rm -r --cached --ignore-unmatch filename&amp;#39;&lt;/span&gt; --prune-empty -f -- --all&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command is adapted from other sources&amp;mdash;the principal addition is &lt;code&gt;--tag-name-filter cat&lt;/code&gt; which ensures tags are rewritten as well.&lt;/p&gt;

&lt;p&gt;After this command has finished executing, your repository should now be cleaned, with all branches and tags in tact.&lt;/p&gt;


&lt;h2&gt;Reclaim space&lt;/h2&gt;

&lt;p&gt;While we may have rewritten the history of the repository, those files &lt;em&gt;still&lt;/em&gt; exist in there, stealing disk space and generally making a nuisance of themselves. Let&#39;s nuke the bastards:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rm -rf .git/refs/original/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git reflog expire --expire&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;now --all&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git gc --prune&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;now&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git gc --aggressive --prune&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;now&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we have a fresh, clean repository. In my case, it went from 180MB to 7MB.&lt;/p&gt;


&lt;h2&gt;Push the cleaned repository&lt;/h2&gt;

&lt;p&gt;Now we need to push the changes back to the remote repository, so that nobody else will suffer the pain of a 180MB download.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git push origin --force --all&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;--all&lt;/code&gt; argument pushes all your branches as well. That&#39;s why we needed to clone them at the start of the process.&lt;/p&gt;

&lt;p&gt;Then push the newly-rewritten tags:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git push origin --force --tags&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Tell your teammates&lt;/h2&gt;

&lt;p&gt;Anyone else with a local clone of the repository will need to either use &lt;code&gt;git rebase&lt;/code&gt;, or create a fresh clone, otherwise when they push again, those files are going to get pushed along with it and the repository will be reset to the state it was in before.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Configure Postfix on OS X Lion to Relay via Gmail</title>
   <link href="http://stevelorek.com/configure-postfix-relay-gmail-osx-lion.html"/>
   <updated>2011-12-28T00:00:00+00:00</updated>
   <id>http://stevelorek.com/configure-postfix-relay-gmail-osx-lion</id>
   <content type="html">&lt;p&gt;Today I had to test e-mail delivery of an app I was working on from home. Annoyingly, my ISP (&lt;a href=&quot;http://www.o2.co.uk&quot;&gt;O2&lt;/a&gt;) block outgoing port 25 because they don&#39;t trust their users not to run open mail relays. This meant that e-mails sent from my app were not being delivered.&lt;/p&gt;

&lt;p&gt;So I needed to set up &lt;a href=&quot;http://www.postfix.org/&quot;&gt;Postfix&lt;/a&gt; (the native Sendmail implementation running on OS X Lion) to relay all outgoing mails to another mail server. It turned out to be quite difficult to configure Postfix to connect to &lt;a href=&quot;http://gmail.com&quot;&gt;Gmail&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Gmail requires an authenticated TLS session to relay mail. But the instructions I found across the web did not seem to work, in that the Gmail CA certificates were not trusted even after adding them.&lt;/p&gt;

&lt;p&gt;The easy solution was to simply stop Postfix from requiring a trusted CA altogether. Below are instructions to replicate my setup.&lt;/p&gt;

&lt;p&gt;First edit the Postfix configuration file as below:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo vim /etc/postfix/main.cf&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Edit the file as below:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;relayhost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;smtp.gmail.com&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;:587
&lt;span class=&quot;nv&quot;&gt;smtp_sasl_auth_enable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; yes
&lt;span class=&quot;nv&quot;&gt;smtp_sasl_password_maps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;:/etc/postfix/sasl_passwd
&lt;span class=&quot;nv&quot;&gt;smtp_sasl_security_options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; noanonymous
&lt;span class=&quot;nv&quot;&gt;smtp_sasl_mechanism_filter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; plain
&lt;span class=&quot;nv&quot;&gt;smtp_use_tls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; yes
&lt;span class=&quot;nv&quot;&gt;smtp_tls_security_level&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; may&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &#39;may&#39; security level settings tells Postfix to ignore untrusted CAs and continue delivery.&lt;/p&gt;

&lt;p&gt;Create a new file containing your Gmail account credentials:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo vim /etc/postfix/sasl_passwd&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;smtp.gmail.com&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;:587 USERNAME@DOMAIN:PASSWORD&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then load the account credentials into Postfix:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;sudo postmap /etc/postfix/sasl_passwd
sudo rm /etc/postfix/sasl_passwd&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then restart Postfix:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;sudo launchctl unload -w /System/Library/LaunchDaemons/org.postfix.master.plist
sudo launchctl load -w /System/Library/LaunchDaemons/org.postfix.master.plist&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you can send a test e-mail:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;mail -s &lt;span class=&quot;s2&quot;&gt;&amp;quot;Testing, Testing&amp;quot;&lt;/span&gt; steve@stevelorek.com&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Type the body of your message then &lt;code&gt;Ctrl-D&lt;/code&gt; to send the e-mail.&lt;/p&gt;

&lt;p&gt;Check the &lt;code&gt;/var/log/mail.log&lt;/code&gt; to see the status of your delivery.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Resque Worker Management with God</title>
   <link href="http://stevelorek.com/resque-worker-management-with-god.html"/>
   <updated>2011-05-06T00:00:00+00:00</updated>
   <id>http://stevelorek.com/resque-worker-management-with-god</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://god.rubyforge.org/&quot;&gt;God&lt;/a&gt; is a process management tool, which can watch your &lt;a href=&quot;https://github.com/defunkt/resque&quot;&gt;Resque&lt;/a&gt; workers, ensuring they&#39;re running and spawn additional workers as necessary in the background.&lt;/p&gt;

&lt;p&gt;We install God as below:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo gem install god&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;God uses configuration files for each of the processes it monitors. The way we&#39;re going to set it up is to have a single directory, &lt;code&gt;/etc/god&lt;/code&gt;, containing all of the scripts we want to be running. Any file named &lt;code&gt;.god&lt;/code&gt; will be run by the initialisation script we create later.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir /etc/god&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Resque comes with an &lt;a href=&quot;https://github.com/defunkt/resque/blob/master/examples/god/resque.god&quot;&gt;example configuration file&lt;/a&gt; which is a good basis for writing your own app-specific configuration.&lt;/p&gt;

&lt;p&gt;When you&#39;ve got your configuration file, you can run God with the following command:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rvmsudo god -c /etc/god/resque.god -D&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Running God Automatically&lt;/h2&gt;

&lt;p&gt;In a production environment, you&#39;ll want God to be running all of the time on system boot. We will need an init script to get this working, in &lt;code&gt;/etc/init.d/god&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# God&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# chkconfig: - 99 1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# description: start, stop, restart God (bet you feel powerful)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# source function library&lt;/span&gt;
. /etc/rc.d/init.d/functions

&lt;span class=&quot;nv&quot;&gt;RUBY_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/usr/bin/ruby&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$RUBY_PATH&lt;/span&gt;:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
&lt;span class=&quot;nv&quot;&gt;DAEMON&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/usr/bin/god&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;PIDFILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/var/run/god.pid
&lt;span class=&quot;nv&quot;&gt;LOGFILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/var/log/god.log
&lt;span class=&quot;nv&quot;&gt;SCRIPTNAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/etc/init.d/god
&lt;span class=&quot;nv&quot;&gt;CONFIGFILEDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/etc/god

&lt;span class=&quot;c&quot;&gt;#DEBUG_OPTIONS=&amp;quot;--log-level debug&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;DEBUG_OPTIONS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Gracefully exit if &amp;#39;god&amp;#39; gem is not available.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; -x &lt;span class=&quot;nv&quot;&gt;$DAEMON&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;0

&lt;span class=&quot;nv&quot;&gt;RETVAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0

god_start&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;start_cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$DAEMON -l $LOGFILE -P $PIDFILE $DEBUG_OPTIONS&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;#stop_cmd=&amp;quot;kill -QUIT `cat $PIDFILE`&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$start_cmd&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;$start_cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -en &lt;span class=&quot;s2&quot;&gt;&amp;quot;god already running&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;RETVAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$RETVAL&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;0&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    sleep &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# wait for server to load before loading config files&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; -d &lt;span class=&quot;nv&quot;&gt;$CONFIGFILEDIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; file in &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;ls -1 &lt;span class=&quot;nv&quot;&gt;$CONFIGFILEDIR&lt;/span&gt;/*.god&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;god: loading $file ...&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$DAEMON&lt;/span&gt; load &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$RETVAL&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

god_stop&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;stop_cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;god terminate&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$stop_cmd&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;$stop_cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -en &lt;span class=&quot;s2&quot;&gt;&amp;quot;god not running&amp;quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$1&amp;quot;&lt;/span&gt; in
  start&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    god_start
    &lt;span class=&quot;nv&quot;&gt;RETVAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
  stop&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    god_stop
    &lt;span class=&quot;nv&quot;&gt;RETVAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
  restart&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    god_stop
    god_start
    &lt;span class=&quot;nv&quot;&gt;RETVAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
  status&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$DAEMON&lt;/span&gt; status
    &lt;span class=&quot;nv&quot;&gt;RETVAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
  *&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Usage: god {start|stop|restart|status}&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$RETVAL&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Make sure you change the paths at the beginning of the file to match your server&#39;s environment. To install the script, issue the following commands:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo chmod +x /etc/init.d/god
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo touch /var/log/god.log
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo update-rc.d -f god defaults&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Congratulations; your workers are now fully managed by God!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Installing Pygments 1.4 on MacOS X</title>
   <link href="http://stevelorek.com/installing-pygments-on-macosx.html"/>
   <updated>2011-03-01T00:00:00+00:00</updated>
   <id>http://stevelorek.com/installing-pygments-on-macosx</id>
   <content type="html">&lt;p&gt;I&#39;m using &lt;a href=&quot;https://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt; to power my blog. It&#39;s a very simple framework which lends itself perfectly to developers used to coding files and the &lt;a href=&quot;http://git-scm.com/&quot;&gt;Git&lt;/a&gt; workflow, and comes without any of the bloat required for a client-facing &lt;a href=&quot;http://en.wikipedia.org/wiki/Content_management_system&quot;&gt;CMS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Jekyll comes with built-in support for &lt;a href=&quot;http://pygments.org/&quot;&gt;Pygments&lt;/a&gt;; a syntax highlighter supporting hundreds of languages. This article details the officially supported method for installing Pygments 1.4 on Mac OS X Snow Leopard. You will need to have &lt;a href=&quot;http://www.python.org/&quot;&gt;Python&lt;/a&gt; installed already&amp;mdash;this is provided by the &lt;a href=&quot;http://www.apple.com/macosx/developers/&quot;&gt;Mac OS X Developer Tools&lt;/a&gt;&amp;mdash;and you&#39;ll need to be logged into an administrator account.&lt;/p&gt;

&lt;p&gt;First, establish the version of Python you have:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;python --version
Python 2.6.1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;http://pypi.python.org/pypi/setuptools#files&quot;&gt;Download the Setuptools package&lt;/a&gt; which corresponds to your version of Python. In this case, it will be &lt;code&gt;setuptools-0.6c11-py2.6.egg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Run the Setuptools package as root:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo sh setuptools-0.6c11-py2.6.egg
...
Finished processing dependencies &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;setuptools&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;0.6c11&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will add a new command you can run: &lt;code&gt;easy_install&lt;/code&gt;. With this we can install Pygments (again as root):&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo easy_install Pygments
...
Finished processing dependencies &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; Pygments&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, in our &lt;code&gt;config.yml&lt;/code&gt; file for our Jekyll blog, we can add:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;pygments&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will add support for syntax highlighting using the &lt;code&gt;&amp;#123;% highlight %&amp;#125;&lt;/code&gt; liquid tags. Enjoy!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Incorporating ActionMailer in Cucumber Tests</title>
   <link href="http://stevelorek.com/actionmailer-cucumber.html"/>
   <updated>2011-02-28T00:00:00+00:00</updated>
   <id>http://stevelorek.com/actionmailer-cucumber</id>
   <content type="html">&lt;p&gt;It is very common for Ruby applications to send transactional e-mails to users. What&#39;s not immediately obvious is how, as developers, we can test this functionality using our tools of choice: &lt;a href=&quot;http://cukes.info/&quot;&gt;Cucumber&lt;/a&gt; and &lt;a href=&quot;http://relishapp.com/rspec&quot;&gt;Rspec&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ideally, the method should be re-usable so that we can simply add a single step to our scenarios, e.g:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-cucumber&quot; data-lang=&quot;cucumber&quot;&gt;&lt;span class=&quot;k&quot;&gt;And &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;it should send me an &amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;account confirmation&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;quot; e-mail&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;One way to do this in a re-usable way is to add a new tag, &lt;code&gt;@email&lt;/code&gt;, which sets up ActionMailer. In your &lt;code&gt;features/support/env.rb&lt;/code&gt; file, add the following:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Around&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;@email&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scenario&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;ActionMailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delivery_method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:test&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;ActionMailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;perform_deliveries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;ActionMailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deliveries&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This ensures ActionMailer is in test mode (all e-mails will be added to an array we can inspect, rather than sent out to the real world), and it clears any other e-mails in the deliveries array before each step is executed. Now we can simply add the &lt;code&gt;@email&lt;/code&gt; tag before any scenario which needs to test e-mail functionality and this will be done for us automatically.&lt;/p&gt;

&lt;p&gt;Then we create a new &lt;code&gt;features/step_definitions/email_steps.rb&lt;/code&gt; file and add the following step definition:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Then&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^it should send me an? &amp;quot;([^\&amp;quot;]*)&amp;quot; e\-mail$/&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionMailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deliveries&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will test the subject line against the argument &quot;account confirmation&quot; in your scenario, so we could use this step for other types of e-mail; e.g. &quot;password reminder&quot;.&lt;/p&gt;

We can also test that the application &lt;em&gt;doesn&#39;t&lt;/em&gt; send an e-mail, for example:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Then&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^it should not send an e\-mail$/&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;ActionMailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deliveries&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here&#39;s an example of the e-mail testing functionality in action:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-cucumber&quot; data-lang=&quot;cucumber&quot;&gt;&lt;span class=&quot;nt&quot;&gt;@email&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;Scenario:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt; Creating an account&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;  Given &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;I am logged out&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Then &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;I should be able to register a new user account&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;When &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;I enter my details&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Then &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;it should create a new account for me&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;And &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;it should send me an &amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;account confirmation&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;quot; e-mail&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I hope this helps someone!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Associated Records with factory_girl</title>
   <link href="http://stevelorek.com/associated-records-with-factorygirl.html"/>
   <updated>2011-02-12T00:00:00+00:00</updated>
   <id>http://stevelorek.com/associated-records-with-factorygirl</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/thoughtbot/factory_girl&quot;&gt;factory_girl&lt;/a&gt; is a Ruby Gem which makes it easy to build re-usable data objects in a test suite. It works especially well with ActiveRecord models.&lt;/p&gt;

&lt;p&gt;I was recently working on adding a new feature to a project which contained some factory implementations written by a colleague, but the Cucumber steps kept failing where it was checking for associated records. This was because the associated records were set up incorrectly in the factory.&lt;/p&gt;

&lt;p&gt;Below is an example of how we build associated records the right way. First is the parent model:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Factory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:booking&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;budget&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;from_now&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;after_build&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;menu_items&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Factory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:menu_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:booking&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note the way we add child records in the &lt;code&gt;after_build&lt;/code&gt; block, and how we&#39;re passing the current object to the factory. And now for the child model:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Factory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:menu_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;description&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Roast Beef&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sale_price&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;association&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:booking&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The problem with my colleague&#39;s implementation was the &lt;code&gt;build&lt;/code&gt; message didn&#39;t include the &lt;code&gt;booking&lt;/code&gt; attribute, therefore factory_girl was creating another Booking object to meet the MenuItem&#39;s &lt;code&gt;association&lt;/code&gt; specification. So each time the factory was run, two Bookings were created, and the MenuItem was associated with the wrong record, not the one returned by the factory.&lt;/p&gt;

&lt;p&gt;Now that we&#39;ve specified our implementations correctly, we can build both Bookings and MenuItems individually.&lt;/p&gt;

&lt;p&gt;Much head scratching was caused by that one&amp;mdash;hopefully this refresher will save someone the same!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Speed Testing with Spork</title>
   <link href="http://stevelorek.com/speed-testing-with-spork.html"/>
   <updated>2011-02-01T00:00:00+00:00</updated>
   <id>http://stevelorek.com/speed-testing-with-spork</id>
   <content type="html">&lt;p&gt;Test-Driven and Behaviour-Driven Development (TDD and BDD) have seen massive rates of adoption among the Ruby community, chiefly thanks to its close integration in the Rails framework and the fast pace of tool development. The benefits of these methodologies are plainly obvious to many experienced Software Developers and Project Managers.&lt;/p&gt;

&lt;p&gt;One set of tools has established itself as the &#39;preferred&#39; set among the Ruby community; &lt;a href=&quot;http://relishapp.com/rspec&quot;&gt;Rspec&lt;/a&gt;, which tests object specifications, and &lt;a href=&quot;http://cukes.info/&quot;&gt;Cucumber&lt;/a&gt;, which tests user interface behaviour. You may be using other tools in addition to these. Today I&#39;m going to give you a tip to help you optimise your workflow by making testing faster, using another tool called &lt;a href=&quot;https://github.com/timcharper/spork&quot;&gt;Spork&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Spork is a small server application which essentially eliminates the long delay in starting up your test suite. Typically, running rake spec or rake features results in a delay of several seconds before testing actually begins. The reason for this is the application environment is being loaded from scratch each time. Spork eliminates this delay by loading it once and then &#39;forking&#39; itself each time you run your tests. The result: tests begin immediately.&lt;/p&gt;


&lt;h2&gt;Installing Spork in your Application&lt;/h2&gt;

&lt;p&gt;This tutorial is based on a Rails 3 application. First, edit your &lt;code&gt;Gemfile&lt;/code&gt; to include the Spork dependancy:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;spork&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;gt;= 0.9.0.rc2&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note: we require at least version 0.9.0.rc2 because it addresses &lt;a href=&quot;http://stackoverflow.com/questions/3894232/rspec-shoulda-and-spork-does-not-work-together&quot;&gt;an issue when using Shoulda&lt;/a&gt;. If you&#39;re not using &lt;a href=&quot;https://github.com/thoughtbot/shoulda&quot;&gt;Shoulda&lt;/a&gt;, you can drop the version requirement.&lt;/p&gt;

&lt;p&gt;Then update your bundle:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle install&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The final thing we need to do is alter the test environment&#39;s behaviour. Unlike in development mode, the test mode will cache your classes, essentially meaning that any changes you make during development will not be reflected automatically when running tests with Spork. So, in the &lt;code&gt;config/environments/test.rb&lt;/code&gt; file, change the following line as shown:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cache_classes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Using Spork with an RSpec Test Suite&lt;/h2&gt;

&lt;p&gt;We need to configure Spork to tell it what parts of the test suite initialisation it can handle. Spork provides a convenient command to make this easy:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;spork --bootstrap&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will add some extra lines to the &lt;code&gt;spec/spec_helper.rb&lt;/code&gt; file. Basically, what you need to do now is move the existing code underneath into the relevant blocks; those which need to happen only once on initialisation, and those which need to happen each time the tests are run. In many simple cases you will be able to copy everything into the &lt;code&gt;Spork.prefork&lt;/code&gt; block. But you must be careful here not the break anything.&lt;/p&gt;

&lt;p&gt;Now you&#39;re ready to start the Spork server:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;spork&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Open another shell session and rather than &lt;code&gt;rake spec&lt;/code&gt;, use the following command:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;rspec --drb spec&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Your tests should now run instantly without delay! Note we don&#39;t run &lt;code&gt;rake&lt;/code&gt; because it will force a load of the Rails application anyway, rendering the savings we&#39;ve made worthless.&lt;/p&gt;

&lt;p&gt;You may also add the &lt;code&gt;--drb&lt;/code&gt; switch to your &lt;code&gt;.rspec&lt;/code&gt; file&amp;mdash;in which case, you can drop this from your command.&lt;/p&gt;


&lt;h2&gt;Spork with Cucumber&lt;/h2&gt;

&lt;p&gt;Cucumber comes with support for Spork as well. You will need to do some editing of your &lt;code&gt;features/support/env.rb&lt;/code&gt; file to add the two Spork blocks, as per the &lt;code&gt;spec/spec_helper.rb&lt;/code&gt; file. The same rules apply.&lt;/p&gt;

&lt;p&gt;Bear in mind that all hooks (e.g. &lt;code&gt;Before&lt;/code&gt;, &lt;code&gt;After&lt;/code&gt;) need to be in the &lt;code&gt;each_run&lt;/code&gt; block. You can refer to &lt;a href=&quot;https://gist.github.com/123370&quot;&gt;this gist&lt;/a&gt; and my example below for further guidelines:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;spork&amp;#39;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Spork&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prefork&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;RAILS_ENV&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;test&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expand_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;__FILE__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/../../config/environment&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;cucumber&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;cucumber/formatter/unicode&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;cucumber/rails/rspec&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;capybara/rails&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;capybara/cucumber&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;capybara/session&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;factory_girl/step_definitions&amp;#39;&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;Capybara&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;default_selector&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:css&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Spork&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each_run&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;cucumber/rails/world&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;cucumber/rails/active_record&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;cucumber/web/tableish&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;simplecov&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;db/seeds&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;SimpleCov&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rails&amp;#39;&lt;/span&gt;
  
  &lt;span class=&quot;no&quot;&gt;Before&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Seeds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;allow_rescue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;Cucumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;World&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;use_transactional_fixtures&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defined?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;begin&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;database_cleaner&amp;#39;&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;DatabaseCleaner&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strategy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:truncation&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;LoadError&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ignore_if_database_cleaner_not_present&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can now run the Spork server. However, the command is different to the Rspec example:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;spork cuc&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You &lt;em&gt;must&lt;/em&gt; use the &lt;code&gt;cuc&lt;/code&gt; argument to run Spork with Cucumber. Now, in a new shell session you can run Cucumber as below:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;cucumber --drb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Again, we don&#39;t run &lt;code&gt;rake features&lt;/code&gt; because Rake would initialise our Rails application on its own anyway. Your features should now be tested instantly!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Security Issue in Mail Gem</title>
   <link href="http://stevelorek.com/mail-gem-security-issue.html"/>
   <updated>2011-01-26T00:00:00+00:00</updated>
   <id>http://stevelorek.com/mail-gem-security-issue</id>
   <content type="html">&lt;p&gt;This is an important one for anyone using &lt;a href=&quot;http://rubyonrails.org/&quot;&gt;Rails 3&lt;/a&gt; in a production environment who hasn’t yet updated the &lt;a href=&quot;https://github.com/mikel/mail&quot;&gt;Mail gem&lt;/a&gt; to version 2.2.15 or later.&lt;/p&gt;

&lt;p&gt;A project I’m working on at the moment sends transactional e-mails via the &lt;a href=&quot;http://en.wikipedia.org/wiki/Sendmail&quot;&gt;sendmail&lt;/a&gt; delivery method. Some of the recipients’ e-mail addresses contain the ampersand (&amp;amp;) character in the &lt;a href=&quot;http://www.remote.org/jochen/mail/info/chars.html&quot;&gt;local part&lt;/a&gt; (the bit before the @ symbol).&lt;/p&gt;

&lt;p&gt;We started being notified of strange exceptions when the application was sending to these addresses. A quick test in the console revealed this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-irb&quot; data-lang=&quot;irb&quot;&gt;&lt;span class=&quot;go&quot;&gt;ruby-1.9.2-p0 &amp;gt; mail.to = &amp;#39;test.&amp;amp;.test@stevelorek.com&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; =&amp;gt; &amp;quot;test.&amp;amp;.test@stevelorek.com&amp;quot; &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ruby-1.9.2-p0 &amp;gt; mail.deliver&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;sh: .test@stevelorek.com: command not found&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Clearly, at some point the e-mail address is being output to the shell directly, without any escaping. We can see that the ampersand is acting as a command splitter, so everything after the ampersand is treated as a new command.&lt;/p&gt;

&lt;p&gt;It’s good practise to sanitise and validate any user input anyway &amp;ndash; indeed, many validations will erroneously reject an ampersand in the local part anyway. However, this still represents a serious security risk to Rails 3 applications.&lt;/p&gt;

&lt;p&gt;The culprit was the Mail gem which Rails depends on to handle e-mail delivery. The lines responsible for this error are in &lt;a href=&quot;https://github.com/mikel/mail/blob/master/lib/mail/network/delivery_methods/sendmail.rb&quot;&gt;lib/mail/network/delivery_methods/sendmail.rb&lt;/a&gt; of version 2.2.14:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Sendmail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;destinations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;IO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;popen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destinations&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;w+&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_lf&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flush&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After discussing this with &lt;a href=&quot;http://www.andylindeman.com/&quot;&gt;Andy Lindeman&lt;/a&gt; we reported the bug to the gem’s author, &lt;a href=&quot;http://lindsaar.net/&quot;&gt;Mikel Lindsaar&lt;/a&gt;, who quickly applied &lt;a href=&quot;https://github.com/mikel/mail/commit/12bfaad0d240bfd3912cfb640bedcb38db4c6f33&quot;&gt;Andy’s patch&lt;/a&gt; and &lt;a href=&quot;http://groups.google.com/group/mail-ruby/browse_thread/thread/e93bbd05706478dd?pli=1&quot;&gt;issued an announcement&lt;/a&gt; which was copied to the &lt;a href=&quot;http://groups.google.com/group/rubyonrails-security/browse_thread/thread/5a9e44a4bf940326&quot;&gt;Ruby on Rails security group&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The patch also had the nice effect of making my application work with all valid e-mail addresses.&lt;/p&gt;

&lt;p&gt;I would advise that everyone in a production environment update the Mail gem to version 2.2.15 immediately:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle update mail&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Introduction</title>
   <link href="http://stevelorek.com/introduction.html"/>
   <updated>2011-01-26T00:00:00+00:00</updated>
   <id>http://stevelorek.com/introduction</id>
   <content type="html">&lt;p&gt;Firstly, a big welcome and many thanks for taking the time to check out my blog.&lt;/p&gt;

&lt;p&gt;I’m a professional Web Developer working at &lt;a href=&quot;http://willoughbystewart.com&quot;&gt;Willoughby Stewart&lt;/a&gt;. I’ve been working in the industry for 16 years, starting when the Web was in its infancy and the term “Web design” meant Times New Roman or nothing! To begin with I used the Web for entrepeneurial benefit&amp;mdash;from launching my first commercial project at the age of 14 to running a successful e-commerce business for 6 years. Web development was purely a means to an end &amp;ndash; as it should be &amp;ndash; but has always been a passion.&lt;/p&gt;

&lt;p&gt;This is actually my first ‘proper’ personal site (if you don’t count the ‘&lt;a href=&quot;http://en.wikipedia.org/wiki/Doom_II:_Hell_on_Earth&quot;&gt;Doom II&lt;/a&gt;’ fan site holding page I made in 1995). I’m not quite sure why that is&amp;mdash;but as an entrepreneur I’ve always invested all of my energies into those ventures, learning new skills along the way. I’ve never really felt the need to express my personal views to the Web development community, nor have I felt confident enough to teach others as I’ve almost existed inside my own ‘bubble’. Now that I’ve been working as a Developer for a few years I feel that perspective has changed and I can offer something genuinely unique and helpful.&lt;/p&gt;

&lt;p&gt;I hope to offer a considered view of the industry in this blog. While development &amp;ndash; whether it’s programming, version control, or design, and everything else &amp;ndash; is certainly art, my motivator has always been to ask myself “what do I need to learn to achieve X, Y and Z?”&lt;/p&gt;

&lt;p&gt;I can give you two personal examples of this philosophy. When I was 16, I wanted to emulate the success of &lt;a href=&quot;http://amazon.co.uk&quot;&gt;Amazon&lt;/a&gt; and other, now defunct retailers, so I looked into how to set up an online shop. My research showed that the off-the-shelf solutions of the time were not fit for purpose, so I learned how to build one myself.&lt;/p&gt;

&lt;p&gt;I had no programming experience or training. I’d had some minor exposure to open source Perl scripts from a previous site (the online presence of a national magazine), so I started hacking one of the free open source cart scripts, little changes here and there, and then more fundamental ones. All the while I was wishing “if only I could do this”&amp;mdash;and the more I dug through forums and &lt;a href=&quot;http://www.hotbot.com&quot;&gt;HotBot&lt;/a&gt; search, the more it seemed &lt;a href=&quot;http://www.php.net/&quot;&gt;PHP 3&lt;/a&gt; was the answer to these problems. So I rewrote my shopping cart in PHP. About a dozen rewrites and a couple of years later I naturally ended up with something akin to a &lt;a href=&quot;http://en.wikipedia.org/wiki/Model–View–Controller&quot;&gt;MVC&lt;/a&gt; design pattern. I also learned a hell of a lot about what it takes to set up a retail business online, which I’m now using for the benefit of my clients.&lt;/p&gt;

&lt;p&gt;Where do I want to be in 5 years? I love Web development, but how can I satisfy my entrepreneurial urges? The answer is to make myself the most valuable asset I can be, by expanding my skills and hopefully stepping up the career ladder, and hopefully I’ll be in a great position when the next big idea arrives. What skills are most in demand? I’ve decided to build on my &lt;a href=&quot;http://www.ruby-lang.org/&quot;&gt;Ruby&lt;/a&gt; and &lt;a href=&quot;http://rubyonrails.org/&quot;&gt;Rails&lt;/a&gt; skills and see if I can transfer my experience to &lt;a href=&quot;http://developer.apple.com/&quot;&gt;iOS development&lt;/a&gt;. But at the same time I need to keep my front-end design skills relevant, and that means &lt;a href=&quot;http://diveintohtml5.org/&quot;&gt;HTML 5&lt;/a&gt;, &lt;a href=&quot;http://jquery.com/&quot;&gt;jQuery&lt;/a&gt; and &lt;a href=&quot;http://hardboiledwebdesign.com//&quot;&gt;CSS 3&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This blog will be a mixture of technical articles on the subject of Web development, commentary on the industry, and hopefully some advice to other Developers hoping to start their careers. I hope that sounds good to you.&lt;/p&gt;

&lt;p&gt;Also, a note on the design; this is the one area that’s held me back for so long. I’m a massive perfectionist. So I’m starting off simple on purpose, because it’s the content that really matters.&lt;/p&gt;</content>
 </entry>
 
 
</feed>