<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Late to the Party: Tag ruby</title>
    <link>http://cwilliams.textdriven.com/articles/tag/ruby?tag=ruby</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Ruby. Rails. Stuff.</description>
    <item>
      <title>Aptana backs RDT, hires me</title>
      <description>&lt;p&gt;I'm proud to announce today that &lt;a href="http://www.aptana.com"&gt;Aptana&lt;/a&gt; has hired me to work full-time on &lt;a href="http://rubyeclipse.sourceforge.net"&gt;RDT&lt;/a&gt;, RadRails and integrating that work with their existing Aptana IDE which focuses on CSS, HTML and Javascript.&lt;/p&gt;

&lt;div style="background-color: white; text-align: center;"&gt;&lt;a href="http://www.aptana.com/rdt.html"&gt;&lt;img src="/images/aptana_radrails_rdt_ajax_rails_blue.gif" alt=""aptana-radrails-rdt ajax on rails/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;This announcement means that RDT will now have commercial backing (but will remain open-source and free!) and that you should see RDT and RadRails move forward at a much quicker pace than in the past.&lt;/p&gt;

&lt;p&gt;This is also great news for RadRails users and Rails developers in general as integrating the two will give you code completion, outlines, help, debugging and much more across the entire stack - from model to controller to the HTML, ruby code, CSS and Javascript that make up your views.&lt;/p&gt;

</description>
      <pubDate>Sat, 21 Apr 2007 16:41:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:c68f2859-5c20-4685-a61e-da26f1583f63</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2007/04/21/aptana-backs-rdt-hires-me</link>
      <category>Programming</category>
      <category>Personal</category>
      <category>Web design</category>
      <category>Ruby</category>
      <category>Rails</category>
      <category>aptana</category>
      <category>ruby</category>
      <category>Rails</category>
      <category>commercial</category>
      <category>sponsor</category>
      <category>RDT</category>
      <category>radrails</category>
      <category>ide</category>
      <category>eclipse</category>
      <category>announcement</category>
    </item>
    <item>
      <title>RDT gets Refactoring support</title>
      <description>&lt;p&gt;Well the &lt;a href="http://jutopia.tirsen.com/articles/2007/01/30/and-you-didnt-think-it-could-be-done"&gt;cat is out&lt;/a&gt; &lt;a href="http://on-ruby.blogspot.com/2007/02/ruby-refactoring-rubicon.html"&gt;of the bag&lt;/a&gt;: &lt;a href="http://r2.ifsoftware.ch/trac"&gt;Mirko Stocker and his cohorts&lt;/a&gt; have committed their refactoring support to &lt;a href="http://rubyeclipse.sourceforge.net/"&gt;&lt;abbr title="Ruby Development Tool"&gt;RDT&lt;/abbr&gt;&lt;/a&gt;'s Subversion repository.&lt;/p&gt;

&lt;p&gt;This means we'll be able to roll out 0.9.0 with this support. Right now we're working to get it integrated into the build process, so that it will begin showing up in our new builds. I'm pretty excited myself, because I've had little chance to try out their work.&lt;/p&gt;

&lt;p&gt;This refactoring support joins other recent work in RDT which allows us to do some occurence marking of variables, code completion and other exciting features (thanks &lt;a href="http://jayunit.net/"&gt;Jason&lt;/a&gt;!). There's certainly a long way yet to go to get the tools polished - for instance we still have a hard time doing code completion (or much else) on a file which is being edited while the syntax is temporarily incorrect (the &lt;a href="http://www.jruby.org"&gt;JRuby&lt;/a&gt; parser is great, but not so forgiving) - but we're constantly marching forward.&lt;/p&gt;

&lt;p&gt;Look for &lt;a href="http://rubyeclipse.mktec.com/cgi-bin/trac.py/roadmap"&gt;0.9.0 to come out sometime this month (we're aiming for the 15th)&lt;/a&gt;!&lt;/p&gt;</description>
      <pubDate>Tue, 06 Feb 2007 16:37:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:1af8c68c-4cb7-4341-a638-b8e396d9f737</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2007/02/06/rdt-gets-refactoring-support</link>
      <category>Programming</category>
      <category>Personal</category>
      <category>Ruby</category>
      <category>Java</category>
      <category>refactoring</category>
      <category>ruby</category>
      <category>eclipse</category>
      <category>ide</category>
    </item>
    <item>
      <title>Patterns in Ruby: Decorator revisited</title>
      <description>&lt;p&gt;A while back I wrote an article describing some possible ways to implement a 
&lt;a href="http://cwilliams.textdriven.com/articles/2006/10/27/patterns-in-ruby-template-method"&gt;Decorator pattern in Ruby&lt;/a&gt;. 
I've stumbled across several mentions of 
yet another idiom used so often in the Rails codebase that they've extracted 
it into the latest ActiveSupport. That idiom is 
&lt;a href="http://weblog.rubyonrails.org/2006/4/26/new-in-rails-module-alias_method_chain"&gt;&lt;code&gt;alias_method_chain&lt;/code&gt;&lt;/a&gt;,
and it's a good example of a decorator implementation.&lt;/p&gt;

&lt;p&gt;This idiom is a codified example of using the alias approach I briefly mentioned in the earlier article. In that 
article we aliased the original implementation with anew name, and set up a new implementation of our method 
(often delegating to the original) with the original's name. A quick example makes this clear:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Window&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;draw&lt;/span&gt;
    &lt;span class="comment"&gt;# do some drawing here...&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="comment"&gt;# some code...&lt;/span&gt;

&lt;span class="comment"&gt;# creates a 'copy' of draw method, but gives it&lt;/span&gt;
&lt;span class="comment"&gt;# the name/selector 'original_draw'&lt;/span&gt;
  &lt;span class="keyword"&gt;alias&lt;/span&gt; &lt;span class="symbol"&gt;:original_draw&lt;/span&gt; &lt;span class="symbol"&gt;:draw&lt;/span&gt; 

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;draw&lt;/span&gt;
    &lt;span class="ident"&gt;draw_vertical_scrollbar&lt;/span&gt;
    &lt;span class="ident"&gt;original_draw&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;&lt;code&gt;alias_method_chain&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;In &lt;a href="http://weblog.rubyonrails.org/2006/4/26/new-in-rails-module-alias_method_chain"&gt;Rails 1.2 (ActiveSupport specifically)&lt;/a&gt;, the Rails core team found many instances of this pattern 
and codified a new method on the class Module, &lt;code&gt;alias_method_chain&lt;/code&gt;. This class-level method encapsulates this 
pattern of wrapping existing methods with additional behavior.&lt;/p&gt;

&lt;p&gt;Here's a specific example, showing how they would wrap rendering with layouts:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;alias_method&lt;/span&gt; &lt;span class="symbol"&gt;:render_with_no_layout&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:render&lt;/span&gt;
&lt;span class="ident"&gt;alias_method&lt;/span&gt; &lt;span class="symbol"&gt;:render&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:render_with_a_layout&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this small code snippet, they are creating a small chain of methods to wrap the existing render behavior. 
Now calls to render will be routed to &lt;code&gt;render_with_a_layout&lt;/code&gt; and then on to the original render implementation 
(which is now aliased to &lt;code&gt;render_with_no_layout&lt;/code&gt;). So they coded up &lt;code&gt;alias_method_chain&lt;/code&gt; which simply does 
the wrapping for them (using naming conventions):&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Module&lt;/span&gt;
  &lt;span class="comment"&gt;# Encapsulates the common pattern of:&lt;/span&gt;
  &lt;span class="comment"&gt;#&lt;/span&gt;
  &lt;span class="comment"&gt;#   alias_method :foo_without_feature, :foo&lt;/span&gt;
  &lt;span class="comment"&gt;#   alias_method :foo, :foo_with_feature&lt;/span&gt;
  &lt;span class="comment"&gt;#&lt;/span&gt;
  &lt;span class="comment"&gt;# With this, you simply do:&lt;/span&gt;
  &lt;span class="comment"&gt;#&lt;/span&gt;
  &lt;span class="comment"&gt;#   alias_method_chain :foo, :feature&lt;/span&gt;
  &lt;span class="comment"&gt;#&lt;/span&gt;
  &lt;span class="comment"&gt;# And both aliases are set up for you.&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;alias_method_chain&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;target&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;feature&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;alias_method&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{target}&lt;/span&gt;_without_&lt;span class="expr"&gt;#{feature}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="ident"&gt;target&lt;/span&gt;
    &lt;span class="ident"&gt;alias_method&lt;/span&gt; &lt;span class="ident"&gt;target&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{target}&lt;/span&gt;_with_&lt;span class="expr"&gt;#{feature}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Please note that if they were to replace their existing two calls to &lt;code&gt;alias_method&lt;/code&gt; above, they would need to tweak the naming a little
(the methods would become &lt;code&gt;render_without_layout&lt;/code&gt; and &lt;code&gt;render_with_layout&lt;/code&gt; as opposed to
&lt;code&gt;render_with_no_layout&lt;/code&gt; and &lt;code&gt;render_with_a_layout&lt;/code&gt; respectively).&lt;/p&gt;</description>
      <pubDate>Tue, 26 Dec 2006 18:38:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:42654a54-afbd-4e14-932e-8ef2ce31b561</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2006/12/26/patterns-in-ruby-decorator-revisited</link>
      <category>Programming</category>
      <category>Ruby</category>
      <category>Rails</category>
      <category>decorator</category>
      <category>patterns</category>
      <category>ruby</category>
      <category>alias</category>
      <category>chain</category>
      <category>method</category>
    </item>
    <item>
      <title>Patterns in Ruby: Observer Pattern</title>
      <description>&lt;p&gt;Another easy to implement pattern in Ruby is the &lt;a href="http://en.wikipedia.org/wiki/Observer_pattern"&gt;Observer pattern&lt;/a&gt;.
The Observer pattern is a publish/subscribe mechanism where an objects can register to be notified of state changes (or &lt;em&gt;observe&lt;/em&gt; changes) on another &lt;em&gt;observed&lt;/em&gt; object. This pattern may often become refactored into a more general event framework (where objects fire events off into queues to which there are listeners subscribed).&lt;/p&gt;

&lt;h2&gt;The basic implementation&lt;/h2&gt;

&lt;p&gt;Here's a look at a simple ruby implementation:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Observable&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
    &lt;span class="attribute"&gt;@listeners&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;register_listener&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;listener&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@listeners&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;listener&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;unregister_listener&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;listener&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@listeners&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;remove&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;listener&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;run&lt;/span&gt;
    &lt;span class="ident"&gt;notify_listeners&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Hello!&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;protected&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;notify_listeners&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;event&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@listeners&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;l&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;l&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;notify&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;event&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Listener&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;observable&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;observable&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;register_listener&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;notify&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;event&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Notified of '&lt;span class="expr"&gt;#{event}&lt;/span&gt;'&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;observable&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Observable&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
&lt;span class="ident"&gt;listener&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Listener&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;observable&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="ident"&gt;observable&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;run&lt;/span&gt;                        &lt;span class="comment"&gt;#=&amp;gt; Notified of 'Hello!'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The pattern itself in this form is pretty general. So general, in fact, that there is a module mixin of Observer inside the standard ruby library (observer.rb).
There's some good documentation in there, and it provides a simpler path to this implementation:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;observer&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;TV&lt;/span&gt;
  &lt;span class="ident"&gt;include&lt;/span&gt; &lt;span class="constant"&gt;Observable&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;channel&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@channel&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;channel&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;up&lt;/span&gt;
    &lt;span class="attribute"&gt;@channel&lt;/span&gt; &lt;span class="punct"&gt;+=&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;
    &lt;span class="ident"&gt;changed&lt;/span&gt;
    &lt;span class="ident"&gt;notify_observers&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="attribute"&gt;@channel&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ChannelWatcher&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;tv&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;tv&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;add_observer&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;update&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;channel&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Changed channel to &lt;span class="expr"&gt;#{channel}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;tv&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;TV&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;160&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="ident"&gt;watcher&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ChannelWatcher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;tv&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="ident"&gt;tv&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;up&lt;/span&gt;                              &lt;span class="comment"&gt;#=&amp;gt; Changed channel to 161&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Please be aware that the API is a little different from my initial example.&lt;/p&gt;

&lt;h2&gt;Moving towards events&lt;/h2&gt;

&lt;p&gt;Both of the above implementations rely on a generic observer pattern, but the Observer pattern can often evolve into a simple event mechanism. The difference is that instead of firing a generic event object via a generic notify method, the move towards events uses unique method names, and filters events to notify only those interested in the type of event occurring.&lt;/p&gt;

&lt;p&gt;Let's see a TV example where we move towards a more specialized event firing version of the pattern:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;observer&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;TV&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;channel&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@channel&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;channel&lt;/span&gt;
    &lt;span class="attribute"&gt;@listeners&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;add_listener&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;listener&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@listeners&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;listener&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;up&lt;/span&gt;
    &lt;span class="attribute"&gt;@channel&lt;/span&gt; &lt;span class="punct"&gt;+=&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;
    &lt;span class="attribute"&gt;@listeners&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;l&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;l&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;channel_increased&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="attribute"&gt;@channel&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;down&lt;/span&gt;
    &lt;span class="attribute"&gt;@channel&lt;/span&gt; &lt;span class="punct"&gt;-=&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;
    &lt;span class="attribute"&gt;@listeners&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;l&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;l&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;channel_decreased&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="attribute"&gt;@channel&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ChannelUpWatcher&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;tv&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;tv&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;add_listener&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;channel_increased&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;channel&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Changed channel to &lt;span class="expr"&gt;#{channel}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;channel_decreased&lt;/span&gt;
    &lt;span class="comment"&gt;# do nothing...&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;tv&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;TV&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;160&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="ident"&gt;watcher&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ChannelUpWatcher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;tv&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="ident"&gt;tv&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;up&lt;/span&gt;                              &lt;span class="comment"&gt;#=&amp;gt; Changed channel to 161&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this instance we can fire off events for surfing the Tv upwards or downwards (in channels) separately, though we still register listeners into a generic pool, and listeners are expected to contain both event methods. Variations of this can be done to register listeners into sub-groups upon registration by calling unique methods names for each registration, or by passing in a Filter object that can be used to filter to the events the listener cares about. In filtering at registration we can avoid listeners having to implement every event firing method and minimize the number of events fired off.&lt;/p&gt;

&lt;p&gt;One illustration of this observer based event model is the &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/event/package-summary.html"&gt;Java Swing events API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Extending the pattern towards this event firing mechanism even further we'd likely move into using queues and firing events off to the queues themselves rather than directly to observers. Observers would then become subscribers to the queues.&lt;/p&gt;

&lt;h2&gt;Using blocks and procs&lt;/h2&gt;

&lt;p&gt;The Observer pattern as described above is the typical pattern followed in most languages without closures, lambdas or functors.
In Ruby we have the ability to throw around closures/blocks so we can take the pattern a little further. &lt;/p&gt;

&lt;p&gt;Let's revisit our original implementation, but let's add the ability to register the callback function to be performed upon notification.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Observable&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
    &lt;span class="attribute"&gt;@listeners&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;register_listener&lt;/span&gt;&lt;span class="punct"&gt;(&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;blk&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@listeners&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;blk&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;unregister_listener&lt;/span&gt;&lt;span class="punct"&gt;(&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;blk&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@listeners&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;remove&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;blk&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;run&lt;/span&gt;
    &lt;span class="ident"&gt;notify_listeners&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Hello!&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;protected&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;notify_listeners&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;event&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@listeners&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;l&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;l&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;event&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Listener&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;observable&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;observable&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;register_listener&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;event&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Notified of '&lt;span class="expr"&gt;#{event}&lt;/span&gt;'&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;}&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;observable&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Observable&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
&lt;span class="ident"&gt;listener&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Listener&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;observable&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="ident"&gt;observable&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;run&lt;/span&gt;                        &lt;span class="comment"&gt;#=&amp;gt; Notified of 'Hello!'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is the model illustrated in the &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/tk/rdoc/index.html"&gt;Tk bindings for Ruby&lt;/a&gt; - you can see examples of usage in &lt;a href="http://www.rubycentral.com/book/ext_tk.html#S3"&gt;Programming Ruby's section on binding events in Tk&lt;/a&gt;. That section and &lt;a href="http://www.rubycentral.com/book/tut_containers.html#UG"&gt;their section on blocks as closures&lt;/a&gt; begin to broach the how closures capture the context in which they were defined - allowing for some very interesting and complex behavior in using blocks and procs as event or observer callbacks (allowing you to refer to objects available at the scope of the block definition, not when the callback/block execution occurs).&lt;/p&gt;</description>
      <pubDate>Thu, 02 Nov 2006 20:10:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:d8f25c41-047b-4a66-ab91-c18dd814ebe4</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2006/11/02/patterns-in-ruby-observer-pattern</link>
      <category>Programming</category>
      <category>Ruby</category>
      <category>ruby</category>
      <category>patterns</category>
      <category>observer</category>
      <category>programming</category>
      <category>design</category>
    </item>
    <item>
      <title>Patterns in Ruby: Singleton Pattern</title>
      <description>&lt;p&gt;The &lt;a href="http://en.wikipedia.org/wiki/Singleton_pattern"&gt;Singleton pattern&lt;/a&gt; is the black sheep of the pattern family. 
It was easy to grasp, developers everywhere applied it liberally, and an inevitable backlash came against its overuse.&lt;/p&gt;

&lt;p&gt;I won't make any judgments or reccomendations on when to use it - but I will show you just how easy it is to apply in Ruby.&lt;/p&gt;

&lt;p&gt;The literal translation of the pattern is to create a class level instance method and to hide the &lt;code&gt;new&lt;/code&gt; method.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;    
&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Example&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
    &lt;span class="comment"&gt;# do something?&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.instance&lt;/span&gt;
    &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="attribute"&gt;@@instance&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="keyword"&gt;defined?&lt;/span&gt; &lt;span class="attribute"&gt;@@instance&lt;/span&gt;
    &lt;span class="attribute"&gt;@@instance&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;new&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="ident"&gt;private_class_method&lt;/span&gt;  &lt;span class="symbol"&gt;:new&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="constant"&gt;Example&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;instance&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;object_id&lt;/span&gt;  &lt;span class="comment"&gt;#=&amp;gt; 21783380&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="constant"&gt;Example&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;instance&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;object_id&lt;/span&gt;  &lt;span class="comment"&gt;#=&amp;gt; 21783380&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This example gives you the basic idea, but it doesn't cover many cases you'd like to handle, like cloning or &lt;code&gt;dup&lt;/code&gt;ing the singleton. It also doesn't hide the class level &lt;code&gt;allocate&lt;/code&gt; method, which means a sneaky coder could still create another instance through some hacking.
Lastly, it's not thread safe.&lt;/p&gt;

&lt;p&gt;Luckily, Ruby already provides a module for making classes singletons. It's in the standard library, inside 'singleton.rb'.
Here's how you use it:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;    
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;singleton&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Example&lt;/span&gt;
  &lt;span class="ident"&gt;include&lt;/span&gt; &lt;span class="constant"&gt;Singleton&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This module will do the same thing as my example above but will also handle hiding &lt;code&gt;allocate&lt;/code&gt;, overriding the &lt;code&gt;clone&lt;/code&gt; and &lt;code&gt;dup&lt;/code&gt; methods, and is thread safe. The library file itself contains a bunch of examples of its usage, and those interested should definitely read through it.&lt;/p&gt;

&lt;p&gt;One thing to note about these implementations is that the instance method takes no arguments, so none are passed on to the object's constructor. This makes sense because the first time instance is called those will be the arguments used for this global instance. Setters are typically more appropriate for most singletons.&lt;/p&gt;

&lt;p&gt;Since singletons are global in nature setters should be at the class level. As an extra bonus here's the implementation of the class level &lt;code&gt;attr_&lt;/code&gt; methods to generate the vanilla getter/setter methods (stolen from &lt;a href="http://www.rubyonrails.org"&gt;Rails&lt;/a&gt;).&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Class&lt;/span&gt; &lt;span class="comment"&gt;# :nodoc:&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;cattr_reader&lt;/span&gt;&lt;span class="punct"&gt;(*&lt;/span&gt;&lt;span class="ident"&gt;syms&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;syms&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;flatten&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;sym&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="ident"&gt;class_eval&lt;/span&gt;&lt;span class="punct"&gt;(&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="constant"&gt;EOS&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;__FILE__&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;__LINE__&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;span class="string"&gt;
        unless defined? @@&lt;span class="expr"&gt;#{sym}&lt;/span&gt;
          @@&lt;span class="expr"&gt;#{sym}&lt;/span&gt; = nil
        end

        def self.&lt;span class="expr"&gt;#{sym}&lt;/span&gt;
          @@&lt;span class="expr"&gt;#{sym}&lt;/span&gt;
        end

        def &lt;span class="expr"&gt;#{sym}&lt;/span&gt;
          @@&lt;span class="expr"&gt;#{sym}&lt;/span&gt;
        end
&lt;/span&gt;&lt;span class="constant"&gt;      EOS&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;cattr_writer&lt;/span&gt;&lt;span class="punct"&gt;(*&lt;/span&gt;&lt;span class="ident"&gt;syms&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;syms&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;flatten&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;sym&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="ident"&gt;class_eval&lt;/span&gt;&lt;span class="punct"&gt;(&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="constant"&gt;EOS&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;__FILE__&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;__LINE__&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;span class="string"&gt;
        unless defined? @@&lt;span class="expr"&gt;#{sym}&lt;/span&gt;
          @@&lt;span class="expr"&gt;#{sym}&lt;/span&gt; = nil
        end

        def self.&lt;span class="expr"&gt;#{sym}&lt;/span&gt;=(obj)
          @@&lt;span class="expr"&gt;#{sym}&lt;/span&gt; = obj
        end

        def &lt;span class="expr"&gt;#{sym}&lt;/span&gt;=(obj)
          @@&lt;span class="expr"&gt;#{sym}&lt;/span&gt; = obj
        end
&lt;/span&gt;&lt;span class="constant"&gt;      EOS&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;cattr_accessor&lt;/span&gt;&lt;span class="punct"&gt;(*&lt;/span&gt;&lt;span class="ident"&gt;syms&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;cattr_reader&lt;/span&gt;&lt;span class="punct"&gt;(*&lt;/span&gt;&lt;span class="ident"&gt;syms&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;cattr_writer&lt;/span&gt;&lt;span class="punct"&gt;(*&lt;/span&gt;&lt;span class="ident"&gt;syms&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we can create a more realistic singleton:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;    
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;singleton&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;JimmyGrimble&lt;/span&gt;
  &lt;span class="ident"&gt;include&lt;/span&gt; &lt;span class="constant"&gt;Singleton&lt;/span&gt;
  &lt;span class="ident"&gt;cattr_reader&lt;/span&gt; &lt;span class="symbol"&gt;:boots&lt;/span&gt;
  &lt;span class="ident"&gt;cattr_accessor&lt;/span&gt; &lt;span class="symbol"&gt;:football&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 31 Oct 2006 14:26:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:9087a930-fcc2-46d1-9852-37f5528f4c57</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2006/10/31/patterns-in-ruby-singleton-pattern</link>
      <category>Programming</category>
      <category>Ruby</category>
      <category>design</category>
      <category>patterns</category>
      <category>ruby</category>
      <category>singleton</category>
      <category>programming</category>
    </item>
    <item>
      <title>Patterns in Ruby: Decorator Pattern</title>
      <description>&lt;p&gt;I've been a fan of the work that was done by the Gang of Four on &lt;a href="http://www.amazon.com/gp/product/0201633612?ie=UTF8&amp;amp;tag=latetothepart-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0201633612"&gt;Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley Professional Computing Series)&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=latetothepart-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0201633612" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;, Martin Fowler's &lt;a href="http://www.amazon.com/gp/product/0201485672?ie=UTF8&amp;amp;tag=latetothepart-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0201485672"&gt;Refactoring: Improving the Design of Existing Code&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=latetothepart-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0201485672" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt; and the bridge book by Joshua Kerievsky, &lt;a href="http://www.amazon.com/gp/product/0321213351?ie=UTF8&amp;amp;tag=latetothepart-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0321213351"&gt;Refactoring to Patterns&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=latetothepart-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0321213351" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;. 
I haven't seen a lot of information out there on how Ruby changes the game: ways to apply these patterns using Ruby idioms, new patterns that show up, patterns that fall away. So I've decided that as I go along I'll try and document the new twists as I see them.&lt;/p&gt;

&lt;p&gt;Today's article is the twist on the &lt;a href="http://www.exciton.cs.rice.edu/JavaResources/DesignPatterns/DecoratorPattern.htm"&gt;Decorator pattern&lt;/a&gt;. The Decorator pattern wraps the original object in a new one which will add functionality to some of the methods and then delegate to the original object. The prototypical example is decorating a window object.&lt;/p&gt;

&lt;h2&gt;A Decorator Example&lt;/h2&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_java "&gt;public interface Window {
  public void draw();
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In Java, we'd probably use a decorator to add scroll bars.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_java "&gt;public Class VerticalScrollWindow implements Window {
  private Window window;

  public VerticalScrollWindow(Window window) {
    this.window = window;
  }

  public void draw() {
    drawScrollBar();
    window.draw();
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The basic concept is that we'll usually want to be adding some behavior around a particular method call to extend behavior, while retaining the same interface.&lt;/p&gt;

&lt;h2&gt;Ruby&lt;/h2&gt;

&lt;p&gt;In ruby, we have a number of options to achieve this pattern. First, let's define our original Window in Ruby code:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Window&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;draw&lt;/span&gt;
    &lt;span class="comment"&gt;# do some drawing here...&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Translating the pattern literally&lt;/h3&gt;

&lt;p&gt;Given ruby's duck-typing nature, we could easily create a VerticalScrollWindow that wraps the original Window when we create the original window object, and pass that around. In fact we could patch only the single method and add a method_missing implementation that always delegated to the original Window.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;VerticalScrollWindow&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;window&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@window&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;window&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;draw&lt;/span&gt;
    &lt;span class="ident"&gt;draw_vertical_scrollbar&lt;/span&gt;
    &lt;span class="ident"&gt;window&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;draw&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;method_missing&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;method&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@window&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;send&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;method&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This approach could be evolved to a much higher level using method_missing tricks and dynamic modifications. One could create a generic Proxy class which took a target class and intercepted all method calls, executing pre- and post- method blocks for specific methods. I'll leave that as an exercise for the reader for now...&lt;/p&gt;

&lt;h3&gt;Using Alias&lt;/h3&gt;

&lt;p&gt;Another option we have is to "monkeypatch" the original class (or specific instances of it). The idea here is to rename the old implementation of the method, insert a new implementation and have that refer to the renamed original.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Window&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;draw&lt;/span&gt;
    &lt;span class="comment"&gt;# do some drawing here...&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="comment"&gt;# some code...&lt;/span&gt;

  &lt;span class="keyword"&gt;alias&lt;/span&gt; &lt;span class="symbol"&gt;:original_draw&lt;/span&gt; &lt;span class="symbol"&gt;:draw&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;draw&lt;/span&gt;
    &lt;span class="ident"&gt;draw_vertical_scrollbar&lt;/span&gt;
    &lt;span class="ident"&gt;original_draw&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Building pre and post hooks&lt;/h3&gt;

&lt;p&gt;Our last option is to build pre and post method hooks into the original class definition. Obviously, this approach requires the original class' author to explicitly build in callback hooks. This approach can be found in Capistrano (you can add tasks which get executed before or after well known tasks), or in ActiveRecord (lifecycle type callbacks - i.e. before_save, after_destroy).&lt;/p&gt;

&lt;p&gt;This option is a bit more advanced and differs in the approach taken. To learn how Capistrano does it, dive into &lt;a href="http://dev.rubyonrails.org/svn/rails/tools/capistrano/lib/capistrano/actor.rb"&gt;capistrano/actor.rb&lt;/a&gt;, line 118. Each task is defined as a method which explicitly calls before and after methods if they exist.&lt;/p&gt;

&lt;p&gt;For ActiveRecord, please refer to &lt;a href="http://dev.rubyonrails.org/svn/rails/trunk/activerecord/lib/active_record/callbacks.rb"&gt;activerecord/callback.rb&lt;/a&gt;. ActiveRecord goes a little further by allowing class level methods to add pre- and post- code blocks to be executed which will be inherited down the class hierarchy. They also allow instance level methods to be defined for each hook which would not be inherited.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: Francisco points us to a &lt;a href="http://www.lukeredpath.co.uk/2006/9/6/decorator-pattern-with-ruby-in-8-lines"&gt;great article on Decorator showing some other possible Ruby implementations&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Fri, 27 Oct 2006 17:08:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:f15c1b54-ff82-4082-b570-7488baf649c9</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2006/10/27/patterns-in-ruby-template-method</link>
      <category>Programming</category>
      <category>Ruby</category>
      <category>patterns</category>
      <category>ruby</category>
      <category>programming</category>
      <category>idioms</category>
    </item>
    <item>
      <title>Multi-stage deployments with Capistrano</title>
      <description>&lt;p&gt;I'm seeing a recurring theme in my feed reader today - multi-stage deployments with Capistrano.
It seems that those of us working in larger companies have all hit the same issue - we have some form of user acceptance, staging or other system which mirrors the production in configuration; and we want to use Capistrano to deploy to it as well as production. I know that my current company has a 5-stage process for pushing out releases (we're in financial services, and very paranoid. Whether they'd ever accept Capistrano is another issue).&lt;/p&gt;

&lt;p&gt;So here are my lazy pointers to the discussions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ola Bini, who's been doing some great posts on ruby metaprogramming, &lt;a href="http://ola-bini.blogspot.com/2006/09/two-things-in-rails.html"&gt;calls out his need for a "production_test" environment&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://www.redhillconsulting.com.au/blogs/simon/archives/000359.html"&gt;Simon Harris&lt;/a&gt; shares some snippets of deploying to his staged server running mongrel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Jamis Buck, the creator of Capistrano, weighed in a while ago on &lt;a href="http://weblog.jamisbuck.org/2006/1/3/using-switchtower-with-multiple-deployment-stages"&gt;multiple deployment stages&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: Michael Buffington shares his Mongrel deployment for &lt;a href="http://www.michaelbuffington.com/articles/2006/09/11/mongrel-and-capistrano"&gt;multiple stages&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Fri, 29 Sep 2006 12:56:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:4759d294-d891-4627-9c37-a0d2fd01721f</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2006/09/29/multi-stage-deployments-with-capistrano</link>
      <category>Programming</category>
      <category>Ruby</category>
      <category>Rails</category>
      <category>Rails</category>
      <category>capistrano</category>
      <category>deployment</category>
      <category>production</category>
      <category>webdev</category>
      <category>programming</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Prototype based Tag Autocompletion</title>
      <description>&lt;p&gt;I've been working on a website that uses tags internally. The &lt;a href="http://rubyforge.org/projects/taggable/"&gt;acts_as_taggable&lt;/a&gt; plugin has been great, but it only takes care of the ActiveRecord portion of tagging. One of the pieces of functionality I needed was to create an autocompleter for users to enter a list of tags on a record. Below is a pure copy-paste dump of my implementation. I'm not claiming it's good code or the right way top do things, but for those looking to use an autocompleter for a text field holding tags might find it useful. The implementation is close to that used by &lt;a href="http://del.icio.us"&gt;delicious&lt;/a&gt; in the tags field on posting new bookmarks.&lt;/p&gt;
&lt;p&gt;Here's an example usage:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_html "&gt;&lt;notextile&gt;&amp;lt;label for=&amp;quot;tags&amp;quot;&amp;gt;Tags&amp;lt;/label&amp;gt;
&amp;lt;%= text_field_tag 'tags', @tags.join(' '), :size =&amp;gt; 80, :autocomplete =&amp;gt; &amp;quot;off&amp;quot; %&amp;gt;
&amp;lt;div class=&amp;quot;auto_complete&amp;quot; id=&amp;quot;tags_auto_complete&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/notextile&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And the prototype-based class in javascript. You'll probably want to stick this in your application.js file if you're using &lt;a href="http://www.rubyonrails.org"&gt;Rails&lt;/a&gt;.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_javascript "&gt;&lt;notextile&gt;String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g,'') }

Autocompleter.Tag = Class.create();
Autocompleter.Tag.prototype = Object.extend(new Autocompleter.Base(), {
  lastEdit: '',
  currentTag: {},
  initialize: function(element, update, array, options) {
    this.baseInitialize(element, update, options);
    this.options.array = array;
  },
  
  getCurrentTag: function() {
	if(this.element.value == this.lastEdit) return true // no edit
	if(this.element == '') return false
	this.currentTag = {}
	var tagArray=this.element.value.toLowerCase().split(' '), oldArray=this.lastEdit.toLowerCase().split(' '), currentTags = [], matched=false, t,o
	for (t in tagArray) {
		for (o in oldArray) {
			if(typeof oldArray[o] == 'undefined') { oldArray.splice(o,1); break }
			if(tagArray[t] == oldArray[o]) { matched = true; oldArray.splice(o,1); break; }
		}
		if(!matched) currentTags[currentTags.length] = t
		matched=false
	}
	// more than one word changed... abort
	if(currentTags.length &amp;gt; 1) {
	  // hideSuggestions(); TODO Fix this!
	  return false;
	}
	this.currentTag = { text:tagArray[currentTags[0]], index:currentTags[0] }
	return true
  },

  getUpdatedChoices: function() {
    this.updateChoices(this.options.selector(this));
  },
  
  onKeyPress: function(event) {
    if(this.active)
      switch(event.keyCode) {
       case Event.KEY_TAB:
       case Event.KEY_RETURN:
         this.selectEntry();
         Event.stop(event);
       case Event.KEY_ESC:
         this.hide();
         this.active = false;
         Event.stop(event);
         return;
       case Event.KEY_LEFT:
       case Event.KEY_RIGHT:
         return;
       case Event.KEY_UP:
         this.markPrevious();
         this.render();
         if(navigator.appVersion.indexOf('AppleWebKit')&amp;gt;0) Event.stop(event);
         return;
       case Event.KEY_DOWN:
         this.markNext();
         this.render();
         if(navigator.appVersion.indexOf('AppleWebKit')&amp;gt;0) Event.stop(event);
         return;
      }
     else 
       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || 
         (navigator.appVersion.indexOf('AppleWebKit') &amp;gt; 0 &amp;amp;&amp;amp; event.keyCode == 0)) return;
    this.lastEdit = this.element.value;

    this.changed = true;
    this.hasFocus = true;

    if(this.observer) clearTimeout(this.observer);
      this.observer = 
        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
  },
  
  updateElement: function(selectedElement) {
    if (this.options.updateElement) {
      this.options.updateElement(selectedElement);
      return;
    }
    var value = '';
    if (this.options.select) {
      var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
      if(nodes.length&amp;gt;0) value = Element.collectTextNodes(nodes[0], this.options.select);
    } else
      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
    
    var lastTokenPos = this.findLastToken();
    if (lastTokenPos != -1) {
      var newValue = this.element.value.substr(0, lastTokenPos + 1);
      var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
      if (whitespace)
        newValue += whitespace[0];
      this.element.value = newValue + value;
    } else {
      tagArray = this.element.value.trim().split(' ')
      if (!this.getCurrentTag()) return;  // We had a problem getting the current tag, just return?
      tagArray[this.currentTag.index] = value;
      this.element.value = tagArray.join(' ');
    }
    this.element.focus();
    
    if (this.options.afterUpdateElement)
      this.options.afterUpdateElement(this.element, selectedElement);
  },

  setOptions: function(options) {
    this.options = Object.extend({
      choices: 10,
      partialSearch: true,
      partialChars: 2,
      ignoreCase: true,
      fullSearch: false,
      selector: function(instance) {
          var ret       = []; // Beginning matches
        var partial   = []; // Inside matches
        var entry     = instance.getToken();
        
        entry = entry.trim().split(' ').pop()
        
        var count     = 0;

        for (var i = 0; i &amp;lt; instance.options.array.length &amp;amp;&amp;amp;  
          ret.length &amp;lt; instance.options.choices ; i++) { 

          var elem = instance.options.array[i];
          var foundPos = instance.options.ignoreCase ? 
            elem.toLowerCase().indexOf(entry.toLowerCase()) : 
            elem.indexOf(entry);

          while (foundPos != -1) {
            if (foundPos == 0 &amp;amp;&amp;amp; elem.length != entry.length) { 
              ret.push(&amp;quot;&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;quot; + elem.substr(0, entry.length) + &amp;quot;&amp;lt;/strong&amp;gt;&amp;quot; + 
                elem.substr(entry.length) + &amp;quot;&amp;lt;/li&amp;gt;&amp;quot;);
              break;
            } else if (entry.length &amp;gt;= instance.options.partialChars &amp;amp;&amp;amp; 
              instance.options.partialSearch &amp;amp;&amp;amp; foundPos != -1) {
              if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
                partial.push(&amp;quot;&amp;lt;li&amp;gt;&amp;quot; + elem.substr(0, foundPos) + &amp;quot;&amp;lt;strong&amp;gt;&amp;quot; +
                  elem.substr(foundPos, entry.length) + &amp;quot;&amp;lt;/strong&amp;gt;&amp;quot; + elem.substr(
                  foundPos + entry.length) + &amp;quot;&amp;lt;/li&amp;gt;&amp;quot;);
                break;
              }
            }

            foundPos = instance.options.ignoreCase ? 
              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : 
              elem.indexOf(entry, foundPos + 1);

          }
        }
        if (partial.length)
          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
        return &amp;quot;&amp;lt;ul&amp;gt;&amp;quot; + ret.join('') + &amp;quot;&amp;lt;/ul&amp;gt;&amp;quot;;
      }    
    }, options || {});
  }
});
      &lt;/notextile&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 19 Sep 2006 15:12:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:2abe1246-129f-45b9-816b-7809b386bd93</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2006/09/19/prototype-based-tag-autocompletion</link>
      <category>Programming</category>
      <category>Personal</category>
      <category>Web design</category>
      <category>Ruby</category>
      <category>Rails</category>
      <category>tags</category>
      <category>delicious</category>
      <category>ruby</category>
      <category>Rails</category>
      <category>autocomplete</category>
      <category>javascript</category>
      <category>prototype</category>
    </item>
    <item>
      <title>JRuby guys hired by Sun, Netbeans Ruby IDE to come?</title>
      <description>&lt;p&gt;Given the news about Sun hiring the &lt;a href="http://www.jruby.org"&gt;JRuby&lt;/a&gt; developers, I thought I should chime my two cents in on the ongoing blog discussions.&lt;/p&gt;
&lt;p&gt;First, and foremost, congratulations to Thomas and Charles. This is great news for their project and for Ruby in general. It goes a long way to say that the company behind Java is now supporting a project to run Ruby on the JVM. Maybe now I can give presentations on Ruby at my employer and not be chased with pitchforks and tar.&lt;/p&gt;
&lt;p&gt;Next, I'd like to address a number of commenters out there. In particular, &lt;a href="http://www.redmonk.com/cote/archives/2006/09/el_rey_de_caf.html"&gt;Cote'&lt;/a&gt;: Hi there. There's already a project out there to make Eclipse into a Ruby IDE. I's called &lt;a href="http://rubyeclipse.sourceforge.org"&gt;RDT&lt;/a&gt; and I'm one of the lead developers. It's also the set of plugins that those &lt;a href="http://www.radrails.org"&gt;RadRails&lt;/a&gt; guys build on top of. Go check it out. Oh, and &lt;a href="http://www.tbray.org/ongoing/When/200x/2006/09/07/JRuby-guys"&gt;Tim Bray should too&lt;/a&gt;. He makes no mention of it, but maybe that has to do with politics...&lt;/p&gt;
&lt;p&gt;Speaking of politics, the underlying tone behind the news is that Sun is looking to create a Ruby IDE in Netbeans. I have to say I'm a bit torn over this. It's great to see a large company want to create a full Ruby IDE and competition leads to better products for the end users, the Ruby community. But can Sun please get over itself and acknowledge Eclipse exists? It seems a bit of a waste of time for them to roll their own IDE rather than support an existing editor like RDT (or &lt;a href="http://freeride.rubyforge.org/wiki/wiki.pl"&gt;FreeRIDE&lt;/a&gt;, or whatever). I guess it's a bit too naive of me to think that they'd do something that didn't push their corporate agenda to some extent. Well, I guess I could always ask IBM to throw me some cash...&lt;/p&gt;</description>
      <pubDate>Thu, 07 Sep 2006 22:40:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:f88671d7-6659-47c7-9391-e972b1cb1d88</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2006/09/07/jruby-guys-hired-by-sun-netbeans-ruby-ide-to-come</link>
      <category>Programming</category>
      <category>Personal</category>
      <category>Ruby</category>
      <category>Java</category>
      <category>RDT</category>
      <category>eclipse</category>
      <category>netbeans</category>
      <category>sun</category>
      <category>jruby</category>
      <category>hire</category>
      <category>developers</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Tim Bray on Ruby IDEs</title>
      <description>&lt;p&gt;Tim Bray has been posting an &lt;a href="http://www.tbray.org/ongoing/When/200x/2006/08/17/JRuby"&gt;ongoing series of articles&lt;/a&gt; documenting his experience in creating a Ruby based Atom protocol exerciser. His inisghts are a nice look from a newcomer to the language and he makes a good case for a number of areas where Ruby is behind the times and behind other prevailing languages.&lt;/p&gt;
&lt;p&gt;One such case is in &lt;a href="http://www.tbray.org/ongoing/When/200x/2006/09/05/What-Ruby-Needs"&gt;&lt;abbr title="Integrated Development Environment"&gt;IDE&lt;/abbr&gt;s&lt;/a&gt;. I've been aware of this since I began looking at Ruby, and obviously with my work on &lt;abbr title="Ruby Development Tools"&gt;RDT&lt;/abbr&gt; I've been trying to help out in this regard.&lt;/p&gt;
&lt;p&gt;I would encourage Tim and other newcomers to the language to give &lt;a  hfef="http://rubyeclipse.sourceforge.net/"&gt;RDT&lt;/a&gt; a serious try. While we're light-years away from the level of functionality found in Java support for Eclipse, we've been making some exciting progress on RDT lately.&lt;/p&gt;
&lt;p&gt;In fact, for those who don't mind the bleeding edge, you can download our nightly builds via Eclipse's update mechanism at &lt;a href="http://updatesite.rubypeople.org/nightly"&gt;http://updatesite.rubypeople.org/nightly&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The latest builds now include the work that was completed by &lt;a href="http://soc.jayunit.net/"&gt;Jason in his Google Summer of Code project&lt;/a&gt;. So the astute among you should now notice mark occurences support for variables, and even some code completion. We're working to polish those features up and get code completion working under more conditions. Right now, it'll work easily to complete variable names in scope or methods on a declared type. There are some severe limitations as to when the method completion will work for now: it's the first method in the chain on the object and the type is able to be inferred (i.e. declared in scope). To try out the type inferrencing (and show I'm not lying!), you can use a simple example of invoking code completion on code like "1.".&lt;/p&gt;
&lt;p&gt;I know, it's a long way from the &lt;abbr title="Java Development Tools"&gt;JDT&lt;/abbr&gt;, but we're getting there. And with a pending patch to &lt;a href="http://www.jruby.org"&gt;JRuby&lt;/a&gt;, we'll also be able to integrate the &lt;a href="http://morki.ch/rubyrefactoring"&gt;refactoring/code generation work by Mirko and company&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Wed, 06 Sep 2006 13:33:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:550b1197-29d8-4ba3-bdee-1b8782a97168</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2006/09/06/tim-bray-on-ruby-ides</link>
      <category>Programming</category>
      <category>Personal</category>
      <category>Ruby</category>
      <category>Java</category>
      <category>ruby</category>
      <category>RDT</category>
      <category>eclipse</category>
      <category>java</category>
      <category>refactoring</category>
      <category>programming</category>
      <category>ide</category>
      <category>editor</category>
    </item>
  </channel>
</rss>
