<?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>billeisenhauer.com &#8212; Professional Blog &#187; Ruby</title>
	<atom:link href="http://blog.billeisenhauer.com/category/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.billeisenhauer.com</link>
	<description></description>
	<lastBuildDate>Mon, 28 Jul 2008 00:03:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Circling Back</title>
		<link>http://blog.billeisenhauer.com/2007/10/10/circling-back/</link>
		<comments>http://blog.billeisenhauer.com/2007/10/10/circling-back/#comments</comments>
		<pubDate>Wed, 10 Oct 2007 14:19:33 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[Business Strategy]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.billeisenhauer.com/2007/10/10/circling-back/</guid>
		<description><![CDATA[People have asked me quite a lot lately what I&#8217;m going to do now that I&#8217;m free and clear of Click Here and my pat answer has been one of two or three things: Find a product-oriented company with a &#8230; <a href="http://blog.billeisenhauer.com/2007/10/10/circling-back/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>People have asked me quite a lot lately what I&#8217;m going to do now that I&#8217;m free and clear of <a target="_blank" title="Click Here" href="http://www.clickhere.com/">Click Here</a> and my pat answer has been one of two or three things:</p>
<ol>
<li>Find a product-oriented company with a high-performance team building something amazing, or</li>
<li>Bootstrap my own tiny consultancy, and / or</li>
<li>Build an amazing product.</li>
</ol>
<p>As luck would have it, I&#8217;ve already landed an interview at a company that offers the first option.  I&#8217;m excited about the interview, but realistic about the possibilities.  Because they appear to be a high-performance team, they are guarding the entrance quite closely.  My level of intrigue is all that much higher because the interview process is anything but easy and normal.  Suffice it to say that you can&#8217;t get hired by being a good guy and liberally dropping high-impact buzzwords.  You may laugh, but I&#8217;ve been hired through such good-guy interviews.</p>
<p>This is a position which features the use of Java as their primary implementation language, so my challenge is to get back into the Java mindset after several months of Ruby development.  My friend <a target="_blank" title="Mike Thomas" href="http://www.samoht.com/weblog/gemcast.rb">Mike</a> once supposed that I would never return to Java.  Its possible he&#8217;s wrong as I could be circling back.  Working with Ruby is fun, but my talents and experience position we well for a Java shop and there is more of a job market there too.</p>
<p>But even as I say that, I must admit that looking at Java for the first time in a few months has surprised me.  Java hasn&#8217;t changed, but it seems that my mind has started to think in Ruby.  I am actually alarmed that a language I&#8217;ve worked in for years could be subject to this kind of transition.  I found myself asking fundamental syntax questions.  So I wondered if this had happened to anyone else.  Or is this just a by-product of my being 43?</p>
<p>Well, I&#8217;m not worried about picking Java up again, but I am picking a problem to code to get my head back into it.  I still have a series of Java projects from an interview process I went through in June (yes, I was offered the job), so I&#8217;m going to work through one of those.  To make it more fun, I may try to integrate it into a JRuby on Rails project and do a local deploy.  This will enable me to prepare for the interview and explore the integration possibilities for JRuby and Java.</p>
<p>What happens if I don&#8217;t get the job?  Well, that&#8217;s a real possibility, so I&#8217;m planning my bootstrapping activities for my consultancy.  Having done recent work for a medium-sized consultancy, I know there is work out there and I know that I can provide high-quality work for a portion of the price that bigger companies are charging.  But as every entrepreneur knows, you cannot be successful without customers, so my biggest challenge will be to construct a marketing machine capable of producing a sustainable pipeline of work.  For technicians, this is not an intrinsic skill, so I&#8217;ve been thinking more about marketing than my technical skills &#8212; the latter is the easy part.</p>
<p>
In some ways this takes me back a great many years ago when I created a small software company, SportSoft Systems, which created and marketed Fantasy Football software and a few other things.  This was back 20 years ago and my product was just about the best out there.  Had I only known that the fantasy sports craze was to explode, I would have stuck with it.   I did actually make decent money, but the pressures of supporting the product and building in new features every year while being an ethical employee at my primary job caused me to discontinue my efforts.</p>
<p>
So for now, I&#8217;m circling back &#8212; either to the Java world or to a world where I build my own company.  Should be fun wherever things lead.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.billeisenhauer.com/2007/10/10/circling-back/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Preserve Semantics in Callbacks</title>
		<link>http://blog.billeisenhauer.com/2007/08/07/preserve-semantics-in-callbacks/</link>
		<comments>http://blog.billeisenhauer.com/2007/08/07/preserve-semantics-in-callbacks/#comments</comments>
		<pubDate>Wed, 08 Aug 2007 03:04:29 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.billeisenhauer.com/2007/08/07/preserve-semantics-in-callbacks/</guid>
		<description><![CDATA[Many people tend to place logic within a method named for the callback (e.g. after_destroy).  This works fine, but tends to be less maintainable, in my opinion. You basically have a method called after_destroy (or whatever), but you don&#8217;t readily &#8230; <a href="http://blog.billeisenhauer.com/2007/08/07/preserve-semantics-in-callbacks/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Many people tend to place logic within a method named for the callback (e.g. after_destroy).  This works fine, but tends to be less maintainable, in my opinion.</p>
<p>You basically have a method called after_destroy (or whatever), but you don&#8217;t readily know what its doing.  A better approach is to write an intention-revealing named method and reference that in the reference to your callback method.  You then can see through the method name what is happening in response to the event.  Further, the method can be used at other times.  This approach restores a bit of maintainability to your code.</p>
<p>I have included an example of this approach below.  You&#8217;ll have to visualize the before version &#8212; I don&#8217;t like posting less maintainable code because sometimes people skim it without reading and take it as good code.</p>
<table class="CodeRay">
<tr>
<td class="line_numbers">
<pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt>13<tt>
</tt>14<tt>
</tt>15<tt>
</tt>16<tt>
</tt>17<tt>
</tt>18<tt>
</tt>19<tt>
</tt><strong>20</strong><tt>
</tt></pre>
</td>
<td class="code">
<pre><span class="r">class</span> <span class="cl">Rating</span> &lt; <span class="co">ActiveRecord</span>::<span class="co">Base</span><tt>
</tt>  <tt>
</tt>  <span class="c"># ---- Associations ----</span><tt>
</tt>  <tt>
</tt>  <span class="c"># The rateable that was rated.</span><tt>
</tt>  belongs_to <span class="sy">:rateable</span><tt>
</tt>  <tt>
</tt>  <tt>
</tt>  <span class="c"># ---- Callbacks ----</span><tt>
</tt>  <tt>
</tt>  after_destroy <span class="sy">:update_ratings</span><tt>
</tt>  <tt>
</tt>  <tt>
</tt>  <span class="c"># ---- Calculations ----</span><tt>
</tt>  <tt>
</tt>  <span class="c"># Updates the parent's rating count and average rating.</span><tt>
</tt>  <span class="r">def</span> <span class="fu">update_ratings</span><tt>
</tt>    rateable.update_ratings<tt>
</tt>  <span class="r">end</span><tt>
</tt><span class="r">end</span></pre>
</td>
</tr>
</table>
]]></content:encoded>
			<wfw:commentRss>http://blog.billeisenhauer.com/2007/08/07/preserve-semantics-in-callbacks/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Constants in Rails Models</title>
		<link>http://blog.billeisenhauer.com/2007/08/06/using-constants-in-rails-models/</link>
		<comments>http://blog.billeisenhauer.com/2007/08/06/using-constants-in-rails-models/#comments</comments>
		<pubDate>Tue, 07 Aug 2007 02:52:16 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.billeisenhauer.com/2007/08/06/using-constants-in-rails-models/</guid>
		<description><![CDATA[One of my pet peeves in code is the absence of constants and thus the prevalence of &#8220;magic numbers&#8221; in their place. Constants add a touch of readability and semantic meaning and magnify the maintainability of the code. As a &#8230; <a href="http://blog.billeisenhauer.com/2007/08/06/using-constants-in-rails-models/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>One of my pet peeves in code is the absence of constants and thus the prevalence of &#8220;magic numbers&#8221; in their place.  Constants add a touch of readability and semantic meaning and magnify the maintainability of the code.</p>
<p>As a simple example, here&#8217;s a partial model featuring constants to aid in clear validation specifications:</p>
<table class="CodeRay">
<tr>
<td class="line_numbers">
<pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt>13<tt>
</tt>14<tt>
</tt>15<tt>
</tt>16<tt>
</tt>17<tt>
</tt>18<tt>
</tt>19<tt>
</tt><strong>20</strong><tt>
</tt>21<tt>
</tt></pre>
</td>
<td class="code">
<pre><span class="r">class</span> <span class="cl">Email</span> &lt; <span class="co">ActiveRecord</span>::<span class="co">Base</span><tt>
</tt>  <tt>
</tt>  <span class="co">MAX_FROM_LENGTH</span>   = <span class="i">30</span><tt>
</tt>  <span class="co">MAX_TO_LENGTH</span>     = <span class="i">100</span><tt>
</tt>  <span class="co">FROM_LENGTH_RANGE</span> = <span class="i">1</span>..<span class="co">MAX_FROM_LENGTH</span><tt>
</tt>  <span class="co">TO_LENGTH_RANGE</span>   = <span class="i">1</span>..<span class="co">MAX_TO_LENGTH</span><tt>
</tt>  <span class="co">TO_FORMAT</span>         = <span class="rx"><span class="dl">/</span><span class="k">^[_a-z0-9</span><span class="ch">+</span><span class="ch">.</span><span class="ch">-</span><span class="k">]+</span><span class="ch">@</span><span class="k">[_a-z0-9</span><span class="ch">-</span><span class="k">]+</span><span class="ch">\.</span><span class="k">[_a-z0-9</span><span class="ch">.</span><span class="ch">-</span><span class="k">]+$</span><span class="dl">/</span><span class="mod">i</span></span><tt>
</tt>  <span class="co">NOTE_LENGTH_RANGE</span> = <span class="i">1</span>..<span class="co">DB_TEXT_MAX_LENGTH</span><tt>
</tt>  <tt>
</tt>  <span class="c"># ---- Attributes ----</span><tt>
</tt>  <tt>
</tt>  <span class="c"># Attributes protected from mass-assignment (as through forms) </span><tt>
</tt>  attr_protected <span class="sy">:sent_at</span><tt>
</tt>  <tt>
</tt>  <tt>
</tt>  <span class="c"># ---- Validations ----</span><tt>
</tt>  <tt>
</tt>  validates_length_of   <span class="sy">:from</span>, <span class="sy">:within</span> =&gt; <span class="co">FROM_LENGTH_RANGE</span><tt>
</tt>  validates_length_of   <span class="sy">:to</span>,   <span class="sy">:within</span> =&gt; <span class="co">TO_LENGTH_RANGE</span><tt>
</tt>  validates_format_of   <span class="sy">:to</span>,   <span class="sy">:with</span>   =&gt; <span class="co">TO_FORMAT</span><tt>
</tt>  validates_length_of   <span class="sy">:note</span>, <span class="sy">:within</span> =&gt; <span class="co">NOTE_LENGTH_RANGE</span></pre>
</td>
</tr>
</table>
<p>As you can see the model defines constants to enforce length maximums and in turn the ranges.  You could argue that the range constants are less useful since you have to refer back to the constants section to see them, but that&#8217;s a matter of taste.  I like having them.</p>
<p>With constants like these properly placed in your model, you can take advantage of them in your migration.  Here&#8217;s a partial example:</p>
<table class="CodeRay">
<tr>
<td class="line_numbers">
<pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt></pre>
</td>
<td class="code">
<pre><span class="r">class</span> <span class="cl">CreateEmails</span> &lt; <span class="co">ActiveRecord</span>::<span class="co">Migration</span><tt>
</tt>  <span class="r">def</span> <span class="pc">self</span>.up<tt>
</tt>    create_table <span class="sy">:emails</span> <span class="r">do</span> |t|<tt>
</tt>      t.column <span class="sy">:emailable_id</span>, <span class="sy">:integer</span>, <span class="sy">:null</span> =&gt; <span class="pc">false</span><tt>
</tt>      t.column <span class="sy">:to</span>,         <span class="sy">:string</span>,  <span class="sy">:null</span> =&gt; <span class="pc">false</span>, <span class="sy">:limit</span> =&gt; <span class="co">Email</span>::<span class="co">MAX_TO_LENGTH</span><tt>
</tt>      t.column <span class="sy">:from</span>,       <span class="sy">:string</span>,  <span class="sy">:null</span> =&gt; <span class="pc">false</span>, <span class="sy">:limit</span> =&gt; <span class="co">Email</span>::<span class="co">MAX_FROM_LENGTH</span><tt>
</tt>      t.column <span class="sy">:note</span>,       <span class="sy">:text</span>,    <span class="sy">:null</span> =&gt; <span class="pc">false</span><tt>
</tt>      t.column <span class="sy">:sent_at</span>,    <span class="sy">:datetime</span><tt>
</tt>    <span class="r">end</span><tt>
</tt>  <span class="r">end</span></pre>
</td>
</tr>
</table>
<p>The advantage here is that your model and your migration are now in synch for field maximums.  If that&#8217;s not enough, then consider what you can now do in your test code:</p>
<table class="CodeRay">
<tr>
<td class="line_numbers">
<pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt></pre>
</td>
<td class="code">
<pre><span class="r">def</span> <span class="fu">test_invalid_with_long_to</span><tt>
</tt>    assert_value_for_attribute_invalid(<span class="co">Email</span>.new, <span class="sy">:to</span>, filled_str(<span class="s"><span class="dl">"</span><span class="k">X</span><span class="dl">"</span></span>, <span class="co">Email</span>::<span class="co">MAX_TO_LENGTH</span> + <span class="i">1</span>))<tt>
</tt>  <span class="r">end</span></pre>
</td>
</tr>
</table>
<p>So now, if you change your mind and decide you need to lengthen your fields, you need only change your model constants.  Your migration could be rerun or you could add an additional migration which applies the new field length.  And lastly, your test code doesn&#8217;t have to change.</p>
<p>I think this is simple, yet very much worth doing.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.billeisenhauer.com/2007/08/06/using-constants-in-rails-models/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>GeoKit Updates</title>
		<link>http://blog.billeisenhauer.com/2007/06/04/geokit-updates/</link>
		<comments>http://blog.billeisenhauer.com/2007/06/04/geokit-updates/#comments</comments>
		<pubDate>Tue, 05 Jun 2007 00:13:03 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[GeoKit]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.billeisenhauer.com/2007/06/04/geokit-updates/</guid>
		<description><![CDATA[I have added a few features and made a few bug fixes to GeoKit. These are as follows: [FEATURE] Added timeout support for geocoder web service calls [FEATURE] Added proxy support for geocoder web service calls [FEATURE] Added support for &#8230; <a href="http://blog.billeisenhauer.com/2007/06/04/geokit-updates/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I have added a few features and made a few bug fixes to GeoKit.  These are as follows:</p>
<ul>
<li>[FEATURE] Added timeout support for geocoder web service calls</li>
<li>[FEATURE] Added proxy support for geocoder web service calls</li>
<li>[FEATURE] Added support for SQL count queries &#8212; they work like the finders</li>
<li>[BUG FIX] Fixed range finders to support exclusive ranges</li>
<li>[BUG FIX] Fixed configuration to use class accessors instead of constants (that were being reinitialized)</li>
<li>[BUG FIX] Eliminated bogus IP address returned from IP geocoder when the request IP is 127.0.0.1</li>
<li>[BUG FIX] Fixed GeoLoc&#8217;s hash method and added an alias to_hash</li>
<li>[REFACTOR] Require statements to be cleaner all the way around</li>
</ul>
<p>Thanks to the following who reported bugs that got fixed or who submitted patches that were used in part or in their entirety:</p>
<ul>
<li>Norbert Crombach</li>
<li>Justin French</li>
<li>Hoan Ton-That</li>
<li>Jason Seifer</li>
</ul>
<p>Thanks to everyone for your feedback, patches, and compliments.  If I didn&#8217;t name you explicitly, it means that your thanks by name will come later.</p>
<p>Since I am in a GeoKit development mode right now, let me or Andre know if there are other features, bug fixes, or patches I should be aware of.  I know that we had been planning to modify our configuration approach to be compatible with YM4R, but that&#8217;s been delayed indefinitely.  They use a YAML file and we use the environment configs &#8212; and there really wasn&#8217;t a compelling reason to mess with it.  Also, no UK geocoding yet &#8212; didn&#8217;t receive too much demand.</p>
<p>Please review the README for updates and take a look at the new environment config template under the plugin&#8217;s assets directory to see how you should config GeoKit.  And by all means, let me know if there are issues that I&#8217;ve inadvertently created for you.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.billeisenhauer.com/2007/06/04/geokit-updates/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Your questions about hire.billeisenhauer.com</title>
		<link>http://blog.billeisenhauer.com/2007/05/13/your-questions-about-hirebilleisenhauercom/</link>
		<comments>http://blog.billeisenhauer.com/2007/05/13/your-questions-about-hirebilleisenhauercom/#comments</comments>
		<pubDate>Mon, 14 May 2007 05:55:51 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.billeisenhauer.com/2007/05/13/your-questions-about-hirebilleisenhauercom/</guid>
		<description><![CDATA[A few people have asked about my &#8220;hire me&#8221; site, so I thought I&#8217;d answer them here for everyone. The first question was how did what I put together differ or distinguish me from what anyone could do with a &#8230; <a href="http://blog.billeisenhauer.com/2007/05/13/your-questions-about-hirebilleisenhauercom/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A few people have asked about <a target="_blank" title="Hire Me" href="http://hire.billeisenhauer.com">my &#8220;hire me&#8221; site</a>, so I thought I&#8217;d answer them here for everyone.<br />
The first question was how did what I put together differ or distinguish me from what anyone could do with a Linkedin profile?  Good question.  A Linkedin profile probably will get more visits based upon Linkedin&#8217;s popularity.  However, I would not be able to provide PDF and Word versions of my resume, work samples, and tinker with my SEO.  At present, if you enter &#8220;Bill Eisenhauer&#8221; into Google, you&#8217;ll see a Linkedin profile under that name as the 5th choice &#8212; unfortunately, that&#8217;s not my profile.</p>
<p>The next question is: would you consider productizing it to enable others to have online resumes?  The answer is: maybe.  If I was convinced that I could find enough paying customers, I would.  However, I&#8217;m not sure I could do that.  I will say that it is nice to be able to point recruiters and potential employers to the site for resumes, samples, and testimonials.</p>
<p>Another question is: what&#8217;s up with the odd classes in some of the markup?  Well, that&#8217;s <a title="Microformats" target="_blank" href="http://microformats.org/">microformats</a>.  I am tinkering with hResume, hReview, and hCard.  You can download a Firefox extension which alerts you when microformats are present on a page and on my site you can see microformats on about half the pages.  For now, I&#8217;m probably about the only one who thinks this is cool, but such is the life of an early-adopter.</p>
<p>Lastly, I&#8217;ve had a couple of recruiters ask about the effects found on the site (e.g. samples, about &#8211; tag cloud).  That&#8217;s some Javascript and AJAX just for the heck of it.  Its kinda cool to refer a recruiter to my site when they are asking if I&#8217;ve ever done any AJAX.  So, not hugely useful, but mildly demonstrative of my skills.</p>
<p>I have surmised that my ability to code in Ruby is not of much value to the Java community.  There&#8217;s just not much crossover between the two.  So while I like coding in Ruby and Rails, it would appear that I won&#8217;t be paid to do so anytime soon.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.billeisenhauer.com/2007/05/13/your-questions-about-hirebilleisenhauercom/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Job Seeking 2.0</title>
		<link>http://blog.billeisenhauer.com/2007/05/03/job-seeking-20/</link>
		<comments>http://blog.billeisenhauer.com/2007/05/03/job-seeking-20/#comments</comments>
		<pubDate>Thu, 03 May 2007 16:09:43 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[Business Strategy]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.billeisenhauer.com/2007/05/03/job-seeking-20/</guid>
		<description><![CDATA[As many of you know, I&#8217;m looking for employment now while my Nokia days come to an end. I thought I would post some thoughts on how you find a job in the current job market. Nevermind that I don&#8217;t &#8230; <a href="http://blog.billeisenhauer.com/2007/05/03/job-seeking-20/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>As many of you know, I&#8217;m looking for employment now while my Nokia days come to an end.  I thought I would post some thoughts on how you find a job in the current job market.  Nevermind that I don&#8217;t have a job, I just started looking in earnest a couple of days ago.  So here goes:</p>
<p>The first thing to get straight is that YOU are the product.  Prospective employers are your customers.  And as a result, you need a marketing plan.  Your marketing plan must begin with the usual self-assessments which eventually lead to your main marketing vehicle &#8212; the resume.  In some ways, you could almost consider your resume as the product.</p>
<p>Next comes the distribution problem.  How do you get your resume in front of those who you wish to become your buyers?  In today&#8217;s world, you get your resume and profile up on all the job boards that are relevant to your profession.  However, reentering the same data over and over is such a pain.  To ease your pain, use <a target="_blank" title="SimplyHired" href="http://www.simplyhired.com">SimplyHired</a> which is a site that will enable you to enter your resume data once and then blast it out to sites of your choosing &#8212; a real time saver.  Just be sure that you get the information right because after SimplyHired does its thing, you will have to manage individual accounts at all the sites.</p>
<p>As an added touch, I created my own <a target="_blank" title="Hire Bill Eisenhauer" href="http://hire.billeisenhauer.com">website</a> to promote my efforts.  The website serves as a visual reinforcement of my technical skills.  Its well-designed, uses semantic standards-based markup, is CSS-based, and uses progressive enhancement in a couple areas to improve the user experience (printing, tag cloud AJAX).  Its not an over-the-top tour de force in technology, but is just enough to impress the target audience &#8212; prospective employers and recruiters.  Because some of you will go there, I readily disclaim that its been soft-launched.  Expect to find minor cross-browser issue and some content yet to be provided.  You techies are a tougher audience than my target audience!</p>
<p>So when you flip the switch on this machine, you will get assaulted with emails and opportunities.  These are your customers banging on the door.  To organize yourself, get a <a target="_blank" title="Highrise" href="http://www.highrisehq.com">Highrise</a> account from 37Signals.  Highrise is a mini-CRM application and let&#8217;s face it, you will be talking to people, exchanging email with people, and more or less manage the sales process.  Highrise is perfect for this and is free for limited use.</p>
<p>Once you actually start interacting with people you&#8217;ll have to get pretty savvy at determining who to spend your time with.  I have received very generic requests to call recruiters and I don&#8217;t get involved further unless I am able to get a compelling story up front.  Be prepared, you will also hear from people who will disregard your skills, experience, and relocation preferences entirely.  I am deleting most emails on that basis alone.</p>
<p>So far, things are going well.  I think that treating this situation like a product campaign has been beneficial.  I already have some solid leads and opportunities that I&#8217;m following up on.  And this is Day 3.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.billeisenhauer.com/2007/05/03/job-seeking-20/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Why Why?</title>
		<link>http://blog.billeisenhauer.com/2007/04/26/why-why/</link>
		<comments>http://blog.billeisenhauer.com/2007/04/26/why-why/#comments</comments>
		<pubDate>Fri, 27 Apr 2007 01:53:28 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.billeisenhauer.com/2007/04/26/why-why/</guid>
		<description><![CDATA[I have subscribed to Why the Lucky Stiff&#8217;s Redhanded blog for quite some time, but lately I&#8217;ve been unable to fight through the distractions.  I present to you his latest performance.  Is anyone else wishing he&#8217;d kill the noise, so &#8230; <a href="http://blog.billeisenhauer.com/2007/04/26/why-why/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I have subscribed to Why the Lucky Stiff&#8217;s <a target="_blank" title="Redhanded" href="http://redhanded.hobix.com/">Redhanded</a> blog for quite some time, but lately I&#8217;ve been unable to fight through the distractions.  I present to you his latest <a target="_blank" title="Disco Strobe Lights" href="http://redhanded.hobix.com/bits/theHeartOfTryRuby.html">performance</a>.  Is anyone else wishing he&#8217;d kill the noise, so that we can all learn from him?</p>
<p>I&#8217;m pretty sure that I sound like a Father telling his kid to turn the music down&#8230;and so at least I am self-aware.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.billeisenhauer.com/2007/04/26/why-why/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>AppConfig Plugin for Rails</title>
		<link>http://blog.billeisenhauer.com/2007/04/26/appconfig-plugin-for-rails/</link>
		<comments>http://blog.billeisenhauer.com/2007/04/26/appconfig-plugin-for-rails/#comments</comments>
		<pubDate>Thu, 26 Apr 2007 23:01:50 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.billeisenhauer.com/2007/04/26/appconfig-plugin-for-rails/</guid>
		<description><![CDATA[Its probably because I come from the Java world that I felt compelled to create an app configuration mechanism which enabled easy externalization of app properties.  This is not an Earth-shattering, whiz-bang plugin, so I&#8217;m not going to oversell it.  &#8230; <a href="http://blog.billeisenhauer.com/2007/04/26/appconfig-plugin-for-rails/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Its probably because I come from the Java world that I felt compelled to create an app configuration mechanism which enabled easy externalization of app properties.  This is not an Earth-shattering, whiz-bang plugin, so I&#8217;m not going to oversell it.  Quite simply, this plugin just enables you to put properties into an app.yml file and manage it nicely with Capistrano.  So maybe this&#8217;ll save you 10 minutes of coding.  Here goes:</p>
<p><strong>FEATURE SUMMARY</strong></p>
<p>This plugin provides for easy externalized configurization in a YML file:</p>
<ul>
<li>Common and environment-specific configuration contained in a single YML file.</li>
<li>Capistrano task to preserve configuration file from release to release.</li>
</ul>
<p><strong>USAGE</strong><br />
Place configuration elements common to all environments in the common area as demonstrated below:</p>
<table class="CodeRay">
<tr>
<td class="line_numbers">
<pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt></pre>
</td>
<td class="code">
<pre><span class="c"># Configuration for ALL environments.</span><tt>
</tt>common: &amp;common<tt>
</tt>  app_name: your_app_name_here</pre>
</td>
</tr>
</table>
<p>Place environment-specific elements under appropriate environment as shown below:</p>
<table class="CodeRay">
<tr>
<td class="line_numbers">
<pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt></pre>
</td>
<td class="code">
<pre><span class="c"># Configuration for PRODUCTION environment.</span><tt>
</tt>production:<tt>
</tt>  &lt;&lt;: *common<tt>
</tt>  google_api: some_long_api_key_here<tt>
</tt></pre>
</td>
</tr>
</table>
<p>To obtain the values from anywhere in your code, simply access the attributes of the environment like so:</p>
<table class="CodeRay">
<tr>
<td class="line_numbers">
<pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt></pre>
</td>
<td class="code">
<pre>puts <span class="co">AppConfig</span>.app_name<tt>
</tt>puts <span class="co">AppConfig</span>.google_api<tt>
</tt></pre>
</td>
</tr>
</table>
<p><strong>DEPLOYMENT</strong></p>
<p>To preserve the configuration values across releases, call the symlink_app_config task from within the after_update_code task.</p>
<table class="CodeRay">
<tr>
<td class="line_numbers">
<pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt></pre>
</td>
<td class="code">
<pre>task <span class="sy">:after_update_code</span>, <span class="sy">:roles</span> =&gt; <span class="sy">:app</span> <span class="r">do</span><tt>
</tt>  symlink_app_config<tt>
</tt><span class="r">end</span></pre>
</td>
</tr>
</table>
<p>To update the app.yml file for the first time or for subsequent times, the task update_app_config can be used as below:</p>
<p>cap update_app_config</p>
<p>This takes the app.yml file from the config directory of the application and uploads it to the release path on the server.</p>
<p>You can get it here:</p>
<p>script/plugin install http://dev.billeisenhauer.com/svn/projects/plugins/appconfig</p>
<p>Hope someone finds this useful.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.billeisenhauer.com/2007/04/26/appconfig-plugin-for-rails/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Deploying CruiseControl.rb with Custom Tasks</title>
		<link>http://blog.billeisenhauer.com/2007/03/19/deploying-cruisecontrolrb-with-custom-tasks/</link>
		<comments>http://blog.billeisenhauer.com/2007/03/19/deploying-cruisecontrolrb-with-custom-tasks/#comments</comments>
		<pubDate>Tue, 20 Mar 2007 04:47:07 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.billeisenhauer.com/2007/03/19/deploying-cruisecontrolrb-with-custom-tasks/</guid>
		<description><![CDATA[More and more work is being done by geographically disparate teams these days, so a continuous integration tool like CruiseControl.rb is quite useful. Andre and I could have used this when we were heads down with GeoKit. But better late &#8230; <a href="http://blog.billeisenhauer.com/2007/03/19/deploying-cruisecontrolrb-with-custom-tasks/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>More and more work is being done by geographically disparate teams these days, so a continuous integration tool like <a target="_blank" href="http://cruisecontrolrb.thoughtworks.com/">CruiseControl.rb</a> is quite useful.  <a target="_blank" href="http://blog.billeisenhauer.com/www.earthcode.com">Andre</a> and I could have used this when we were heads down with <a target="_blank" href="http://geokit.rubyforge.org/">GeoKit</a>.  But better late than never, right?</p>
<p>I decided I would make an attempt to deploy CruiseControl.rb to one of the hosts that I have &#8212; and do so with Capistrano.  For the most part, it was pretty painless, but I did run into a gotcha or two.</p>
<p>First, the host I deployed to uses the Apache / Lighttpd (fastcgi) style of deployment.  Unfortunately, Lighttpd just would never start up for me!  After way too long, I finally figured out that I had DOS line breaks in my file that I could not see.  So I zapped them with dos2unix and all was well.  Unfortunately, this ate up a lot of my time as I&#8217;m not very skilled at debugging fastcgi issues.</p>
<p>CruiseControl.rb is a Rails app, but not your typical Rails app.  It uses no Rails app, but rather stores your project information in a projects directory underneath the app root.  Further, its more than just a Rails app, it utilizes additional processes as project builders.</p>
<p>To deploy with Capistrano, you have to preserve the projects directory so that it will persist across your releases.  That&#8217;s pretty easy to do with symlinks, so that&#8217;s a piece of cake.  You can use the after_update_code callback to do this.</p>
<p>There are two other use cases that I could see that I would need.  Adding a project and starting a builder for that project.  To enable those, I added Capistrano tasks for each.  Both tasks rely on environment variables and both tasks could probably benefit from a bit more error-checking, but they are good enough for me.</p>
<p>So to start a project, I use:</p>
<p>NAME=GeoKit URL=svn://rubyforge.org/var/svn/geokit cap add_project</p>
<p>to start its builder, I use:</p>
<p>NAME=GeoKit cap start_builder</p>
<p>I added my custom tasks under config/recipes/cruisecontrol.rb and required this in deploy.rb.  The custom tasks code is below:</p>
<table class="CodeRay">
<tr>
<td class="line_numbers">
<pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt>13<tt>
</tt>14<tt>
</tt>15<tt>
</tt>16<tt>
</tt>17<tt>
</tt>18<tt>
</tt>19<tt>
</tt><strong>20</strong><tt>
</tt>21<tt>
</tt>22<tt>
</tt>23<tt>
</tt>24<tt>
</tt></pre>
</td>
<td class="code">
<pre><span class="co">Capistrano</span>.configuration(<span class="sy">:must_exist</span>).load <span class="r">do</span><tt>
</tt><tt>
</tt>  desc <span class="s"><span class="dl">"</span><span class="k">Update symlink for projects directory.</span><span class="dl">"</span></span><tt>
</tt>  task <span class="sy">:after_update_code</span> <span class="r">do</span><tt>
</tt>    run <span class="s"><span class="dl">&lt;&lt;-CMD</span></span><span class="s"><span class="k"><tt>
</tt>      rm -rf </span><span class="il"><span class="dl">#{</span>release_path<span class="dl">}</span></span><span class="k">/projects &amp;&amp;<tt>
</tt>      ln -nfs </span><span class="il"><span class="dl">#{</span>shared_path<span class="dl">}</span></span><span class="k">/projects </span><span class="il"><span class="dl">#{</span>release_path<span class="dl">}</span></span><span class="k">/projects</span><span class="dl"><tt>
</tt>    CMD</span></span><tt>
</tt>  <span class="r">end</span><tt>
</tt><tt>
</tt>  desc <span class="s"><span class="dl">"</span><span class="k">Add a project to cruise control.</span><span class="dl">"</span></span><tt>
</tt>  task <span class="sy">:add_project</span> <span class="r">do</span><tt>
</tt>    <span class="r">unless</span> <span class="co">ENV</span>[<span class="s"><span class="dl">'</span><span class="k">NAME</span><span class="dl">'</span></span>] &amp;&amp; <span class="co">ENV</span>[<span class="s"><span class="dl">'</span><span class="k">URL</span><span class="dl">'</span></span>] <tt>
</tt>      raise <span class="co">ArgumentError</span>, <span class="s"><span class="dl">"</span><span class="k">***** You must specify the NAME and URL parameters to add a project. *****</span><span class="dl">"</span></span> <tt>
</tt>    <span class="r">end</span>   <tt>
</tt>    run <span class="s"><span class="dl">"</span><span class="il"><span class="dl">#{</span>current_release<span class="dl">}</span></span><span class="k">/cruise add </span><span class="il"><span class="dl">#{</span><span class="co">ENV</span>[<span class="s"><span class="dl">'</span><span class="k">NAME</span><span class="dl">'</span></span>]<span class="dl">}</span></span><span class="k"> --url </span><span class="il"><span class="dl">#{</span><span class="co">ENV</span>[<span class="s"><span class="dl">'</span><span class="k">URL</span><span class="dl">'</span></span>]<span class="dl">}</span></span><span class="dl">"</span></span><tt>
</tt>  <span class="r">end</span><tt>
</tt>  <tt>
</tt>  desc <span class="s"><span class="dl">"</span><span class="k">Start a builder for a project.</span><span class="dl">"</span></span><tt>
</tt>  task <span class="sy">:start_builder</span> <span class="r">do</span><tt>
</tt>    raise <span class="co">ArgumentError</span>, <span class="s"><span class="dl">"</span><span class="k">***** You must specify the NAME of the project to build. *****</span><span class="dl">"</span></span> <span class="r">unless</span> <span class="co">ENV</span>[<span class="s"><span class="dl">'</span><span class="k">NAME</span><span class="dl">'</span></span>] <tt>
</tt>    run <span class="s"><span class="dl">"</span><span class="il"><span class="dl">#{</span>current_release<span class="dl">}</span></span><span class="k">/cruise build </span><span class="il"><span class="dl">#{</span><span class="co">ENV</span>[<span class="s"><span class="dl">'</span><span class="k">NAME</span><span class="dl">'</span></span>]<span class="dl">}</span></span><span class="k"> &amp;</span><span class="dl">"</span></span>   <tt>
</tt>  <span class="r">end</span><tt>
</tt><span class="r">end</span></pre>
</td>
</tr>
</table>
<p>And with that, any of my projects can now be monitored with CruiseControl.rb.</p>
<p>A few caveats.</p>
<ul>
<li>I had to physically edit the cruise_config.rb file (on the server) for the project to include my email address and polling interval.  No big deal, its a one-time thing.</li>
<li>If your code is proprietary, you may want to protect the site with<br />
basic authentication to keep unwanted eyes from seeing your project assets.</li>
<li>Since your project data is on your server&#8217;s file system, you may want to consider a backup strategy if you value your build history.</li>
</ul>
<p>Suggestions for ThoughtWorks:</p>
<ul>
<li>Consider including Capistrano tasks to make it easier &#8212; mine are admittedly rough, I&#8217;m sure.</li>
<li>Consider adding some element of authorization by project.  For example, I have public plugins, but I also have proprietary code that I do not wish to share.  Obviously, its easy enough to deploy a second site, but that&#8217;s mildly inconvenient.</li>
</ul>
<p>I hope this is helpful to continuous integration fans out there trying to get set up!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.billeisenhauer.com/2007/03/19/deploying-cruisecontrolrb-with-custom-tasks/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>GeoKit: A Tiny Update</title>
		<link>http://blog.billeisenhauer.com/2007/03/12/geokit-a-tiny-update/</link>
		<comments>http://blog.billeisenhauer.com/2007/03/12/geokit-a-tiny-update/#comments</comments>
		<pubDate>Tue, 13 Mar 2007 05:10:28 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[GeoKit]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.billeisenhauer.com/2007/03/12/geokit-a-tiny-update/</guid>
		<description><![CDATA[Its been a while since I tinkered with GeoKit, but when I read this post, I thought I&#8217;d take a look at a couple of things that were mentioned. James wrote that it would be nice to be able to &#8230; <a href="http://blog.billeisenhauer.com/2007/03/12/geokit-a-tiny-update/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Its been a while since I tinkered with GeoKit, but when I read <a target="_blank" href="http://jystewart.net/process/2007/03/rails-geo-plugins-geokit">this post</a>, I thought I&#8217;d take a look at a couple of things that were mentioned.</p>
<p>James wrote that it would be nice to be able to reset the default_units value to enable localization.  Well, actually you can.  :default_units is modifiable through a class accessor.  Also, you can pass an optional parameter in your finders called :units which enables you to override whatever default value you&#8217;ve set.</p>
<p>While we&#8217;re talking about defaults, I applied a patch submitted by Hoan Ton-That which enables you to specify your preferences for units and for the formula from within the environment files.  So these preferences would appear right along side your API keys for GeoKit.  Its a small feature, but you may appreciate it.  Thanks Hoan!</p>
<p>Otherwise, James mentioned that :include support is lacking with GeoKit.  That&#8217;s not entirely true.  I added a passing test case which successfully pulls columns from a belongs_to relationship.  I suspect that the has_many relationships are the problem.  But if your case is covered by the belongs_to relationship, then you are covered.</p>
<p>There is a less-used method called distance_sql which enables you to just get the distance calculation in SQL form.  You would use this if you ever found that GeoKit could not support your exact query requirements.  Its less elegant for sure, but saves you the trouble of having to code the distance calculation.</p>
<p>UK geocoding is still in the roadmap, but both Andre and I have a few other projects and side endeavors going on.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.billeisenhauer.com/2007/03/12/geokit-a-tiny-update/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
