<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>tail -f development.log &#187; ruby</title>
	<atom:link href="http://craigjolicoeur.com/blog/category/ruby/feed" rel="self" type="application/rss+xml" />
	<link>http://craigjolicoeur.com/blog</link>
	<description>code with a purpose</description>
	<lastBuildDate>Sun, 19 Jun 2011 13:25:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=abc</generator>
		<item>
		<title>guard-annotate Gem Released</title>
		<link>http://craigjolicoeur.com/blog/guard-annotate-gem-released</link>
		<comments>http://craigjolicoeur.com/blog/guard-annotate-gem-released#comments</comments>
		<pubDate>Sat, 21 May 2011 13:18:14 +0000</pubDate>
		<dc:creator>Craig</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://craigjolicoeur.com/blog/?p=163</guid>
		<description><![CDATA[I&#8217;ve been meaning to look into the guard gem for a while now. After falling out of love with ZenTest/Autotest, and switching back and forth between watchr and autotest-standalone, I&#8217;ve had a few friends who recommended giving guard a try. Last night, one of those friends retweeted a request for a guard plugin to work [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been meaning to look into the <a href="http://rubygems.org/gems/guard">guard gem</a> for a while now.  After falling out of love with ZenTest/Autotest, and switching back and forth between <a href="http://rubygems.org/gems/watchr">watchr</a> and <a href="http://rubygems.org/gems/autotest-standalone">autotest-standalone</a>, I&#8217;ve had a few friends who recommended giving <a href="https://github.com/guard/guard">guard</a> a try.</p>
<p>Last night, one of those friends retweeted a request for a guard plugin to work with the <a href="http://rubygems.org/gems/annotate">annotate gem</a>.</p>
<p><a href="http://twitter.com/#!/jschoolcraft/status/71588152787214336"><img src="http://craigjolicoeur.com/blog/wp-content/uploads/2011/05/Screen-shot-2011-05-21-at-9.12.10-AM.png" alt="" title="twitter retweet" width="480" height="283" class="aligncenter size-full wp-image-164" /></a></p>
<p>I figured that was good a cause as any to finally dig in and give guard a try.  What better way to begin using and understanding a gem, then by writing an extension for it?</p>
<p>About two hours later, I released the first versions of <a href="http://rubygems.org/gems/guard-annotate">guard-annotate on rubygems.org</a> (<a href="http://github.com/cpjolicoeur/guard-annotate">source code on Github</a>).</p>
<p>So, if you use the annotate gem on your rails projects, as well as guard, feel free to give the gem a try and save your self some time re-running your annotations.</p>
<p>As always, comments and questions, as well as pull requests for features and bugfixes are welcome.</p>
<p><strong>** UPDATE **</strong></p>
<p>guard-annotate has now been officially added to the main guard repository on GitHub.  You can still install the gem the same way, but now you can also find the codebase on<a href="https://github.com/guard/guard-annotate"> the guard page at GitHub</a> as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://craigjolicoeur.com/blog/guard-annotate-gem-released/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cerberus 0.7 Released</title>
		<link>http://craigjolicoeur.com/blog/cerberus-0-7-released</link>
		<comments>http://craigjolicoeur.com/blog/cerberus-0-7-released#comments</comments>
		<pubDate>Wed, 05 Aug 2009 15:37:05 +0000</pubDate>
		<dc:creator>Craig</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[cerberus]]></category>

		<guid isPermaLink="false">http://craigjolicoeur.com/blog/?p=142</guid>
		<description><![CDATA[This morning I released version 0.7 of the Cerberus continuous integration gem. The gem (and zip and tarballs) are all available now via RubyForge. Thanks to all who had a part in this release. Paul Hinze added bazaar SCM support. Joe Van Dyk did some general code cleanup and Git SCM updates. So, grab the [...]]]></description>
			<content:encoded><![CDATA[<p>This morning I released <a href="http://rubyforge.org/frs/?group_id=1794">version 0.7</a> of the <a href="http://cerberus.rubyforge.org">Cerberus continuous integration gem</a>.</p>
<p>The gem (and zip and tarballs) are all available now via RubyForge.</p>
<p>Thanks to all who had a part in this release.  Paul Hinze added bazaar<br />
SCM support.  Joe Van Dyk did some general code cleanup and Git SCM<br />
updates.</p>
<p>So, grab the new version and kick the tires with it.  Get the word out.</p>
<p>I&#8217;d really like to see Cerberus get some more usage and to see it grow<br />
into a really mature, lightweight tool in the coming months.</p>
<p>Here is the changelog details for version 0.7</p>
<p>== Version 0.7<br />
New config options, Bazaar SCM support, removed GMailer bugfixes</p>
<p>* added support for bazaar scm<br />
* fixed bug with ActionMailer 2.3.3<br />
* removed GMailer library.  Use default Mail publisher instead<br />
* added &#8216;build_dir&#8217; option for setting custom build directory<br />
* added &#8216;setup_script&#8217; option for a custom script to be run before build command<br />
* Projects using the Git SCM were not getting the full diff output in<br />
their Publishers</p>
]]></content:encoded>
			<wfw:commentRss>http://craigjolicoeur.com/blog/cerberus-0-7-released/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to integrate punBB into an existing Ruby on Rails application</title>
		<link>http://craigjolicoeur.com/blog/how-to-integrate-punbb-into-an-existing-ruby-on-rails-application</link>
		<comments>http://craigjolicoeur.com/blog/how-to-integrate-punbb-into-an-existing-ruby-on-rails-application#comments</comments>
		<pubDate>Sat, 30 May 2009 15:32:12 +0000</pubDate>
		<dc:creator>Craig</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[forums]]></category>
		<category><![CDATA[integration]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[punBB]]></category>

		<guid isPermaLink="false">http://craigjolicoeur.com/blog/?p=133</guid>
		<description><![CDATA[A quick tutorial on how to integrate the punBB forum system into an existing Rails application with a single sign-on for both systems.]]></description>
			<content:encoded><![CDATA[<p>I released launched a rails side project, <a href="http://xboxmma.com">XBoxMMA.com</a>, and one of the most requested features by the initial users was the addition of forums to the site.</p>
<p>Thinking it over, I clearly had two options: 1) code my own custom forum system for the site, or 2) use an existing forum system.</p>
<p>While I don&#8217;t mind coding forums for the site, I really didn&#8217;t want to set aside the time needed for coding when I could have been working on plenty of other projects.  So, I set out researching existing forum software that I could utilize.</p>
<p>In searching for a third-party forum system, I really only had one major requirement &#8211; users needed to be able to login to the main website and be authenticated at the same time on the forums.  I didn&#8217;t want my users to have to maintain separate accounts and separate logins for the forums and the main website.  If I did, there would be no need for this tutorial as implementing standalone forums is a basic task.</p>
<p><span id="more-133"></span>First off, I researched existing forum systems that were already rails based, hoping there was something I could quickly integrate into my app.  I checked out all the regular suspects like Beast, <a href="http://github.com/courtenay/altered_beast/tree/master">Altered Beast</a>, <a href="http://code.google.com/p/savage-beast-2/">Savage Beast 2</a>, and the new <a href="http://github.com/radar/rboard/tree/master">rBoard</a>.</p>
<p>Of the existing rails forums, rBoard showed the most promise but none of them really work well for integrating into an existing, established rails app.  All of the rails options are really intended for standalone use as a forum only.</p>
<p>Next I proceeded to research non-Rails based forums like <a href="http://bbpress.org/">bbPress</a>, <a href="http://www.vbulletin.com/">vBulletin</a>, <a href="http://www.phpbb.com/">phpBB</a> and a handful of others.</p>
<p>I ended up settling on the <a href="http://punbb.informer.com/">punBB</a> forum software, written in PHP.  I chose punBB for a few reasons: 1) it was a lightweight forum system, 2) it seemed to get good reviews online, and 3) I was able to find some existing information online on integrating punBB with Rails.</p>
<p>Terrell Russell wrote two blog posts (<a href="http://weblog.terrellrussell.com/2008/01/running-php-within-rails/">post one</a>, <a href="http://weblog.terrellrussell.com/2008/01/generating-a-rails-and-punbb-and-dokuwiki-shared-cookie/">post two</a>) regarding running PHP from within a Rails environment and how to get punBB (and DokuWiki) running within a Rails app using single sign-on.  I used Terrell&#8217;s posts as a starting point for my project as some of his information is now outdated for both Rails 2.3x and punBB 1.3x.</p>
<p>Now, on to the tutorial.</p>
<p>My next decision was to choose how exactly to integrate the PHP code into my Rails app.  I could put the forum&#8217;s PHP code into my application&#8217;s
<pre class="brush: plain; light: true;">RAILS_ROOT/public/forums/</pre>
<p> directory, or I could install the forums somewhere else on my servers file system.</p>
<p>Since the forums really are their own separate application, and the code is independent of my Rails code, I decided to install punBB on its own and leave it out of my source repository.  This will allow me to maintain/upgrade/modify the forum software without touching my Rails repository.</p>
<blockquote><p>As a side note, your server must be able to run PHP.  My app server is a <a href="http://www.debian.org/">Debian Lenny</a> system and I installed PHP via the normal
<pre class="brush: bash; light: true;">$ sudo aptitude install</pre>
<p> routine.  (Installing PHP on your server is beyond the scope of this tutorial.)</p></blockquote>
<p>I went ahead and setup the punBB files into
<pre class="brush: plain; light: true;">/var/www/punbb</pre>
<p> on my server.  I want users to be able to access the forums by visiting <a href='http://xboxmma.com/forums/'>http://xboxmma.com/forums</a>, so there were a few additional steps I needed to take.</p>
<p>First, when I deploy my app via <a href="http://www.capify.org/">capistrano</a>, I setup a symlink in the public directory to point to my forum installation.  I also copy the forum config file into my Rails app config directory (I&#8217;ll explain why later).  Add the following code to your capistrano deploy file.</p>
<pre class="brush: ruby;">
# RAILS_ROOT/config/deploy.rb
desc &amp;quot;Setup settings for punBB forums&amp;quot;
task :after_symlink, :roles =&amp;gt; [:app] do
  run &amp;quot;ln -nfs /var/www/punbb #{release_path}/public/forums&amp;quot;
  run &amp;quot;cp /var/www/punbb/config.php #{release_path}/config&amp;quot;
end
</pre>
<p>My app server uses <a href="http://wiki.nginx.org/Main">Nginx</a> as the web front end, so I also needed to update my nginx configuration to properly route requests for the new forums.</p>
<p>My existing nginx configuration file looked like this</p>
<pre class="brush: plain;">
server {
        listen  80;
        server_name xboxmma.com;
        root /home/deploy/xboxmma.com/current/public;
        passenger_enabled on;
        access_log off;
        client_max_body_size 20M;

        location ~* \.(ico|css|js|gif|jp?g|png)(\?[0-9]+)?$ {
                expires max;
                break;
        }

        if (-f $request_filename) {
                break;
        if (-f $document_root/system/maintenance.html) {
                rewrite ^(.*)$ /system/maintenance.html break;
        }

        error_page 500 502 503 504 /500.html;
        location = /500.html {
                root /home/deploy/xboxmma.com/current/public;
        }
}
</pre>
<p>I updated it with the following sections</p>
<pre class="brush: plain;">
        location /forums {
                root /var/www/punbb;
                index index.php;

                if (-f $request_filename) {
                        expires 30d;
                        break;
                }

                if (!-e $request_filename) {
                        rewrite ^(.+)$ /forums/index.php?q=$1 last;
                }
        }

        location ~ \.php$ {
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include /opt/nginx/conf/fastcgi_params;
        }

        location ~ /\.ht {
                deny all;
        }
</pre>
<p>The
<pre class="brush: plain; light: true;">location /forums {}</pre>
<p> block will process all requests that are made to the /forums path on my site.  I set the document root to
<pre class="brush: plain; light: true;">/var/www/punbb</pre>
<p> where I installed the punBB software and set the index page to index.php.</p>
<p>The
<pre class="brush: plain; light: true;">location ~ \.php$ {}</pre>
<p> block catches any request for a php page and passes the request along to the php5-cgi processor to handle the request.</p>
<p>The end result config file looks like this:</p>
<pre class="brush: plain;">
server {
        listen  80;
        server_name xboxmma.com;
        root /home/deploy/xboxmma.com/current/public;
        passenger_enabled on;
        access_log off;
        client_max_body_size 20M;

        location ~* \.(ico|css|js|gif|jp?g|png)(\?[0-9]+)?$ {
                expires max;
                break;
        }

        location /forums {
                root /var/www/punbb;
                index index.php;

                if (-f $request_filename) {
                        expires 30d;
                        break;
                }

                if (!-e $request_filename) {
                        rewrite ^(.+)$ /forums/index.php?q=$1 last;
                }
        }

        location ~ \.php$ {
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include /opt/nginx/conf/fastcgi_params;
        }

        location ~ /\.ht {
                deny all;
        }

        if (-f $request_filename) {
                break;
        if (-f $document_root/system/maintenance.html) {
                rewrite ^(.*)$ /system/maintenance.html break;
        }

        error_page 500 502 503 504 /500.html;
        location = /500.html {
                root /home/deploy/xboxmma.com/current/public;
        }
}
</pre>
<p>Now that the boring php processing and routing stuff is out of the way, lets get into the important stuff and look how to integrate the authentication system of punBB and the Rails application.</p>
<p>The &#8220;trick&#8221; we will be using, is to manually set the login cookie for punBB whenever a user logs into the main website (we&#8217;ll delete the cookie as well when the user logs out).  The login cookie format has changed a bit since <a href="http://weblog.terrellrussell.com/2008/01/generating-a-rails-and-punbb-and-dokuwiki-shared-cookie/">Terrell&#8217;s writeup</a>, so I had to get my hands dirty and dig into the punBB PHP codebase to see exactly how they are setting their cookies.</p>
<p>First, add the following code to your application controller (or another controller if you don&#8217;t want/need the methods to be available everywhere).</p>
<pre class="brush: ruby;">
# RAILS_ROOT/app/controllers/application_controller.rb
  def set_shared_cookie
    return true unless Rails.env.production?
    require 'base64'
    expires = Time.now.to_i + 1209600

    begin
      # this sets the punbb cookie
      # it should be called on login from main site to allow unified login
      forumconfig = get_forum_config_data() # private method at bottom
      forumuser = ForumAccount.find_by_username( current_user.username )

      forum_hash = Digest::SHA1.hexdigest( forumuser.salt + Digest::SHA1.hexdigest( expires.to_s ) )
      cookie_value = &amp;quot;#{forumuser.id}|#{forumuser.password}|#{expires.to_s}|&amp;quot;
      cookie_value &amp;lt;&amp;lt; Digest::SHA1.hexdigest( &amp;quot;#{forumuser.salt}#{forumuser.password}#{forum_hash}&amp;quot; )

      cookies[forumconfig[:cookie_name]] = {
        :value =&amp;gt; Base64.encode64( cookie_value ),
        :expires =&amp;gt; 14.days.from_now
      }
    rescue =&amp;gt; e
      Rails.logger.warn &amp;quot;Problem setting punBB cookie #{e.message}&amp;quot;
    end
  end

  def clear_shared_cookie
    return true unless Rails.env.production?
    begin
      # should be called on logout from main site
      forumconfig = get_forum_config_data() # private method at bottom
      cookies[forumconfig[:cookie_name]] = nil
    rescue =&amp;gt; e
      Rails.logger.warn &amp;quot;Problem clearing punBB cookie #{e.message}&amp;quot;
    end
  end

  private

  # Uses regex to parse the php punbb config file
  # taken from: ahgsoftware.com/punbb_sdk/
  def get_forum_config_data
    config_hash = Hash.new
    c = File.read( File.join( RAILS_ROOT, 'config', 'config.php' ) )
    c.scan(/\$(\w*)\s*=\s*['&amp;quot;](.*)['&amp;quot;];/).each do |pair|
      config_hash[pair[0].to_sym] = pair[1]
    end
    config_hash
  end
</pre>
<p>The
<pre class="brush: plain; light: true;">#get_forum_config_data</pre>
<p> private method simply reads the punBB config.php file to get the forum configuration info. (Remember we copied the config.php file over in our capistrano deploy addition.)</p>
<p>Both the
<pre class="brush: plain; light: &quot;true&quot;;">#set_shared_cookie</pre>
<p> method and the
<pre class="brush: plain; light: true;">#clear_shared_cookie</pre>
<p> method will only run during production mode.  I don&#8217;t have punBB setup on my dev system.  If you run a staging server you probably want to change it to check
<pre class="brush: plain; light: true;">Rails.env.development?</pre>
<p> so that the method will also be processed on your staging server.</p>
<p>You&#8217;ll also notice I wrap everything in both methods in a
<pre class="brush: ruby; light: true;">begin ... rescue</pre>
<p> block.  I don&#8217;t want errors in the cookie creation/deletion to throw errors to the users, so I just log then gracefully for now.</p>
<p>Let&#8217;s do a quick run through on the #set_shared_cookie method.  First we set an integer expiration date to 14 days in the future (the default punBB cookie length).  Next we read the forum config data and find the existing user record from the punBB database via the ForumAccount model.  We&#8217;ll look at the ForumAccount model in a bit.  </p>
<p>Next we set the cookie value so it appears in the same format the punBB will expect when it reads the cookie back in and write the cookie to the session.</p>
<p>For XBoxMMA.com I use <a href="http://github.com/binarylogic/authlogic/tree/master">Authlogic</a> as the authentication system, so I call the set_shared_cookie method from my user_sessions controller after a new session is created.  I also call it from my users_controller when a new user is created.  I call the clear_shared_cookie method when the user logs out.</p>
<p>Now that we&#8217;ve seen how to make the shared cookie, lets look at the models used to access the punBB database tables.</p>
<p>I use a separate database for punBB instead of dumping the tables into my rails app DB, so I added an extra section to my
<pre class="brush: plain; light: true;">RAILS_ROOT/config/database.yml</pre>
<p> file.</p>
<pre class="brush: plain;">
forums_production:
  adapter: mysql
  database: xboxmma_forum
  username: xboxmma
  password: password
  host: localhost
  encoding: utf8
  socket: /var/run/mysqld/mysqld.sock
</pre>
<p>If you are using a staging environment, be sure to add a &#8220;forums_staging&#8221; section as well.</p>
<p>Next, I added two new models to access the punBB DB.</p>
<pre class="brush: ruby;">
# app/models/forum.rb
class Forum &amp;lt; ActiveRecord::Base
  self.abstract_class = true
  establish_connection &amp;quot;forums_#{Rails.env}&amp;quot;
end

# app/models/forum_account.rb
class ForumAccount &amp;lt; Forum
  set_table_name 'users' # add the table prefix if you set one in punBB

  def encrypt_and_save_new_password( _password )
    write_attribute( &amp;quot;password&amp;quot;, forum_hash( _password ) )
    save
  end

  private

  def forum_hash( _str )
    Digest::SHA1.hexdigest( self.salt + Digest::SHA1.hexdigest( _str ) )
  end

end
</pre>
<p>The
<pre class="brush: ruby; light: true;">#encrypt_and_save_new_password</pre>
<p> method should be called anytime your user updates their password in your Rails app.  This method will update their forum password at the same time and keep the two in sync.</p>
<p>Now you have Rails models setup that will be able to access your punBB DB (you will remember the ForumAccount model we referenced earlier in the set_shared_cookie method).</p>
<p>Everything should now be working for you.  Don&#8217;t forget to run the
<pre class="brush: plain; light: true;">admin/install.php</pre>
<p> script as well to setup your initial punBB configuration.</p>
]]></content:encoded>
			<wfw:commentRss>http://craigjolicoeur.com/blog/how-to-integrate-punbb-into-an-existing-ruby-on-rails-application/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Cerberus to Build Rails</title>
		<link>http://craigjolicoeur.com/blog/using-cerberus-to-build-rails</link>
		<comments>http://craigjolicoeur.com/blog/using-cerberus-to-build-rails#comments</comments>
		<pubDate>Sun, 24 May 2009 18:38:18 +0000</pubDate>
		<dc:creator>Craig</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[cerberus]]></category>
		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http://craigjolicoeur.com/blog/?p=127</guid>
		<description><![CDATA[A nice guide on how to use the latest version of Cerberus to build Rails with multiple versions of Ruby.]]></description>
			<content:encoded><![CDATA[<p>Over the weekend, I released version 0.5 of the <a href="http://cerberus.rubyforge.org">Cerberus gem</a>.</p>
<p>The release included some better test support, as well as support for git branches and custom settings file inclusion for the Maven2 builder.</p>
<p>No, sooner had version 0.5 been released, then we began work in earnest on version 0.6</p>
<p><a href="http://twitter.com/mikeg1">Mike Gunderloy</a> has been working on adding features to Cerberus to support using a custom Ruby script as a project builder.  The main reason, is to build the Rails project using their ci_setup.rb, CruiseControl build script.</p>
<p>The current code with Ruby builder support can be found in the <a href="http://github.com/cpjolicoeur/cerberus/tree/ruby_builder">ruby_builder branch of the main repository</a> at the moment.</p>
<p>In addition, <a href="http://afreshcup.com/2009/05/24/building-rails-with-cerberus-and-multiruby/">Mike wrote an excellent blog post on how he is building Rails using Cerberus and multiruby</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://craigjolicoeur.com/blog/using-cerberus-to-build-rails/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New Cerberus Release</title>
		<link>http://craigjolicoeur.com/blog/new-cerberus-release</link>
		<comments>http://craigjolicoeur.com/blog/new-cerberus-release#comments</comments>
		<pubDate>Mon, 16 Feb 2009 14:07:45 +0000</pubDate>
		<dc:creator>Craig</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[cerberus]]></category>

		<guid isPermaLink="false">http://craigjolicoeur.com/blog/?p=89</guid>
		<description><![CDATA[Cerberus 0.4.4 has been officially released]]></description>
			<content:encoded><![CDATA[<p>Over the past month there have been several small point releases to <a href="http://cerberus.rubyforge.org">Cerberus</a>, the most recent being <a href="http://rubyforge.org/forum/forum.php?forum_id=30381">version 0.4.4 released just last night</a>.</p>
<p>The latest changes include some minor bugfixes, better RSpec support, the ability to write and use your own custom publishers, and a cron-like scheduling option for the &#8216;buildall&#8217; command.</p>
<p>Also of important note, the official tracker for issues and bugs has been moved from RubyForge to <a href="http://cpjolicoeur.lighthouseapp.com/projects/22299-cerberus/overview">a new Lighthouse tracker</a>.  Also, a <a href="http://groups.google.com/group/cerberusci">mailing list / public forum has been setup</a> for discussion.</p>
<p>As usual, you can grab the newest gem from RubyForge or <a href="http://github.com/cpjolicoeur/cerberus">download the source code at GitHub</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://craigjolicoeur.com/blog/new-cerberus-release/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cerberus 0.4.0 Released</title>
		<link>http://craigjolicoeur.com/blog/cerberus-040-released</link>
		<comments>http://craigjolicoeur.com/blog/cerberus-040-released#comments</comments>
		<pubDate>Tue, 30 Dec 2008 14:12:40 +0000</pubDate>
		<dc:creator>Craig</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[cerberus]]></category>
		<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[Gems]]></category>

		<guid isPermaLink="false">http://craigjolicoeur.com/blog/?p=87</guid>
		<description><![CDATA[Version 0.4.0 of Cerberus Continuous Integration server has been officially released.]]></description>
			<content:encoded><![CDATA[<p><a href="http://rubyforge.org/projects/cerberus/"><strong>Cerberus 0.4.0</strong> was officially released last night on RubyForge</a>.</p>
<p>The new major features include the Twitter publisher support that I added and the Git SCM support added by <a href="http://github.com/notch8">Rob Kaufman</a>.  Several other minor updates and bug fixes were also included.</p>
<p>Cerberus is a lightweight Continuous Integration package written in Ruby.  The package hadn&#8217;t been under active maintenance lately, but I hope to be able to get some new work done on the project now that I am on the development team.</p>
]]></content:encoded>
			<wfw:commentRss>http://craigjolicoeur.com/blog/cerberus-040-released/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cerberus Gets Twitter Support</title>
		<link>http://craigjolicoeur.com/blog/cerberus-gets-twitter-support</link>
		<comments>http://craigjolicoeur.com/blog/cerberus-gets-twitter-support#comments</comments>
		<pubDate>Sun, 21 Dec 2008 14:37:16 +0000</pubDate>
		<dc:creator>Craig</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[cerberus]]></category>
		<category><![CDATA[rubyonrails]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://craigjolicoeur.com/blog/?p=83</guid>
		<description><![CDATA[I have added Twitter publisher support to Cerberus CI server.]]></description>
			<content:encoded><![CDATA[<p>Recently, I set up <a href="http://cerberus.rubyforge.org/">Cerberus</a> for continuous integration for our internal project at <a href="http://www.parkassist.com">Park Assist</a>.  I chose Cerberus over other CI servers like <a href="http://cruisecontrolrb.thoughtworks.com/">CruiseControl.rb</a> due to its lightweight install and setup and the fact that it doesn&#8217;t need to run constantly in the background and consumes fewer resources.</p>
<p>Unfortunately, Cerberus doesn&#8217;t seem to still be under active maintenance as the most recently commit on the main RubyForge SVN repository was back in July of 2007.  Since Cerberus was written under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT License</a>, I made a copy of the repository and <a href="http://github.com/cpjolicoeur/cerberus/tree/master">posted it to GitHub</a>.</p>
<p>At the moment, Cerberus appeared to be missing two major features as far as I was concerned.  First, no <a href="http://git.or.cz/">git</a> support for an SCM and second, no <a href="http://twitter.com">Twitter</a> support for posting build success and failure notifications.</p>
<p>A quick search of Github revealed that <a href="http://github.com/notch8/cerberus/commit/aac64122775aaf531ecccb32eb48d4f6853a3590">Rob Kaufman had already added git support</a> so I went ahead and <a href="http://github.com/cpjolicoeur/cerberus/commit/bcbeac8962f421d7319100dfbae99942021920d6">added Twitter support to Cerberus</a>.</p>
<p>I plan on pulling the git support into my git repository and submitting a patch to the official Cerberus project.  Hopefully the original developers are still around and willing to update the repository.  If not, feel free to clone or fork my copy of Cerberus for the new features.</p>
]]></content:encoded>
			<wfw:commentRss>http://craigjolicoeur.com/blog/cerberus-gets-twitter-support/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ParseHTML 1.12 Released</title>
		<link>http://craigjolicoeur.com/blog/parsehtml-112-released</link>
		<comments>http://craigjolicoeur.com/blog/parsehtml-112-released#comments</comments>
		<pubDate>Thu, 21 Aug 2008 16:55:10 +0000</pubDate>
		<dc:creator>Craig</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[ParseHTML]]></category>
		<category><![CDATA[Parser]]></category>

		<guid isPermaLink="false">http://craigjolicoeur.com/?p=64</guid>
		<description><![CDATA[Version 1.12 of the ParseHTML library has been released.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve updated the <a href="http://github.com/cpjolicoeur/parsehtml">ParseHTML code on github</a> to the latest 1.12 version.</p>
<p>I haven&#8217;t done much work with the ParseHTML library, simply because I wasn&#8217;t actively doing development on the <a href="http://github.com/cpjolicoeur/clothblue">ClothBlue HTML-to-Markdown library</a>.  ClothBlue is the reason I wrote ParseHTML in the first place.  Well, I&#8217;ve had some downtime and figured I would revive the ClothBlue rewrite effort and that meant getting ParseHTML up to snuff.</p>
<p>The library should be fully working now as most of the previously reported bugs have been sorted out.  If you find any issues or new features you want added, just let me know.</p>
]]></content:encoded>
			<wfw:commentRss>http://craigjolicoeur.com/blog/parsehtml-112-released/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby Iconv to the Rescue</title>
		<link>http://craigjolicoeur.com/blog/ruby-iconv-to-the-rescue</link>
		<comments>http://craigjolicoeur.com/blog/ruby-iconv-to-the-rescue#comments</comments>
		<pubDate>Mon, 14 Jul 2008 13:33:20 +0000</pubDate>
		<dc:creator>Craig</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[ascii]]></category>
		<category><![CDATA[iconv]]></category>
		<category><![CDATA[utf8]]></category>

		<guid isPermaLink="false">http://craigjolicoeur.com/?p=38</guid>
		<description><![CDATA[How Iconv can help convert UTF-8 characters in to ascii output.]]></description>
			<content:encoded><![CDATA[<p>I ran into a situation today while working on a client project that was resulting in some &#8220;funky&#8221; output.</p>
<p>I&#8217;ve been using <a href="http://sporkmonger.com/projects/feedtools/">Bob Aman&#8217;s standard FeedTools library</a> to grab and parse some RSS feeds for output in a WordPress site.  </p>
<div style="text-align:center;"><img src="http://craigjolicoeur.com/blog/wp-content/uploads/2008/07/utf8-issues.jpg" alt="utf8_issues.jpg" border="0" width="450" height="156" class="center" /></div>
<p>Now, it was obvious to me this had something to do with character encoding issues so I dug in to find out the problem.  It turns out FeedTools converts the feeds it parses to <a href="http://en.wikipedia.org/wiki/UTF-8">UTF-8</a> encoding, which is great, but can result in some strange characters in the string depending on what the original feed encoding was.</p>
<p>Viewing the native feeds in a feed reader I could see they were simply quotes, apostrophes and ellipses characters.  I needed a way to either convert these character strings into <a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> printable characters or simply discard them altogether. </p>
<p>I didn&#8217;t want to go through the process of setting up a translation table for every possible character code that might possibly show up in a feed title, so I simply chose to discard the &#8220;unprintable&#8221; strings completely.  I came across <a href="http://www.jroller.com/obie/tags/unicode">this post by Obie Fernandez</a> and decided his simple method would work for me.</p>
<pre class="brush: ruby;">
require 'iconv'

class String
  def to_ascii_iconv
    converter = Iconv.new('ASCII//IGNORE//TRANSLIT', 'UTF-8')
    converter.iconv(self).unpack('U*').select{ |cp| cp &lt; 127 }.pack('U*')
  end
end
</pre>
<p><a href="http://www.ruby-doc.org/stdlib/libdoc/iconv/rdoc/index.html">Ruby&#8217;s built-in Iconv library</a> can be used for charset conversions.  I extended the <code>String</code> class to include a new <code>to_ascii_iconv</code> method.  This method creates a new Iconv converter that will convert from UTF-8 encoding to ASCII encoding.  The <code>IGNORE</code> and <code>TRANSLIT</code> flags tell the converter to ignore errors and transliterate accented chracters to an appropriate charcter in the ASCII charset.  Next, I use the newly created converter to do the conversion and then strip out any characters with decimal values higher than 127 (non-ASCII printable characters).</p>
<p>The results are exactly what I needed.  No &#8220;funky&#8221; characters in my output.</p>
]]></content:encoded>
			<wfw:commentRss>http://craigjolicoeur.com/blog/ruby-iconv-to-the-rescue/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

