<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>LabRatz - Home</title>
  <id>tag:blog.labratz.net,2007:mephisto/</id>
  <generator version="0.7.3" uri="http://mephistoblog.com">Mephisto Noh-Varr</generator>
  <link href="http://blog.labratz.net/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://blog.labratz.net/" rel="alternate" type="text/html"/>
  <updated>2007-01-06T01:38:23Z</updated>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2007-01-05:307</id>
    <published>2007-01-05T20:35:00Z</published>
    <updated>2007-01-06T01:38:23Z</updated>
    <category term="apple"/>
    <link href="http://blog.labratz.net/articles/2007/1/5/5-os-x-apps-that-you-didn-t-know-you-needed" rel="alternate" type="text/html"/>
    <title>5 OS X Apps that You Didn't Know You Needed</title>
<content type="html">
            I think a lot of people are unaware of just how many pieces of great software for the mac are out there.  It seems like every three days I'll read about how people are switching to the mac in record numbers.  A wider user base means that much more opportunities for software developers to make money.  However, what a lot of people don't realize is that there are also many &lt;b&gt;developers&lt;/b&gt; switching to the OS X platform as well.

With that in mind, I've taken care to compile a list of &quot;hidden gems&quot; that can make a real quality difference to your mac experience on a daily basis.

There are no earth-shattering apps or obvious choices like Quicksilver but apps that will make a little difference every day, whether it's a small performance gain or fulfilling a useful function that many people aren't aware of.  Most of these apps are shareware but offer decent trial periods.


&lt;p&gt;&lt;b&gt;Main Menu: Free&lt;/b&gt;&lt;/p&gt;
The mac is relatively maintenance-free compared to Windows. However, after a while it does help to do a little maintenance and get rid of that accumulated junk that slowly drags you down.  Before I found Main Menu, I used to use &lt;a href='http://www.titanium.free.fr/pgs2/english/onyx.html'&gt;Onyx&lt;/a&gt; which has similar functionality.  The big difference is Main Menu stays accessible to you from the menu bar.  Quick and simple.

&lt;p&gt;&lt;blockquote&gt;&quot;Rebuilding your Spotlight library for faster searching, repairing permissions, cleaning caches to improve application performance, and even more advanced settings — such as enabling and disabling the Dashboard — are no more than two clicks away.&quot;&lt;/blockquote&gt;&lt;/p&gt;

&lt;img src='http://blog.labratz.net/assets/2007/1/5/MainMenu.jpg' /&gt;

&lt;p&gt;&lt;a href='http://www.santasw.com/'&gt;Main Menu&lt;/a&gt;&lt;/p&gt;


&lt;b&gt;&lt;p&gt;WriteRoom: $24.95 (free version available)&lt;/p&gt;&lt;/b&gt;
Ever sit down to write something only to find yourself distracted by emails, chats, new RSS feeds coming in, or some app in your dock begging for your attention?  The sad fact is we're not as good at multi-tasking as our computers are.  Sure, we can eat a bag of chips, drink soda, and watch TV at the same time but some things require concentration, especially if you want a decent amount of quality and get the task done on time.  Writing is one of those activities.

WriteRoom will turn your mac into a classic typewriter and I mean it in a good way.  This app will give you one big blank screen with no dock, no menu bar, no scroll bars.  Just text.

&lt;a href='http://www.hogbaysoftware.com/files/website_images/writeroom/main-screen.png'&gt;Check this screen&lt;/a&gt; out for an idea of what you get.  If you care about your prose, this will be a good investment.  A &lt;a href='http://www.hogbaysoftware.com/files/releases/WriteRoom-1.0.dmg'&gt;free version&lt;/a&gt; (limited features and polish) is also available.

&lt;img src='http://blog.labratz.net/assets/2007/1/5/WriteRoom.gif' /&gt;

&lt;p&gt;&lt;a href='http://www.hogbaysoftware.com/product/writeroom'&gt;WriteRoom | Hog Bay Software&lt;/a&gt;&lt;/p&gt;


&lt;b&gt;&lt;p&gt;1Passwd: $29.95&lt;/p&gt;&lt;/b&gt;
Nowadays all browsers more or less come with password management built-in.  Firefox does a nice enough job but did you know that if someone can access your Firefox profile folder, they can &lt;a href='http://www.technipages.com/article117.html'&gt;easily transfer you passwords and decrypt them&lt;/a&gt;?

There's also no sane way to transfer these passwords since mac uses keychain for all password management and keychain integration for Firefox is still down the road.

1Passwd allows you to securely store and manage a single collection of password from any major browser.  It can also import passwords from Firefox as well.  It comes with many security options (like generating strong passwords) and can be synced across multiple macs.

As an added bonus, their toolbar gives you a form filler so you can stop typing things like name, email, homepage, etc. when online shopping or commenting on a blog that you're visiting for the first time.

It may seem a bit expensive but if you spend time participating in a variety of community-related sites or blog, this app will make a big difference.

&lt;img src='http://blog.labratz.net/assets/2006/12/14/password_manager_logo.png' /&gt;

&lt;p&gt;&lt;a href='http://1passwd.com/?r=f9067980&amp;b=6cecfc20'&gt;Password Manager + AutoFill for Mac OS X&lt;/a&gt;&lt;/p&gt;


&lt;b&gt;&lt;p&gt;Xslimmer: $9.95&lt;/p&gt;&lt;/b&gt;
Most of the mac users I know personally have finally taken the plunge into the Intel world.  The performance gains are really fantastic.  Luckily, PPC users are not left behind as many apps migrate to the Intel platform with Universal Binaries or single installations that work on both platforms.

However, did you know that Universal Binaries take up more space and usually run slower than a binary specifically suited for your chipset?

Xslimmer will strip out the unneeded chunks of many apps and not only free up space but speed up formerly universal apps.  I put Firefox on a diet but I hear it even works for the Adobe Photoshop Beta as well.

&lt;img src='http://blog.labratz.net/assets/2007/1/5/Xslimmer.gif' /&gt;

&lt;p&gt;&lt;a href='http://www.xslimmer.com/'&gt;Xslimmer - Your Mac, on a Diet!&lt;/a&gt;&lt;/p&gt;


&lt;b&gt;&lt;p&gt;Hazel: $16&lt;/p&gt;&lt;/b&gt;
If you're like me or many others, your desktop or hard-drive is probably a mess with files strewn everywhere. I try to keep my desktop clean but that usually means dumping them in my documents folder.  Who needs to organize when you have Spotlight right?

Not exactly.

The OS X has a bunch of functionality to keep your folders organized such as Folder Actions and Automator tasks but these require a bit of learning and is definitely not for an average user.

Hazel lets you keep your folders tidy with Mail-like rules for keeping your folders neat.  It can even apply rules retroactively.

&lt;img src='http://blog.labratz.net/assets/2007/1/5/HazelPref-Large.gif' /&gt;

&lt;p&gt;&lt;a href='http://www.noodlesoft.com/download.php'&gt;Noodlesoft&lt;/a&gt;&lt;/p&gt;

None of these apps will take center stage on your mac with the exception of WriteRoom (if you write a lot).  At most they run in the background or support a more major activity (like browsing) but these are nonetheless quality apps that can make a big difference to your experience over the long-term.

Enjoy!
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2007-01-03:294</id>
    <published>2007-01-03T02:27:39Z</published>
    <updated>2007-01-03T02:27:39Z</updated>
    <link href="http://blog.labratz.net/articles/2007/1/3/failing-gracefully" rel="alternate" type="text/html"/>
    <title>Failing gracefully</title>
<content type="html">
            Failure is something we all harbor a secret fear of.  Unless you're one of those super confident types who rarely look flustered.  Even then it's most likely there's some deep insecurity that can rock your boat.

As adults, we tend to focus on the things we do well.  However, life is rarely so kind.  There are always roadblocks, unforeseen circumstances, and disasters.  Times when we're simply unprepared.  In the world of software design this is even more crucial because programs can only do what you tell it or prepare it for.

In engineering, failure is always part of good design.  There are a variety of concepts in physical engineering such as failure rates and &lt;a href='http://en.wikipedia.org/wiki/Force_majeure'&gt;force majeure&lt;/a&gt;.  The more parts you have the more likely things can go wrong.  Various strategies utilizing a statistical approach to the likelihood of failure help ensure that things are engineered properly and will work most of the time.  It acts like a bridge between the crystal palace of pure sciences and the forces of chaos we face in the cruel world. 

Software design is of course no different.  Take this quote from one of the first class Cocoa programmers:

&lt;blockquote&gt;&lt;p&gt;&quot;I am very much in awe of the guy who invented barcodes; they are incredibly elegant. One trick is to notice that every digit in a barcode is two black stripes and two white stripes, so if you've read black-white-black-white you know you have a digit, no matter how quickly it happened. (If it happened too quickly, you can decide you're reading garbage and just bail.)&lt;/p&gt;

&lt;p&gt;One of the rules of writing algorithms that I've recently been sort of toying with is that we (as programmers) spend too much time trying to find provably correct solutions, when what we need to do is write really fast heuristics that fail incredibly gracefully.&lt;/p&gt;

&lt;p&gt;This is almost always how nature works. You don't have to have every cell in your eye working perfectly to be able to see. We can put together images with an incredible amount of damage to the mechanism, because it fails so gracefully and organically.&lt;/p&gt;

&lt;p&gt;This is, I am convinced, the next generation of programming, and it's something we're already starting to see: for instance, vision algorithms today are modeled much more closely after the workings of the eye, and are much more successful than they were twenty years ago.&quot;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;a href='http://www.drunkenblog.com/drunkenblog-archives/000581.html'&gt;On Being and Deliciousness, with Wil Shipley&lt;/a&gt;&lt;/p&gt;

Internet technology is a good illustration of this.  If you think of all the points of failure facing an average internet transaction it seems a miracle that we can stay connected so reliably and carry out a variety of activities in the safe knowledge that all will be well or can be remedied without catastrophic consequences.  If things do fail, they can be designed to fail gracefully.

Of course, that's also the catch.  Are they designed to fail gracefully?

I think it's something that we lose track of as technology advances and we have so many safeguards that we take for granted in our everyday lives.  It's shocking but we still see large-scale infrastructure failures (power outages or server facilities going out) that are more or less the byproduct of bad design.

Just some thoughts I had while dubbing some disks from HDD/DVD player.  It's a Panasonic model and frankly I've been shocked at how badly engineered the software is.  Sometimes the disk being dubbed randomly freezes (either due to a bad disk or the process comes to a halt) and the only choice you have is to pull the power or let it spin eternally.  Of course, this rough treatment voids warranty.  Looks like the engineers didn't think users would use substandard bargain disks to do their dubbing (even if you produce coasters every 5 disks it's way cheaper than the over-priced but nicely branded ones and perfectly good if the dubbing completes).  Talk about the ultimate exit choice from hell.

I think the recent fall of Japanese electronics manufacturers is not the manufacturing quality (it's still quite good, except for Sony -- which was never up to par compared to others) but the intangibles, especially the software driving the products.  For example, the Panasonic interface uses an appalling color scheme that makes characters hard to see, there is no concept of flow to common tasks like dubbing, and things are rarely intuitive.

Contrast this with Apple.  Their products are some of the best designed on the market in any category but the real gem is the software that drives their products.  The interfaces are beautiful and the engineering is rock solid.  Of course, their track record for hardware is appalling.  In the short time I've been a mac user, I've heard of whining fans, random shutdowns, sudden combustion of all kinds, all sorts of discoloring, and exploding batteries (that's Sony's fault of course).  This is just from the top of my head.  Not to mention just random hardware failures.  I rarely see a month go by when some programmer's not lamenting about sending his MacBook off to Apple Care.  I've been fortunate enough not to have to deal with Apple Care but it seems I'm one of the few.  I also avoid first generation laptops. I hate the feeling that I'm typing this on a time bomb.

Yet for all the shortcomings, I can't get enough of Apple because it's the interface that we deal with on a day to day basis and it's what forms our experience.  The interface is first class and something I only thought existed in an ideal fantasy.  Things that fail are designed to fail gracefully (you can force quit a lot of system processes and launchd will bring them back up without having to reboot).  I'd buy an OS X Vaio in a heartbeat but never a Windows-only MacBook.

Designing something to fail gracefully takes an extra bit of imagination and finesse but it's worthy goal that I hope to strive for.  Of course, I'm still not at a level where I can design something that works well much less fail gracefully so that's something for this year!
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2006-12-31:281</id>
    <published>2006-12-31T17:54:54Z</published>
    <updated>2007-01-01T00:07:03Z</updated>
    <link href="http://blog.labratz.net/articles/2006/12/31/9rules" rel="alternate" type="text/html"/>
    <title>9rules?</title>
<content type="html">
            &lt;a href='http://9rules.com/blog/2006/12/new-additions-12-28-06'&gt;I'm speechless&lt;/a&gt;.  I just couldn't believe my eyes when I saw the sudden spike on my Google Analytics page with the bulk of referrals coming from &lt;a href='http://9rules.com/'&gt;9rules.com&lt;/a&gt;.

Guess I'll need to step up my game!

&lt;p&gt;&lt;a href='http://9rules.com/blog/2006/12/new-additions-12-28-06/'&gt;New additions: 12-28-06 » 9rules Network Official Blog&lt;/a&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2006-12-21:236</id>
    <published>2006-12-21T05:20:25Z</published>
    <updated>2007-01-01T00:07:03Z</updated>
    <link href="http://blog.labratz.net/articles/2006/12/21/principles-behind-the-kamikaze-manifesto" rel="alternate" type="text/html"/>
    <title>Principles behind the Kamikaze Manifesto</title>
<content type="html">
            I was reflecting on my development style and thought to myself, &quot;this could be the new agile&quot;.  Of course, I'm just a hobbyist.




&lt;b&gt;Principles behind the Kamikaze Manifesto&lt;/b&gt;


We follow these principles:

Our highest priority is to satisfy our sanity
through early and continuous delivery
of semi-doable software that at least does not crash or cause death.

Welcome changing requirements, even late in
development because none of them were realistic to start with. 
Kamikaze processes harness downward spiraling change in order to
pass the minimum requirements to pay rent.

Deliver working software frequently, from a
couple of weeks to a couple of months, with a
preference to the shorter timescale 
even if it means that all we did is tweak css and html
only to find that Internet Explorer bugs make it worse than it was.

Business people and developers must work
together daily throughout the project
because in reality kamikaze coders are business people in disguise who write their programs in MS Word.

Build projects around loud, obnoxious individuals.
Give them the environment and support they need,
and trust them to silence clients.

The most efficient and effective method of
conveying information to and within a development
team is hit-and-run emails and answering machines, 
keep chat off at all times.

Working software is the primary measure of progress.
Grafting a new look onto an opensource project is a perfectly valid way to achieve this.

Kamikaze processes promote sustainable development
because we collect money for essentially delivering ether.
The sponsors, developers, and users should be able
to maintain a constant pace indefinitely as long as money is freely available.

Continuous attention to financial gain
and good marketing enhances kamikaze-ness.

Simplicity--the art of maximizing the amount
of work not done and money simultaneously--is essential.

The best architectures, requirements, and designs
emerge from self-organizing teams which is why opensource is the best for poaching code.

At regular intervals, the team reflects on how
to become more effective, then heads to the local bar.  
Time spent at the bar is a billable activity.

&lt;p&gt;&lt;a href='http://agilemanifesto.org/principles.html'&gt;Principles behind the Agile Manifesto&lt;/a&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2006-12-19:217</id>
    <published>2006-12-19T12:07:00Z</published>
    <updated>2007-01-01T00:07:03Z</updated>
    <link href="http://blog.labratz.net/articles/2006/12/19/y-include-dependencies" rel="alternate" type="text/html"/>
    <title>Y include dependencies</title>
<content type="html">
            Going for a dramatic title.  Here's a quick tip.  Next time you install a gem with dependencies give your fingers rest by typing:

		gem install rails -y

Instead of:

		gem install rails --include-dependencies  

It's the same thing.
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2006-12-19:213</id>
    <published>2006-12-19T01:50:00Z</published>
    <updated>2007-01-01T00:10:07Z</updated>
    <link href="http://blog.labratz.net/articles/2006/12/19/return-to-the-rescue-in-views" rel="alternate" type="text/html"/>
    <title>Return to the rescue in views</title>
<content type="html">
            I was thinking of a way to show a navigation bar with subcategories depending on what the user was doing.  For example if the user was looking at an article I wanted a subset of actions relevant to that individual article.  That's a perfect job for &quot;if current_page?(:action =&gt; &quot;something&quot;)&quot; but if you apply any styling to that you end up with an empty pair of tags in your html.  And as always it looks really funky (and I mean it in a bad way) especially in windows IE.

By using return in the else conditional I found you can quickly snap out of it and avoid empty divs.  How charming.


   &lt;pre&gt;
    &lt;div&gt;
        &amp;lt;% if current_page?(:action =&gt; &quot;show&quot;) %&gt;
            &amp;lt;%= link_to 'Edit', :controller =&gt; &quot;article&quot;, :action =&gt; 'edit', :id =&gt; @article %&gt;|
            &amp;lt;%= link_to 'Destroy', { :controller =&gt; &quot;article&quot;, :action =&gt; 'destroy', :id =&gt; @article }, :confirm =&gt; 'Are you sure?', :method =&gt; :post %&gt;
        &amp;lt;% else %&gt;
          &amp;lt;% return %&gt;
        &amp;lt;% end %&gt;
    &lt;/div&gt;
   &lt;/pre&gt;
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2006-12-15:185</id>
    <published>2006-12-15T00:28:17Z</published>
    <updated>2007-01-01T00:07:03Z</updated>
    <link href="http://blog.labratz.net/articles/2006/12/15/hashwithnotsoindifferentattitude" rel="alternate" type="text/html"/>
    <title>HashWithNotSoIndifferentAttitude</title>
<content type="html">
            I was doing some stuff with serialized objects.  Basically, I wanted to use serialized objects as a halfway house for holding an array of hashes before they get promoted into full-fledged objects.  The thing is I also want to read each item of the array into an editable form (not using any in-place editing).

Serialization is a one-line configuration and reading the hashes into an editable form was easy enough but allowing a roundtrips for the data was difficult.

The serialized object is actually a database field on the object proper stored in YAML format (it's applied on the way in and out so it acts like a pseudo object).  You can store it as an Array or Hash or some combination.

The main problem was that when I passed in the params of the edited form, the individual objects within the Array suddenly became a HashWithIndifferentAccess and the key values were saved as strings.  This was not cool because now I had a serialized object in two formats making it impossible to meaningfully compare them.

Of course, this would not affect the step where I convert the hash into an object but I'd rather keep the data in a unified format that allows easy comparison for duplicates.  

I essentially had two choices:

1. Convert the hash into the string and then compare them.

		{:key =&gt; &quot;value&quot;}.to_s == {&quot;key&quot; =&gt; &quot;value&quot;}.to_s

2. Make sure they get saved properly and not worry about them.


Here's what I did.  First the object:

    class Invitation &amp;lt; ActiveRecord::Base 
      serialize :invitees_list 


The view that reads it into an editable form:

		  &amp;lt;% @invitation.invitees_list.each_with_index do |invitee, index| %&gt;
		     &lt;p&gt;Recipient: &amp;lt;%= text_field_tag &quot;invitee[#{index}][recipient]&quot;, invitee[:recipient], :class =&gt; 'input_box' %&gt; Email: &amp;lt;%= text_field_tag &quot;invitee[#{index}][email]&quot;, invitee[:email], :class =&gt; 'input_box' %&gt;&lt;/p&gt;
		  &amp;lt;% end %&gt;
		&amp;lt;% end %&gt;


Controller:

      def update
        @invitation = Invitation.find(params[:id])
        @invitation.invitees_list = rehash_email(params[:invitee].values) unless params[:invitee].nil?


Helper methods for the hash:

      def hash_email(recipient, email = recipient)
        emails = {:recipient =&gt; recipient,
                  :email =&gt; email}
      end
  
      def rehash_email(bad_array)
        array = []
        bad_array.each {|funny_hash| array &amp;lt;&amp;lt; hash_email(funny_hash[&quot;recipient&quot;], funny_hash[&quot;email&quot;])}
        array
      end


This gives me the ability to roundtrip data without fiddling formats.  When the form values of the view are submitted I get params like the following.

		&quot;invitee&quot;=&gt;{&quot;6&quot;=&gt;{&quot;recipient&quot;=&gt;&quot;john&quot;, &quot;email&quot;=&gt;&quot;john@example.com&quot;}, &quot;7&quot;=&gt;{&quot;recipient&quot;=&gt;&quot;jenny&quot;, &quot;email&quot;=&gt;&quot;jen@jen.com&quot;}}

I need the numbers to keep all the values unique (otherwise I just get the last value submitted) and keeping the info in pairs but not needed for the object itself.  By ordering them such I can call params[:invitee].values and strip out the numbers but that gives me strings for keys.  That's where rehash_email comes in.

As an additional step I have a before\_save callback that calls the flatten! method (otherwise I get two separate Arrays of hashes).

The lesson?  Indifferent hashes aren't so indifferent when you try to do something different.  I doubt this is a case of syntactic vinegar but it does add slight overhead.  However, the upside is that I don't have to clutter my tables with meaningless objects.
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2006-12-14:177</id>
    <published>2006-12-14T04:24:39Z</published>
    <updated>2007-01-01T00:07:03Z</updated>
    <link href="http://blog.labratz.net/articles/2006/12/14/liberating-myself-from-password-hell" rel="alternate" type="text/html"/>
    <title>Liberating Myself from Password Hell</title>
<content type="html">
            I got this app called &lt;a href='http://1passwd.com/'&gt;1passwd&lt;/a&gt; as one of the many pieces of loot from &lt;a href='http://macheist.com'&gt;macheist&lt;/a&gt; of &lt;a href='http://gusmueller.com/blog/archives/2006/12/week_of_the_independent_mac_developer.html'&gt;recent controversy&lt;/a&gt;.  Of the 11 or so free apps I got from &quot;participating&quot; in the heists this is really the only one that I'm really glad to have.  One of the things that struck me after switching from windows to the mac was the number of high-quality programs offered by independent developers.  At the same time with the rising tide of switchers (both developers and users) there's a growing number of third-rate eye candy apps marketed heavily and selling for competitive prices.  It's getting harder to find the gems amongst the lesser known apps.


One of the artifacts of my previous incarnation as a windows user was the the sheer number of passwords and identities locked into Firefox.  Firefox's password management is really nice and it allowed me to transition my online life from windows to the mac by simply transferring my user profile folder.  It auto-completes the bulk of my logins so I don't have to remember every minor site I might have registered.

Still, it raises a number of concerns:

1. I'm locked into Firefox because switching to Safari means rummaging through memory lane to remember old passwords

2. There's some concern with security using automatic logins and the default Firefox set up makes it easy to locate necessary files to steal someone's password.

3. Increasing security naturally decreases convenience (frequent timeouts, master password, etc.)

4. My identities on multiple computers stay out of sync.

It essentially piggybacks on OS X's keychain support so it's all in one safe place.  It also gives you:

1. Automatic form completion based on multiple identities to prevent repetitive typing of name, address, etc.

2. Automatically generated strong passwords

3. Additional protection against keylogging and phishing.

This thing imported all my firefox logins and passwords flawlessly.

It might sound like a plug but this is not paid in anyway.  Although I wouldn't mind putting an ad in the sidebar sometime in the future...

It does cost $29.95 for a full version (free to try on 12 forms forever) and that does seem a bit expensive.  You do have to spend some time with it before you can truly appreciate it but it should be worth it.

&lt;img src='http://blog.labratz.net/assets/2006/12/14/password_manager_logo.png' height='64' alt='1passwd' width='64' /&gt;



&lt;p&gt;&lt;a href='http://1passwd.com/'&gt;Password Manager + AutoFill for Mac OS X&lt;/a&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2006-12-10:163</id>
    <published>2006-12-10T03:53:06Z</published>
    <updated>2007-01-01T00:07:03Z</updated>
    <link href="http://blog.labratz.net/articles/2006/12/10/using-mocks-for-those-hard-to-reach-areas" rel="alternate" type="text/html"/>
    <title>Using Mocks for those Hard to Reach Areas</title>
<content type="html">
            I'm only getting the hang of mocks but I think I'm finally realizing how useful these things are.  A case in point is writing a test for rails observers.  Rails observers are actually sub-classed under its namesake model.  For example UserObserver is treated as a subclass of User for the sake of callbacks.

I have separate unit tests for the notifiers triggered by observers but I also wanted a sanity check to ensure that observers were doing there work as well.  Even though I knew it was very much the case by monkey clicking.

With &lt;a href='http://mocha.rubyforge.org/'&gt;mocha&lt;/a&gt; it's dead simple.

Suppose you have an observer that does something after the User model is created.  If you want to ensure the method is called on creation, all you need are the following lines:


    require File.dirname(__FILE__) + '/../test_helper'

    class UserObserverTest &amp;lt; Test::Unit::TestCase
  
      def test_user_create_triggers_observer
        @observer = UserObserver.instance
        @observer.expects(:after_create).at_least_once
        user = User.create({ :login =&gt; &quot;john&quot;, :email =&gt; &quot;john@example.com&quot;, :password =&gt; 'guess', :password_confirmation =&gt; 'guess'})
      end
    end


You'll appreciate the brevity of this if you take a peek at the testing of observers done in the rails core &lt;a href='http://dev.rubyonrails.org/browser/trunk/activerecord/test/lifecycle_test.rb?rev=4'&gt;here&lt;/a&gt;.

This really saves me time from jumping through hoops to recreating an universe of rails code just to test one isolated method with a complicated &quot;def setup&quot;.  Pretty cool.  You can use this to test all the nooks and crannies that you want without draining your precious time.
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2006-12-05:138</id>
    <published>2006-12-05T20:28:00Z</published>
    <updated>2007-01-01T00:07:03Z</updated>
    <link href="http://blog.labratz.net/articles/2006/12/5/officially-migrated-to-mephisto-from-typo" rel="alternate" type="text/html"/>
    <title>Officially Migrated to Mephisto from Typo</title>
<content type="html">
            Yes, I'm now officially on mephisto and will more or less stay with it as long as I can.  I must say that a lot of things about mephisto just feel right.  The experience is remarkably close to MovableType, a platform that I've used for over two years.

Easy edit templates accessible from the control panel was something that I liked about MovableType.  I can finally put my Google analytics account to use without any &quot;hacking&quot;.

The process was simple:

- Added my typo config to database.yml under &quot;typo:&quot;

- SSH into the main directory and type:

		script/runner &quot;Mephisto.convert_from :typo&quot; -e production

- In the settings add the following so typo links don't break:

		articles/:year/:month/:day/:permalink

Just to think that it was built in a fraction of the time that MovableType has been around by essentially two guys is mind-blowing.

However, I wouldn't take it as a shining example of &quot;l33t rails r0xxx0rzzss pwn U&quot; but a testament to Rick and Justin's talent.

Too bad Gear of War came out.  Let's hope he doesn't get his hands on a Wii...
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2006-12-04:73</id>
    <published>2006-12-04T14:29:00Z</published>
    <updated>2007-01-01T00:07:03Z</updated>
    <link href="http://blog.labratz.net/articles/2006/12/4/keeping-tabs-on-attribute-changes-in-your-models" rel="alternate" type="text/html"/>
    <title>Keeping tabs on attribute changes in your models?</title>
<content type="html">
            With rails' database mapping updating various attributes to your models is a breeze and quite flexible with all the callbacks.  So I thought it would be a breeze to do a callback on whether a given model attribute is changed.

For example, the user authentication needs to redo the activation process if a user changes their email address.  Doing the initial activation is easy with a before_create callback.  So where is the before_attribute_changed callback?

There is none.  You'll have to figure out a way to do it yourself.  There are plugins out there such as &lt;a href='http://svn.viney.net.nz/things/rails/plugins/acts_as_modified/'&gt;acts\/as\/modified&lt;/a&gt; that add such methods but I only need a one-off solution.

Here is the code:

		class User &amp;lt; ActiveRecord::Base

			attr_accessor :old_email

			def email=(new_email)
			  @old_email = read_attribute(:email)
			  write_attribute :email, new_email
			end

			def before_update
			  (make_activation_code &amp;&amp; self.activated_at = nil) if self.email_changed?
			end

			def email_changed?
			  (self.old_email.nil? || self.old_email == self.email) ? false : true
			end
		end

Basically, you create an accessor called old\_email because there is no such column in your database, then you redefine the email attribute setter method that comes out of the box.  This will swap out the old email into, drum-roll please, into an attribute called old\_email before being overwritten with a new value.

The before update callback resets the activation and email\_changed? is a convenient wrapper.

Yes, I realize that this method may result in stranded users who mistype their new address.  Just an illustration.
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2006-12-02:72</id>
    <published>2006-12-02T14:25:28Z</published>
    <updated>2007-01-01T00:07:03Z</updated>
    <link href="http://blog.labratz.net/articles/2006/12/2/how-to-really-get-mephisto-on-dreamhost" rel="alternate" type="text/html"/>
    <title>How to Really Get Mephisto on Dreamhost</title>
<content type="html">
            My blog post on this seems like the premier destination on how to get Mephisto on Dreamhost.  Unfortunately, the directions stopped working at some point (although it's been updated now thanks to the new info).

Thank goodness someone figured it out!  If you want to get mephisto on dreamhost &lt;a href='http://mede.us/2006/12/1/mephisto-and-dreamhost'&gt;follow these instructions.&lt;/a&gt;  It's the surest way.

Looks like you just can't stay on edge with Mephisto &amp; dreamhost.  You need to download the zip.  I'm sure this will change for the better when Rails 1.2 rolls out.

I followed the directions with some guidance from my original post and put &lt;a href='http://railerz.com/'&gt;railerz.com&lt;/a&gt; back online.

Not sure I'll go that route since I'm being plagued by a lot of spam and I've hacked my typo to mark as spam and delete it at the same time.  I think the only thing that would convince me to switch is a tricked out spam killing interface.  MovableType does a really good job with this with a &quot;junk&quot; folder that acts as a holding cell.  You can set it to get nuked after an x number of days.  That's about the only killer feature I need.

Having said that, mephisto code is the example that I look at almost daily for inspiration and it's nice that I can play with it locally and in live production.  If I was to start a blog today I'd definitely go with mephisto.

For all you struggling souls:

&lt;p&gt;&lt;a href='http://mede.us/2006/12/1/mephisto-and-dreamhost'&gt;mede.us Mephisto and Dreamhost&lt;/a&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2006-12-02:71</id>
    <published>2006-12-02T05:01:00Z</published>
    <updated>2007-01-01T00:07:03Z</updated>
    <link href="http://blog.labratz.net/articles/2006/12/2/a-rake-task-for-rcov" rel="alternate" type="text/html"/>
    <title>A rake task for rcov</title>
<content type="html">
            I was using the &lt;a href='http://blog.codahale.com/2006/05/26/rails-plugin-rails_rcov/'&gt;rcov plugin from Coda Hale&lt;/a&gt; for a while but wanted to trim down the list of growing rake tasks since the plugin appends an rcov version to every variety of the test task.  I only need something that runs them all.  Plus, the plugin doesn't accurately show coverage compared to unit or functional tests run individually for code under the lib directory.  At least for me.

Here's my rake task for rcov that modifies the &lt;a href='href=' /&gt;Rails Plugin: rails_rcov | Archives | codablog | Coda Hale&lt;/a&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2006-12-02:70</id>
    <published>2006-12-02T01:44:36Z</published>
    <updated>2007-01-01T00:07:03Z</updated>
    <link href="http://blog.labratz.net/articles/2006/12/2/rails-dropping-the-mysql-ball" rel="alternate" type="text/html"/>
    <title>Rails dropping the MySQL ball?</title>
<content type="html">
            Since migrating to a MacBook I've been tweaking stuff back into shape.  Everything was working as expected until I updated my MySQL.  For some reason rake was dropping connections and not running unit tests.

It took me back quite a bit to the days when I was struggling to get rails simply running forgetting how nice it is to have your environment all set up.

I was a quick fix using Marc Liyanage's uninstallation script and then removing the mysql gem (this is the important step) then re-installing the gem.

&lt;p&gt;&lt;a href='http://www.entropy.ch/software/macosx/mysql/remove-old-mysql.html'&gt;Marc Liyanage - Software - Mac OS X Packages - MySQL - Remove old MySQL&lt;/a&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.labratz.net/">
    <author>
      <name>labrat</name>
    </author>
    <id>tag:blog.labratz.net,2006-12-01:69</id>
    <published>2006-12-01T03:05:29Z</published>
    <updated>2007-01-01T00:07:03Z</updated>
    <link href="http://blog.labratz.net/articles/2006/12/1/handling-structured-data-with-activerecord" rel="alternate" type="text/html"/>
    <title>Handling Structured Data with ActiveRecord</title>
<content type="html">
            I decided that I wanted to save structured data to a database field.  Specifically an array of hashes for creating a separate object later.  This data would serve as an intermediary form or draft before the user decided to finalize the creation.

I had the methods that process raw input into the proper hashes that would easily generate new objects with Object.new.  However, I wasn't aware that an array of hashes would lose structure on the way to becoming an ActiveRecord object attribute when the data is input via a form.

This is easily remedied with:

      class Car &amp;lt; ActiveRecord::Base  
        serialize :info
      end

You can also append &quot;, Hash&quot; or &quot;, Array&quot; to restrict the data-type that can be saved rather than leave it to rails.

This will save the data in yaml (equivalent to calling .to_yaml) format so if you want your array, hash or any combination of either you need to process it back.  This is of course easy.

I'll skip a real example using the above model and simply show you the relevant methods:

		@car = {:maker =&gt; &quot;General Motors&quot;, :model =&gt; &quot;Cadillac&quot;} 
       #via web would become: &quot;--- \n:maker: General Motors\n:model: Cadillac\n&quot; same as calling .to_yaml
		YAML::load(@car.info)
		# this will be return it to a hash

The only difficulty I had was with using values separated by newline characters when saving data via an input form.  Rails converts the newlines in the form of &quot;\r\n&quot; instead of just &quot;\n&quot; so the processing code I wrote worked fine in unit tests within ruby but gave me empty hashes via the controller/views.  Couldn't figure it out or waste the time pinning it down so I simply substituted them with spaces so I can simply use the split method and be done with it. 

		def replace_newlines!
		  return if self.nil?
		  self.gsub(&quot;\r\n&quot;,&quot; &quot;) || self
		end

This goes against the convention of normal ruby !methods by not returning nil if no substitution is made.  I wanted it to be &lt;a href='http://en.wikipedia.org/wiki/Idempotence_(computer_science)'&gt;idempotent&lt;/a&gt; and not throw a monkey wrench when it's called rather than handle it with errors and exceptions.

Mainly, two scenarios that were perfectly valid in my application:

1.  Calling it on nil since users might not put this info in to start
1.  Calling it on a string without any newline characters

This is something beginners like me need to keep in mind because if a method call returns nil it might screw up a whole slew of processes downstream.  In the worst case scenario the method does nothing and that's actually a plus when processing some forms of data.

Consider this:

		irb(main):069:0&gt; comment = &quot;sssssoooooo kewl&quot;
		=&gt; &quot;sssssoooooo kewl&quot;
		irb(main):070:0&gt; comment.squeeze!
		=&gt; &quot;so kewl&quot;
		irb(main):071:0&gt; comment.squeeze!
		=&gt; nil

Of course the comment is not nil after repeated squeezes:
		irb(main):099:0&gt; comment
		=&gt; &quot;so kewl&quot;


The idempotent way (I think):

		def good_squeeze!
		  return if self.nil?
		  self.squeeze! || self
		end  


		irb(main):086:0&gt; comment = &quot;sssssoooooo kewl&quot;
		irb(main):087:0&gt; comment.good_squeeze!
		=&gt; &quot;so kewl&quot;
		irb(main):088:0&gt; comment.good_squeeze!
		=&gt; &quot;so kewl&quot;
		irb(main):089:0&gt; comment.good_squeeze!
		=&gt; &quot;so kewl&quot;


It's also harmless on a nil object:

		irb(main):094:0&gt; nil.squeeze!
		NoMethodError: undefined method `squeeze!' for nil:NilClass
		        from (irb):94


		irb(main):095:0&gt; nil.good_squeeze!
		=&gt; nil
		
Of course, being a newb I'm really not sure if this is really the best way to do it but at least in my case it prevents unnecessary breakage no matter what data you throw at it.  It's mainly for using bang methods on the other side of an assignment but doesn't matter if called &quot;in place&quot; as the return of a nil value.  As I write this I'm starting to think that maybe I shouldn't be calling bang methods on the other side of an assignment but simply calling it in place.

Either way, I'll be learning as I go.  I think I got like 20 readers who might self-destruct by following my advice.  Food  for newbie thought.
          </content>  </entry>
</feed>
