<?xml version='1.0'?><rss xmlns:admin='http://webns.net/mvcb/' version='2.0' xmlns:sy='http://purl.org/rss/1.0/modules/syndication/' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
    <channel>
    <title>www.ian.dees.name</title>
    <link>http://www.ian.dees.name</link>
    <description>running on fumes for three decades</description>
    <dc:language>en-us</dc:language>
    <dc:creator/>
    <dc:date>2009-10-31T17:37:15+00:00</dc:date>
    <admin:generatorAgent rdf:resource='http://hobix.com/?v=0.5'/>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase>
    <item><title>how to speak robinese</title><link>http://www.ian.dees.name/life/how-to-speak-robinese.html</link><guid isPermaLink='false'>life/how-to-speak-robinese@http://www.ian.dees.name</guid><dc:subject>life</dc:subject><dc:subject>life</dc:subject><dc:creator>undees</dc:creator><dc:date>2009-10-31T16:41:43+00:00</dc:date><description xml:space='preserve'>&lt;p&gt;The baby is teaching me how to speak Robinese. This is a greater
intellectual challenge, she reasons, than merely learning English
would be (which she&amp;#8217;s also doing). Old dogs, new tricks, and all
that.&lt;/p&gt;


	&lt;p&gt;From what I&amp;#8217;ve been able to gather, Robinese is more of an &lt;a href=&quot;http://en.wikipedia.org/wiki/Analytic_language&quot;&gt;analytic
language&lt;/a&gt; than
English. She changes the meanings of words not by gluing on prefixes
or suffixes, but by adding more words. For example, I would stick
together two concepts and a suffix in one word to refer to my
&lt;em&gt;absentmindedness&lt;/em&gt;. She would express the same sentiment using
separate words: &amp;#8220;silly Daddy.&amp;#8221;  We intensify a word by adding &amp;#8220;-er&amp;#8221; 
or &amp;#8220;-est.&amp;#8221;  She does so by repeating the word: &amp;#8220;shoo shoo bad bad,&amp;#8221; 
she says to the cats or anyone else who crosses her.&lt;/p&gt;


	&lt;p&gt;Her most creative use of this technique so far has to be &amp;#8220;water
monkey balls,&amp;#8221; her term for &amp;#8220;museum&amp;#8221; (don&amp;#8217;t all museums have a giant
monkey and an aquatic play room?).&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://www.ian.dees.name/lalo-monkey-ball.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Other linguistic highlights:&lt;/p&gt;


	&lt;p&gt;Normally we don&amp;#8217;t modify pronouns: we can say &amp;#8220;red car,&amp;#8221; but not
&amp;#8220;red it.&amp;#8221; Robinese has no such restriction: &amp;#8220;my this&amp;#8221; is a
frequent utterance when she has no idea what to call something,
but knows she wants it.&lt;/p&gt;


	&lt;p&gt;&amp;#8220;All right&amp;#8221; is not just a response to cajoling (as in, &amp;#8220;all right,
I&amp;#8217;ll do it, quit bugging me&amp;#8221;); it is also an &lt;em&gt;expression&lt;/em&gt; of
cajoling. Can you imagine waking up to a baby standing next to
your bed, pulling on your arm and saying, &amp;#8220;All right, all right,
all right?&amp;#8221;&lt;/p&gt;


	&lt;p&gt;Word meanings are extremely dependent on context. The single-word
sentence, &amp;#8220;Hold,&amp;#8221; can mean, &amp;#8220;I want to play with the cups that are
on that table,&amp;#8221; or &amp;#8220;If you value your eardrums, you&amp;#8217;ll pick me up
right now.&amp;#8221;&lt;/p&gt;


	&lt;p&gt;Next lesson starts today. Can&amp;#8217;t wait.&lt;/p&gt;</description></item><item><title>drain bump</title><link>http://www.ian.dees.name/life/drain-bump.html</link><guid isPermaLink='false'>life/drain-bump@http://www.ian.dees.name</guid><dc:subject>life</dc:subject><dc:subject>life</dc:subject><dc:creator>undees</dc:creator><dc:date>2009-09-05T06:07:45+00:00</dc:date><description xml:space='preserve'>&lt;p&gt;We have a drawer at the house we call the &amp;#8220;oh, shit&amp;#8221; drawer. It has
chargers for long-discontinued phones (hey, Nokia might start making
the &lt;a href=&quot;http://en.wikipedia.org/wiki/Brick&quot;&gt;2120&lt;/a&gt; again!). It has enough
paperclips and safety pins to melt down and make, say, a
medium-sized bicycle. It&amp;#8217;s got crap I don&amp;#8217;t even know what to call.&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/threadedthoughts/3258974154/&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3411/3258974154_508d5d3e61_m.jpg&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;Welcome to the verbal equivalent of that drawer. What&amp;#8217;s left to write
about here? Flash-pan, off-the-cuff insights go on Twitter. Code
goes on GitHub, thanks to
&lt;a href=&quot;http://bitbucket.org/abderrahim/hg-git&quot;&gt;hg-git&lt;/a&gt;. Prose, if I&amp;#8217;m
excited enough to feel compelled to type it in no matter where I am,
gets e-mailed straight to
&lt;a href=&quot;http://undees.posterous.com&quot;&gt;Posterous&lt;/a&gt;. And if I&amp;#8217;m not excited to
write it? Well, you&amp;#8217;re lookin&amp;#8217; at it, bub.&lt;/p&gt;


	&lt;p&gt;Weird that just a couple of years ago, a domain was a one-stop shop
to put everything you cared about: reading, writing, code, life,
photos, essays, quips, everything. Now, our identities are so
sharded. (No, not
&lt;a href=&quot;http://www.imdb.com/title/tt0343135/quotes&quot;&gt;sharted&lt;/a&gt;.) Not a bad
thing, necessarily. A bunch of people I know get way more eyeballs
on their tweets than they ever did on their blog posts. And one gal
uses the Internet as kind of a fault-embracing distributed backup of
her brain. Why worry about meticulously finding room on your
computer to put stuff, the reasoning goes, when you can blast it out
into the ether?&lt;/p&gt;


	&lt;p&gt;Tempting.&lt;/p&gt;


	&lt;p&gt;Still, though, the retro-2000s curmudgeon in me says that
www.yourname.com is better than facebook.com/yourname plus
twitter.com/yourname. Not that these are mutually exclusive, but
realistically, how much time do we all have to be de-facto system
admins of ten different websites? In our spare time, no less?&lt;/p&gt;


	&lt;p&gt;And what&amp;#8217;s left to put on your own domain when you&amp;#8217;ve already said
everything elsewhere? Just an aggregation of crud that lives
elsewhere?&lt;/p&gt;


	&lt;p&gt;I dunno, maybe I&amp;#8217;m overthinking this (shocker!). Probably best just
to let all those other (a)venues be breeding grounds for ideas, and
use good ol&amp;#8217; Ctrl-C plus Ctrl-V to bring the greatest hits into one
place.&lt;/p&gt;


	&lt;p&gt;Not that there won&amp;#8217;t always be that little monkey voice saying,
&amp;#8220;Wouldn&amp;#8217;t it be cool to have a little script to tie this all
together? C&amp;#8217;mon, let&amp;#8217;s fire up Emacs&amp;#8230;.&amp;#8221;&lt;/p&gt;</description></item><item><title>bacon cucumber sandwich</title><link>http://www.ian.dees.name/tech/bacon-cucumber-sandwich.html</link><guid isPermaLink='false'>tech/bacon-cucumber-sandwich@http://www.ian.dees.name</guid><dc:subject>tech</dc:subject><dc:subject>tech</dc:subject><dc:creator>undees</dc:creator><dc:date>2009-05-26T15:08:44+00:00</dc:date><description xml:space='preserve'>&lt;p&gt;Dammit,
&lt;a href=&quot;http://gilesbowkett.blogspot.com/2009/05/one-way-to-escape-cargo-cult.html&quot;&gt;scooped&lt;/a&gt;
by Giles. I hint tantalizingly at an upcoming article on &lt;a href=&quot;http://github.com/chneukirchen&quot;&gt;Bacon&lt;/a&gt;
and &lt;a href=&quot;http://cukes.info&quot;&gt;Cucumber&lt;/a&gt;, and he goes and writes the damn
thing. I was even gonna raid Flickr for an appropriate picture, just like
he did (this one&amp;#8217;s courtesy of user nicubunu):&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/kyletramirez/3611597405&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3628/3611597405_f37f8ec730_m.jpg&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p style=&quot;clear:both;&quot;&gt;Ah well. It turns out we have different
things to say on the matter, anyway. Giles was making an important
point about understanding the tools you work with, and you should
listen to him. I&amp;#8217;m just going to say something much more mundane
about using these two particular test libraries together.&lt;/p&gt;

	&lt;p&gt;You&amp;#8217;ll recall that Cucumber&amp;#8217;s ancestor, the Story Runner, used to be
part of RSpec. So it made sense to use RSpec as your one-stop
testing shop, for unit tests, acceptance tests, mocks, stubs, and
best of all, the beautiful &amp;#8220;should&amp;#8221; syntax for assertions.&lt;/p&gt;


	&lt;p&gt;Of course, RSpec has long supported drop-in replacements for most of
these, should you have a favorite stub library or such. The spinning
off of Cucumber has made it that much more timely to consider
custom-fitting each layer of your tests.&lt;/p&gt;


	&lt;p&gt;You certainly can use RSpec&amp;#8217;s assertions underneath your Cucumber
stories, as we&amp;#8217;ve
&lt;a href=&quot;http://www.ian.dees.name/tech/cucumber-for-a-story.html&quot;&gt;seen&lt;/a&gt;. But
let&amp;#8217;s say I&amp;#8217;m some kind of hypothetical curmudgeonly developer who
doesn&amp;#8217;t want to download an entire test + assertion + mock + stub
framework, just to get nice assertions for Cucumber. What do I do?&lt;/p&gt;


	&lt;p&gt;Well, one option is Bacon (Christian Neukirchen&amp;#8217;s nod to RSpec;
&amp;#8220;Spec&amp;#8221; in German means &amp;#8220;Bacon&amp;#8221;), which gives you RSpec-style
asssertions, but leaves you to find or invent your own mocking,
Rails integration, Web bindings, and so on.&lt;/p&gt;


	&lt;p&gt;Because it comes without all those extras, and because it &amp;#8220;cuts with
the grain&amp;#8221; of Ruby in its design, the Bacon core weighs in at a
svelte 356 lines of code as of this writing&amp;#8212;that&amp;#8217;s counting
comments, but not tests.  If you stick to the basics, it feels a lot
like RSpec, with two important distinctions worth mentioning here:&lt;/p&gt;


&lt;ol&gt;
&lt;li&gt;RSpec assertions tend to use spaces and underscores to separate words, while Bacon
tends to use dots. So &lt;code&gt;answer.should be_true&lt;/code&gt;
becomes &lt;code&gt;answer.should.be.true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;RSpec always throws an exception when a test fails. Bacon
tailors its behavior to whether it thinks
you&amp;#8217;re manually typing code into &lt;code&gt;irb&lt;/code&gt; or running an
automated test. So to use Bacon with Cucumber, you have to throw
&lt;code&gt;Bacon::Counter[:depth] = 1&lt;/code&gt; inside your
&lt;code&gt;env.rb&lt;/code&gt; somewhere, effectively saying, &amp;#8220;Hey, Bacon,
we&amp;#8217;re inside a test framework, even though you don&amp;#8217;t see a
&lt;code&gt;describe&lt;/code&gt; block anywhere.&amp;#8221;&lt;/li&gt;
&lt;/ol&gt;

	&lt;p&gt;So for the &lt;a href=&quot;http://bitbucket.org/undees/idgtr-code/src/tip/story/&quot;&gt;party-planning
example&lt;/a&gt; from
the book, all you&amp;#8217;d need to do is &lt;code&gt;require 'bacon'&lt;/code&gt;, do
the counter-depth thing I described above, make a quick pass through
the &lt;code&gt;should&lt;/code&gt;s to &amp;#8220;decimalize&amp;#8221; them, and&amp;#8230; deal with
custom matchers.&lt;/p&gt;


	&lt;p&gt;For simplicity&amp;#8217;s sake, Bacon omits some of RSpec&amp;#8217;s fancier
matchers. In particular, &lt;code&gt;object.should have_foo&lt;/code&gt; doesn&amp;#8217;t
automatically call &lt;code&gt;object.has_foo?&lt;/code&gt;. But we can get
pretty close to that with a custom matcher, which in Bacon is a
plain old top-level function:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
  def have(suffix, *args)
    lambda do |obj|
      obj.send &quot;has_#{suffix}?&quot;, *args
    end
  end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Then, instead of &lt;code&gt;party.should have_location&lt;/code&gt;, you&amp;#8217;ll
write &lt;code&gt;party.should.have(:location)&lt;/code&gt;.&lt;/p&gt;


	&lt;p&gt;What have we gained from all this? If your project already has
code-level tests in RSpec, you can get &lt;code&gt;should&lt;/code&gt;-style
assertions in your acceptance tests for free&amp;#8212;might as well use
&amp;#8216;em. But if you don&amp;#8217;t need the mocks and extras that come with RSpec
(maybe you&amp;#8217;re testing non-Ruby project!), and you just want the
assertion syntax, that&amp;#8217;s where Bacon comes in.&lt;/p&gt;


	&lt;p&gt;Anyway, have a look at the
&lt;a href=&quot;http://bitbucket.org/undees/idgtr-code-bacon/src/tip/bacon.diff&quot;&gt;diff&lt;/a&gt;
between an RSpec project and a Bacon one; it&amp;#8217;s quite easy to migrate
from one to the other. Me, I&amp;#8217;m going to lunch. Enjoy!&lt;/p&gt;</description></item><item><title>cucumber for a story</title><link>http://www.ian.dees.name/tech/cucumber-for-a-story.html</link><guid isPermaLink='false'>tech/cucumber-for-a-story@http://www.ian.dees.name</guid><dc:subject>tech</dc:subject><dc:subject>tech</dc:subject><dc:creator>undees</dc:creator><dc:date>2009-02-18T06:57:35+00:00</dc:date><description xml:space='preserve'>&lt;p&gt;Ah, technology.  Write a &lt;a href=&quot;http://pragprog.com/titles/idgtr&quot;&gt;book&lt;/a&gt;
with a chapter on testing programs in plain English, and they go and
&lt;a href=&quot;http://blog.davidchelimsky.net/2008/9/22/cucumber&quot;&gt;change the
software&lt;/a&gt; the next
morning.  It would be enough to make a more timorous developer tip
the entire bookshelf into the dustbin and give up on testing
altogether.&lt;/p&gt;


	&lt;p&gt;But not us.  You and I, we&amp;#8217;re going strap &lt;a href=&quot;http://wiki.github.com/aslakhellesoy/cucumber/migration-from-rspec-stories&quot;&gt;Aslak&amp;#8217;s
guide&lt;/a&gt;
to our side, wade in, and see just what it takes to whip a bunch of
RSpec stories into shape for Cucumber.  Specifically, we&amp;#8217;re going to
tackle the party planning web app from Chapter 10 of the book.&lt;/p&gt;


	&lt;p&gt;Renaming the files from &lt;code&gt;.story&lt;/code&gt; to &lt;code&gt;.feature&lt;/code&gt; and sticking them in
a &lt;code&gt;features/&lt;/code&gt; directory is easy, right?  No need to edit the contents
of the file, unless you get weird parser errors&amp;#8212;Cucumber is
strangely unforgiving about really silly things like line breaks in
comments.  The examples for the book didn&amp;#8217;t need any tweaking, but a
couple of tests at work did.  When in doubt, keep deleting lines
(temporarily!) until you find the problem child.&lt;/p&gt;


	&lt;p&gt;Next, it&amp;#8217;s time to free the step definitions from the blocks that
enchain them.  For the party-planning example in the book, we have
&lt;code&gt;steps_for :planning&lt;/code&gt;, &lt;code&gt;:reviewing&lt;/code&gt;, &lt;code&gt;:rsvp&lt;/code&gt;, and &lt;code&gt;:email&lt;/code&gt; blocks.
Here&amp;#8217;s a tiny example.  If this were one of our blocks:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
steps_for :rsvp do
  Then 'I should see &quot;$guest&quot; in the list of $type' do |guest, type|
    want_attending = (type == 'partygoers')
    @party.responses(want_attending).should include(guest)
  end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;...we&amp;#8217;d ditch the first and last lines (&lt;code&gt;steps_for...&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt;)
and put the rest into &lt;code&gt;features/step_definitions/rsvp_steps.rb&lt;/code&gt;).
The other three groups of definitions get a similar treatment.&lt;/p&gt;


	&lt;p&gt;Next, we need to get rid of the Story Runner&amp;#8217;s fuzzy string matchers
and replace them with proper regular expressions.  This only took a
few seconds, even on the large body of tests we have at my day job;
we just used a text editor search-and-replace to change &lt;code&gt;Given '&lt;/code&gt; to
&lt;code&gt;Given /^&lt;/code&gt;, and so on.  (If your text editor is extra-clever, you
can use a regex to, um, write your regex for you.  Somewhere in
there, there&amp;#8217;s a &lt;a href=&quot;http://knowyourmeme.com/memes/48-xzibit-yo-dawg&quot;&gt;Sup
dawg&lt;/a&gt; joke just
aching to get out.)&lt;/p&gt;


	&lt;p&gt;Next, we need to get rid of those dollar-variables inside, and
replace them with good ol&amp;#8217; regex captures.  All of the ones for this
chapter worked with &lt;code&gt;(.*)&lt;/code&gt;&amp;#8212;the catch-all capture.  For a chunk of
tests we converted at work, there were a few places where Cucumber
complained that a test step matched more than one regular
expression.  This kind of thing can happen when you want to match
both of these:&lt;/p&gt;


&lt;pre&gt;
When I frob the quux to 123

When I frob the quux to 123 furlongs
&lt;/pre&gt;

	&lt;p&gt;The na&amp;#239;ve approach won&amp;#8217;t work:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
When /I frob the quux to (.*)/

When /I frob the quux to (.*) (.*)/
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Because &amp;#8220;123 furlongs&amp;#8221; matches both &lt;code&gt;(.*)&lt;/code&gt; and &lt;code&gt;(.*) (.*)&lt;/code&gt;.  Cases
like these call for more specific captures, either requiring numeric
characters, or enclosing quotes, or optional matches, or some other
way to tell them apart&amp;#8212;for now.  The Cucumber team are &lt;a href=&quot;http://rubyforge.org/pipermail/rspec-devel/2009-January/005196.html&quot;&gt;working
on&lt;/a&gt;
a way to resolve some ambiguous matches automatically.  In the
meantime, cleaning up regexes doesn&amp;#8217;t hurt too bad.&lt;/p&gt;


	&lt;p&gt;After the changes we&amp;#8217;ve done so far, the step definitions in
&lt;code&gt;rsvp_steps.rb&lt;/code&gt; would look like this excerpt:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
Then /^I should see &quot;(.*)&quot; in the list of (.*)$/ do |guest, type|
  want_attending = (type == 'partygoers')
  @party.responses(want_attending).should include(guest)
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Next up: the setup and teardown stuff.  Cucumber provides &lt;code&gt;Before&lt;/code&gt;
and &lt;code&gt;After&lt;/code&gt; hooks, but these run for every &lt;code&gt;Scenario&lt;/code&gt; in our code.
Some actions, like starting and stopping a web browser, are slower
than typical setup code and should only be run one time.  For
these cases, Cucumber will run anything you put in
&lt;code&gt;features/support/env.rb&lt;/code&gt; just once&amp;#8212;at launch time.  Since this
file can contain Ruby-style &lt;code&gt;at_exit&lt;/code&gt; handlers, you can also put
global teardown code in this file.&lt;/p&gt;


	&lt;p&gt;For this example, we need just one little tweak to the approach.
The browser object needs to be available inside or test steps,
so we can pass it into our &lt;code&gt;Party&lt;/code&gt; support code.  Cucumber&amp;#8217;s &lt;code&gt;World&lt;/code&gt;
method will do the trick.  Think of it as a &lt;code&gt;Before&lt;/code&gt; hook with
instance methods; if we define a &lt;code&gt;browser&lt;/code&gt; method in a custom
&lt;code&gt;World&lt;/code&gt;, every test step in our suite will have access to
the it.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class PartyWorld
  @@browser = Selenium::SeleniumDriver.new \
    'localhost', 4444, '*firefox', 'http://localhost:3000', 10000
  @@browser.start
  at_exit {@@browser.stop}

  def browser; @@browser end
end

World do
  PartyWorld.new
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;(Note that one test step uses the old &lt;code&gt;@browser&lt;/code&gt; instance
variable inside; it needs to be changed to use the &lt;code&gt;browser&lt;/code&gt; method
instead.)&lt;/p&gt;


	&lt;p&gt;The last holdover from our old RSpec-style stories is the &lt;code&gt;with_steps_for ... run ...&lt;/code&gt;
block that actually starts the tests.  We don&amp;#8217;t need this any more,
since Cucumber comes with its own launcher that scans a directory
for &lt;code&gt;*.feature&lt;/code&gt; files and runs them:&lt;/p&gt;


&lt;pre&gt;
cucumber features
&lt;/pre&gt;

	&lt;p&gt;Don&amp;#8217;t forget to &lt;code&gt;require 'spec/expectations'&lt;/code&gt; somewhere if you&amp;#8217;re
using the fancy RSpec matchers like &lt;code&gt;should_have&lt;/code&gt;.  See &lt;a href=&quot;http://bitbucket.org/undees/idgtr-code/src/tip/story/features/&quot;&gt;the code
listings&lt;/a&gt;
for the finished product.&lt;/p&gt;


	&lt;p&gt;Coming up next: I&amp;#8217;ll explore using the lo-cal Bacon assertion
framework instead of RSpec.  Mmmm, Cucumber and Bacon&amp;#8230;.&lt;/p&gt;</description></item><item><title>iphone gui testing</title><link>http://www.ian.dees.name/tech/iphone-gui-testing.html</link><guid isPermaLink='false'>tech/iphone-gui-testing@http://www.ian.dees.name</guid><dc:subject>tech</dc:subject><dc:subject>tech</dc:subject><dc:creator>undees</dc:creator><dc:date>2009-02-02T06:13:37+00:00</dc:date><description xml:space='preserve'>&lt;p&gt;Ah, the iPhone.  Darling of the geeks.  All these shiny new
applications running on it.  How will we test them all?  What
software test framework is simple enough, elegant enough, trendy
enough to suit the device?&lt;/p&gt;


	&lt;p&gt;Why, &lt;a href=&quot;http://cukes.info&quot;&gt;Cucumber&lt;/a&gt;, of course.&lt;/p&gt;


	&lt;h3&gt;the state of the art&lt;/h3&gt;


	&lt;p&gt;The art of automated testing of iPhone apps is still in its infancy.
Not to say folks haven&amp;#8217;t been busy.  There&amp;#8217;s the &lt;a href=&quot;http://code.google.com/p/google-toolbox-for-mac&quot;&gt;Google Toolbox for
Mac&lt;/a&gt;, which includes
an iPhone test section.  And Dr. Nic has paved the way for
code-level &lt;a href=&quot;http://drnicwilliams.com/2008/07/04/unit-testing-iphone-apps-with-ruby-rbiphonetest&quot;&gt;unit
testing&lt;/a&gt;
of Cocoa classes, albeit on the Mac.&lt;/p&gt;


	&lt;p&gt;Most promisingly, Matt Gallagher has put together the &lt;a href=&quot;http://cocoawithlove.com/2008/11/automated-user-interface-testing-on.html&quot;&gt;three crucial
pieces&lt;/a&gt;
of automated &lt;span class=&quot;caps&quot;&gt;GUI&lt;/span&gt; testing for iPhone apps: identifying pieces of the
UI, simulating a human finger poking at the screen, and finding out
what happened.&lt;/p&gt;


	&lt;p&gt;And in just a few short steps, we&amp;#8217;re going to hook up Matt&amp;#8217;s demo
app to Cucumber, the Ruby-based framework that understands tests in
plain English.  What you&amp;#8217;re about to see is a toy.  It&amp;#8217;s the minimum
amount of glue to get Ruby pointed at Matt&amp;#8217;s code.  Plenty of time
to make it into something for grownups later.&lt;/p&gt;


	&lt;p&gt;First, a brief word on Matt&amp;#8217;s approach is in order.  He basically
&lt;a href=&quot;http://en.wikipedia.org/wiki/Objective-C#Categories&quot;&gt;monkey-patched&lt;/a&gt;
the &lt;code&gt;UIView&lt;/code&gt; class that underlies the iPhone&amp;#8217;s on-screen
gizmos, so that you can interrogate them at runtime: &amp;#8220;What are you?
Where are you?  Do you have any text or gizmos inside you?&amp;#8221;  Next,
he reverse-engineered how to simulate screen taps.  And he tied it
all together with an &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt;-based scripting language that lets you
define simple steps like, &amp;#8220;scroll to the 10th row in the list,&amp;#8221; or,
&amp;#8220;Press the button that says, &amp;#8216;Click me.&amp;#8217;&amp;#8221;&lt;/p&gt;


	&lt;p&gt;For this technique to work on an iPhone app, you have to add a
little piece of custom code to read the test script and spider your
UI.  And you have to bundle the &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; test script itself into your
app&amp;#8212;well, into a special test version of your app.&lt;/p&gt;


	&lt;h3&gt;hooking it up to cucumber&lt;/h3&gt;


	&lt;p&gt;I thought of just building a translator from Cucumber&amp;#8217;s subset of
plain English (affectionately called &amp;#8220;Gherkin&amp;#8221;) into the &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/Property_list&quot;&gt;property list&lt;/a&gt; format,
and then just using that generated code as before.  But I wanted
Cucumber to be actually talking to the iPhone app.&lt;/p&gt;


	&lt;p&gt;Remember, Apple likes iPhone apps to pull data from the rest of the
world, rather than having data pushed into it.  And one of the
simplest, dumbest ways you can make data available for the iPhone is
to use a web server.&lt;/p&gt;


	&lt;p&gt;So this project uses a slight modification of Matt&amp;#8217;s app.  Instead
of reading its instructions all at once at the beginning of the
program, we want to fetch each step one at a time from a web server.
The app runs the step&amp;#8212;pushing a button, or comparing a
caption, or what have you&amp;#8212;and then reports its results by
hitting a &lt;code&gt;/pass&lt;/code&gt; or &lt;code&gt;/fail&lt;/code&gt; URL on the web
server.  (Yes, I know that&amp;#8217;s not what &lt;a href=&quot;http://en.wikipedia.org/wiki/Idempotence&quot;&gt;&lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt;
&lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt;&lt;/a&gt; is for, but until
Apple provides a one-liner for &lt;span class=&quot;caps&quot;&gt;HTTP POST&lt;/span&gt; instead of a &lt;a href=&quot;http://deusty.blogspot.com/2006/11/sending-http-get-and-post-from-cocoa.html&quot;&gt;ten-line
novella&lt;/a&gt;,
&lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; will remain the refuge of scoundrels writing quickie blog
posts.)&lt;/p&gt;


	&lt;p&gt;Another web server listens to requests from Cucumber and&amp;#8230;.  Wait a
sec.  We&amp;#8217;re going to need better names for these than &amp;#8220;the first
server&amp;#8221; and &amp;#8220;the other one.&amp;#8221;  In honor of the &lt;a href=&quot;http://www.thehumorarchives.com/joke/Handegg&quot;&gt;Big Important Handegg
Game&lt;/a&gt; that was going on
during this madcap experiment, we&amp;#8217;ll call them the quarterback and
the coach.  The quarterback talks to the iPhone, and the coach talks
to Cucumber.  The coach signals plays to the quarterback via the
silliest set of hand signals you can think of: the file system (told
you it was a toy).&lt;/p&gt;


	&lt;h3&gt;trying it out&lt;/h3&gt;


	&lt;p&gt;You can actually try out these pieces in isolation, using
&lt;a href=&quot;http://curl.haxx.se&quot;&gt;curl&lt;/a&gt; to pretend to be an iPhone asking for
instructions or an instance of Cucumber issuing them.  But of
course, it&amp;#8217;ll be more fun to put it all together.&lt;/p&gt;


	&lt;p&gt;More detailed instructions and code are available using the
distributed revision control system of
&lt;a href=&quot;http://github.com/undees/yesbut/tree/master/2009-02-01&quot;&gt;your&lt;/a&gt;
&lt;a href=&quot;http://bitbucket.org/undees/yesbut/src/tip/2009-02-01/&quot;&gt;choice&lt;/a&gt;.
Here&amp;#8217;s the short, short version.&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;Apply a patch to Matt&amp;#8217;s project to fetch the list of test
instructions from a web server instead of a disk file.&lt;/li&gt;
		&lt;li&gt;Launch the coach and quarterback web servers.&lt;/li&gt;
		&lt;li&gt;Start the Cucumber test.&lt;/li&gt;
		&lt;li&gt;Kick off the test version of the app.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;You won&amp;#8217;t see the iPhone simulator pop up, but the code is running
and duly reporting its results to the quarterback.&lt;/p&gt;


	&lt;p&gt;Where do we go from here?  Lots of directions.&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;The test script should have an option to kick off the simulator
  app, instead of waiting for you to launch it manually.&lt;/li&gt;
		&lt;li&gt;The Ruby side should expand to do things like string comparisons
  and pass/fail decisions, so that we can move some of that stuff
  out of the iPhone.&lt;/li&gt;
		&lt;li&gt;The cheesy one-liners I added to the app to fetch data
  should be replaced by event-driven network I/O.&lt;/li&gt;
		&lt;li&gt;We should get this thing going on a real iPhone.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;What we&amp;#8217;ve got so far is a just a baby step.  But take it from the
father of a toddler, those can be entertaining.&lt;/p&gt;</description></item><item><title>primitive boots</title><link>http://www.ian.dees.name/tech/primitive-boots.html</link><guid isPermaLink='false'>tech/primitive-boots@http://www.ian.dees.name</guid><dc:subject>tech</dc:subject><dc:subject>tech</dc:subject><dc:creator>undees</dc:creator><dc:date>2008-12-16T23:26:00+00:00</dc:date><description xml:space='preserve'>&lt;p&gt;Do you remember the &lt;a href=&quot;http://www.warrenrobinett.com/rockysboots&quot;&gt;Rocky&amp;#8217;s
Boots&lt;/a&gt; video game from the
eighties?  Of course you do.  While the rest of us were struggling
to survive to the end of the &lt;a href=&quot;http://is.gd/c2KR&quot;&gt;Oregon Trail&lt;/a&gt;, you
were building rudimentary Rube Goldberg devices out of simple &amp;#8220;and&amp;#8221; 
and &amp;#8220;or&amp;#8221; operations to make Rocky the Raccoon kick the right
sequence of little colored squares.&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Primitive_recursive_function&quot;&gt;Primitive recursive&lt;/a&gt; functions in mathematics are kind of like that.  Most simple calculations you can think of &amp;#8212; testing whether or not a number is prime, say &amp;#8121; can be built out of a few really basic functional pieces.&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://picasaweb.google.com/lh/photo/uelBtK30FutgKI9Tujt78g&quot;&gt;&lt;img src=&quot;http://lh3.ggpht.com/_Q9q7vqzAkY4/SUopu9Nd_pI/AAAAAAAAAJE/n2lTdfd9EIA/s288/boots.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;First, you need to be able to represent natural numbers.  You can do
that with a zero function, a successor function, and a glue function
to stick &amp;#8216;em together.  Need to represent the number two?  Glue a
successor to another successor to a zero.&lt;/p&gt;


	&lt;p&gt;Next, you need a &lt;a href=&quot;http://www.urbandictionary.com/define.php?term=Picker%20Flicker&quot;&gt;picker and a
flicker&lt;/a&gt;.
The picker chooses a single item out of a list, and the flicker
takes two functions and &amp;#8220;flicks&amp;#8221; the calculation to one of them,
depending solely on whether a single number is zero or nonzero.&lt;/p&gt;


	&lt;p&gt;The accepted names for these functions, respectively, are zero (Z),
successor (S), composition (written as a little circle; I&amp;#8217;ll use a
lower case o), projection (P), and primitive recursion (PR).&lt;/p&gt;


	&lt;p&gt;Projection is typically written with a superscript representing the
number of items on the list, and a subscript representing which item
to choose.  So P/3/2 is a function that takes three numbers and hands
you the second.&lt;/p&gt;


	&lt;p&gt;The canonical example they give you in grad school is defining
addition.  You add two numbers together by adding 1 to one of them,
over and over again.  Doing something over and over requires the
flicker; that is, primitive recursion.  PR asks us for two things:&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;When the first number is zero, PR hands us just the other number
says, &amp;#8220;What do you want to do with this?&amp;#8221;  Since anything plus
zero equals itself, we just hand the number back.  We&amp;#8217;re given
one number and we give it right back, so this is P/1/1.&lt;/li&gt;
		&lt;li&gt;When the first number is something greater than zero, PR gives us
a three-item list: the first number&amp;#8217;s &lt;em&gt;predecessor&lt;/em&gt;, the running
total so far, and the second number.  How do we get a sum from
that?  We take the running total and add one to it.  Picking the
middle item from a list is P/3/2, adding one is S, and when we
glue &amp;#8216;em up, we get [S o P/3/2].&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;Putting it all together, we have Add = PR[P/1/1, [S o P/3/2]].&lt;/p&gt;


	&lt;p&gt;If we had some kind of machine that understood all these pieces, we
could feed it this definition of Add, give it two numbers, and watch
as the correct sum came magically out the other end.  Some would
read this paragraph, scoff, and say, &amp;#8220;Big deal.  Even Windows Vista
can add two numbers together.&amp;#8221;  But you&amp;#8217;d never say that, no.  You
like knowing that you could build addition with your bare hands if
an emergency called for it.&lt;/p&gt;


So here&amp;#8217;s an Lisp-y implementation in &lt;a href=&quot;http://clojure.org&quot;&gt;Clojure&lt;/a&gt;
that you can play with.  For zero and the successor, Clojure has the
&lt;code&gt;constantly&lt;/code&gt; and &lt;code&gt;inc&lt;/code&gt; built-in functions,
respectively:

&lt;pre&gt;&lt;code&gt;
(def z (constantly 0))

(def s inc)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Composition &amp;#8212; the glue function &amp;#8212; is easy when we&amp;#8217;re
just sticking two single-value functions together:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
(defn o [f g]
  (fn [x] (f (g x))))
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;This code just builds a new function &lt;code&gt;f o g&lt;/code&gt; that takes a
number &lt;code&gt;x&lt;/code&gt;, runs it through a function &lt;code&gt;g&lt;/code&gt;,
and hands the result to another function, &lt;code&gt;f&lt;/code&gt;.&lt;/p&gt;


Real life is a little more complicated, though.  &lt;code&gt;g&lt;/code&gt; may
take more than one parameter, so we may need a bunch of
&lt;code&gt;x&lt;/code&gt;&amp;#8217;s.  Similarly, &lt;code&gt;f&lt;/code&gt; may take more than one
parameter, so we may need not just one &lt;code&gt;g&lt;/code&gt;, but a slew of
them.  Calling a function with an unknown number of arguments is a
job for &lt;code&gt;apply&lt;/code&gt;, that cornerstone of Lisp programming:

&lt;pre&gt;&lt;code&gt;
(defn o [f &amp;#38; gs]
  (fn [&amp;#38; xs]
    (apply f
           (map
             (fn [g] (apply g xs))
             gs))))
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now for the picker and the flicker.  The picker, remember, just
returns a single list item.  Clojure has a handy &lt;code&gt;nth&lt;/code&gt;
function for looking inside lists.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
(defn p [_ subscript] (fn [&amp;#38; xs] (nth xs (dec subscript))))
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;You&amp;#8217;ll notice that &lt;code&gt;p&lt;/code&gt; ignores its first parameter;
that&amp;#8217;s just the list length, and we don&amp;#8217;t need it for this exercise.
Also, lists start at the zeroth item in Clojure, rather than the
first&amp;#8212;so we need to subtract one from our index.&lt;/p&gt;


	&lt;p&gt;That just leaves the flicker, primitive recursion.  This definition
is the most complicated one of the batch, but it&amp;#8217;s still fairly
straightforward.  By convention, we take a function &lt;code&gt;g&lt;/code&gt;
for the zero case and &lt;code&gt;h&lt;/code&gt; for the nonzero case.  We then
build a new function &lt;code&gt;f&lt;/code&gt; that decides whether to call g
or h based on the first value passed to it.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
(defn p-r [g h]
  (fn f [x y]
    (if (zero? x)
        (g y)
        (let [prev (dec x)]
          (h prev (f prev y) y)))))
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;This limited PR won&amp;#8217;t be able to define anything other than a
two-argument function, but that&amp;#8217;s enough for us to build and use
addition:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
(def add (p-r (p 1 1) (o s (p 3 2))))

(add 4 5) ;; =&amp;gt; 9
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Aside from making addition slower and harder to read, what has this
bought us?  Well, it&amp;#8217;s given me peace of mind, since I can test my
&lt;a href=&quot;http://www.ian.dees.name/life/fuzzy-grad-student&quot;&gt;grad school&lt;/a&gt; homework answers after
writing them.  It was also a great excuse to learn the basics of
Clojure and &lt;a href=&quot;http://common-lisp.net/project/slime&quot;&gt;&lt;span class=&quot;caps&quot;&gt;SLIME&lt;/span&gt;&lt;/a&gt;.  But
mostly, it was a chance to recapture that thrill of lining up all
the building-block logic circuits to boot all the blue diamonds and
make Rocky dance.&lt;/p&gt;


	&lt;p&gt;So have a peek at the &lt;a href=&quot;http://bitbucket.org/undees/yesbut/src/tip/2008-12-05/primitive_recursive.clj&quot;&gt;latest
version&lt;/a&gt;
of the code.  It does a bit more than what you see here, like
checking the lengths of argument lists, and handling primitive
recursion for any number of parameters.  Happy kickin&amp;#8217;!&lt;/p&gt;</description></item><item><title>the road to quineville</title><link>http://www.ian.dees.name/tech/road-to-quineville.html</link><guid isPermaLink='false'>tech/road-to-quineville@http://www.ian.dees.name</guid><dc:subject>tech</dc:subject><dc:subject>tech</dc:subject><dc:creator>undees</dc:creator><dc:date>2008-12-16T22:38:34+00:00</dc:date><description xml:space='preserve'>&lt;p&gt;A quine is a program that prints its own source code as output,
without using any dirty tricks like &amp;#8220;go find the file this source code
lives in, and spit out the contents.&amp;#8221;&lt;/p&gt;


	&lt;p&gt;Most programmers cut their baby teeth on neat tricks like quines.
Others spend their undergrad years using electrons as the fundamental
unit of computation, and don&amp;#8217;t get to programming-language tomfoolery
until much further on.&lt;/p&gt;


	&lt;p&gt;So, better late than never.&lt;/p&gt;


	&lt;p&gt;To see why writing a quine takes a bit of twisty thinking, consider
this Ruby program:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
puts
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;It just prints a blank line.  How about this one?&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
puts 'puts'
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;That one prints the following:&lt;/p&gt;


&lt;pre&gt;
puts
&lt;/pre&gt;

	&lt;p&gt;Okay, how about this?&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
puts 'puts &quot;puts&quot;'
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;That results in:&lt;/p&gt;


&lt;pre&gt;
puts &quot;puts&quot; 
&lt;/pre&gt;

	&lt;p&gt;No matter how many &lt;code&gt;puts&lt;/code&gt;-es we have in there, we always
need one more than we have.  We need a way to hide a lil&amp;#8217; copy of
the program inside itself.  Let&amp;#8217;s try to trick ourselves by
scrambling it!&lt;/p&gt;


	&lt;p&gt;What if we could set up some variable &lt;code&gt;s&lt;/code&gt; that contained
a scrambled version of the program&amp;#8217;s source?&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
s = &quot;[scrambled source code]&quot; 
puts s.unscramble
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;But to scramble the program, we&amp;#8217;d have to know the whole text in
advance&amp;#8212;including the scrambled part!  Instead, let&amp;#8217;s imagine
scrambling just a skeleton of the program, with the &lt;code&gt;%s&lt;/code&gt;
marker standing in for the scrambled part.&lt;/p&gt;


	&lt;p&gt;Here&amp;#8217;s what the skeleton looks like:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
s = &quot;%s&quot; 
puts s.unscramble % s
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now &lt;em&gt;that&lt;/em&gt; we can scramble.  Don&amp;#8217;t worry about how yet.  But once
we&amp;#8217;ve done so, the following program will be a quine:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
s = &quot;[scrambled skeleton]&quot; 
puts s.unscramble % s
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Almost.  We still have to write the &lt;code&gt;unscramble&lt;/code&gt; function
and make sure the program has access to the definition.&lt;/p&gt;


	&lt;p&gt;Rather than manually scrambling the skeleton and pasting it into the
program, I&amp;#8217;ve built a &amp;#8220;Quinerizer&amp;#8221; class that does this for me.
That way, it&amp;#8217;s easy to change scramble / unscramble methods on a
whim.  In the spirit of swatting a fly with a Buick, Quinerizer has
unit tests as well; feel free to peek at &lt;a href=&quot;http://bitbucket.org/undees/yesbut/src/tip/2008-11-29/quinerizer_spec.rb&quot;&gt;that
code&lt;/a&gt;
on your own.&lt;/p&gt;


	&lt;p&gt;Here&amp;#8217;s the auto-generated quine using Base64 as a scrambling mechanism:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
require 'base64'

class String
  def unscramble
    Base64.decode64 self
  end
end

s = &quot;cmVxdWlyZSAnYmFzZTY0JwoKY2xhc3MgU3RyaW5nCiAgZGVmIHVuc2NyYW1i
bGUKICAgIEJhc2U2NC5kZWNvZGU2NCBzZWxmCiAgZW5kCmVuZAoKcyA9ICIl
cyIKCnB1dHMgcy51bnNjcmFtYmxlLnN1YigiJXMiLCBzKQo=
&quot; 

puts s.unscramble.sub(&quot;%s&quot;, s)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Go ahead, try it!&lt;/p&gt;


	&lt;p&gt;This qualifies as a quine, but we can certainly be more
space-efficient than Base64.  Imagine using regular string quoting and
printing (e.g., via String#inspect) instead of a scrambling and
unscrambling routine.  If we&amp;#8217;re very careful with our percent signs
and quote marks, we can condense the quine down to this:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
s = &quot;s = %s; puts s %% s.inspect&quot;; puts s % s.inspect
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;This approach reaches its full logical extreme in Ryan Davis&amp;#8217;s &lt;a href=&quot;http://blog.zenspider.com/2006/09/ruby-quine--slightly--smaller.html&quot;&gt;curt
Ruby quine&lt;/a&gt;:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
_=&quot;_=%p;puts _%%_&quot;;puts _%_
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Hard to do much better than that.&lt;/p&gt;</description></item><item><title>fuzzy grad student</title><link>http://www.ian.dees.name/life/fuzzy-grad-student.html</link><guid isPermaLink='false'>life/fuzzy-grad-student@http://www.ian.dees.name</guid><dc:subject>life</dc:subject><dc:subject>life</dc:subject><dc:creator>undees</dc:creator><dc:date>2008-12-16T20:26:36+00:00</dc:date><description xml:space='preserve'>&lt;p&gt;With an intelligently rambunctious second-grader, a trouble-seeking
one-year-old, a full-time job, a book to promote, and another book
to write, I&amp;#8217;d have to be stupid to take on anything else, right?&lt;/p&gt;


	&lt;p&gt;Heh.&lt;/p&gt;


	&lt;p&gt;Now I&amp;#8217;m a fuzzy grad student, too.  (The terminology comes from my
old undergrad days, when we&amp;#8217;d universally refer to all the masters /
doctoral crowd, regardless of facial hair situation or even gender,
as &amp;#8220;fuzzy grad students.&amp;#8221;)  How did &lt;em&gt;this&lt;/em&gt; happen?&lt;/p&gt;


	&lt;p&gt;Two things kind of led up to this foolishness.  The first was
Ackermann&amp;#8217;s function, a programming rite of passage I&amp;#8217;d decided to
take a particularly strange whack at.  It&amp;#8217;s easy enough to do in
Ruby, my favorite programming language, but&amp;#8212;and here&amp;#8217;s the
teeth-gritting part&amp;#8212;I insisted on doing it in a certain strange
way, implementing
&lt;a href=&quot;http://en.wikipedia.org/wiki/Pattern_matching&quot;&gt;language&lt;/a&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/Lazy_evaluation&quot;&gt;features&lt;/a&gt; Ruby was
never meant to have.&lt;/p&gt;


	&lt;p&gt;Tilting at this windmill led to all sorts of mental bookkeeping
about a single piece of code meaning different things in different
contexts.  &amp;#8220;I&amp;#8217;ve heard this stuff before,&amp;#8221; says I, &amp;#8220;from
professional computer scientists.  Maybe I should talk to some of
those.&amp;#8221;&lt;/p&gt;


	&lt;p&gt;The other thing that led me down this road was that a bunch of my
co-workers got their &lt;a href=&quot;http://www.pdx.edu/omse&quot;&gt;&lt;span class=&quot;caps&quot;&gt;OMSE&lt;/span&gt;&lt;/a&gt; (Oregon Master
of Software Engineering) certificates, a kind of professional-track
alternative to a traditional comp-sci master&amp;#8217;s degree.  They were
beaming, of course, but also spoke coherently and specifically about
what they got from the program.&lt;/p&gt;


	&lt;p&gt;I don&amp;#8217;t think the &lt;span class=&quot;caps&quot;&gt;OMSE&lt;/span&gt; is for me.  There seems to be a lot of focus
on doing anything &lt;em&gt;but&lt;/em&gt; writing great programs.  For example, there
are a lot of courses in engineering budgets, time estimates, project
management, bug tracking, and so on.  All worthwhile endeavors, to
be sure.  But the gaps in my knowledge are in the egg-headed arena
of
&lt;a href=&quot;http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-35.html#%_sec_5.5.6&quot;&gt;context&lt;/a&gt;
and meaning.&lt;/p&gt;


	&lt;p&gt;So I&amp;#8217;m dipping my toes into the water and taking a few traditional
master&amp;#8217;s-level classes at Portland State, starting right smack dab
in the middle of the gaping void with the &lt;a href=&quot;http://www.cs.pdx.edu/user/coursedetails/69&quot;&gt;Theory of
Computation&lt;/a&gt;.  The ink
dried on the last of our final exams last week.  I&amp;#8217;ll let you know
how it went.&lt;/p&gt;


	&lt;p&gt;In the meantime, a bunch of my half-assed experiments will probably
show up from time to time on this blog.  They will probably share
the dual fault of being inscrutable to non-programmers and absurdly
simple to experienced programmers.  C&amp;#8217;est la vie&amp;#8230;.&lt;/p&gt;</description></item><item><title>one!</title><link>http://www.ian.dees.name/life/one.html</link><guid isPermaLink='false'>life/one@http://www.ian.dees.name</guid><dc:subject>life</dc:subject><dc:subject>life</dc:subject><dc:creator>undees</dc:creator><dc:date>2008-12-02T09:59:58+00:00</dc:date><description xml:space='preserve'>&lt;p&gt;&lt;a href=&quot;http://picasaweb.google.com/lh/photo/k_6H7kWIemdEaNnAN0ykyQ&quot;&gt;&lt;img src=&quot;http://lh3.ggpht.com/_Q9q7vqzAkY4/STUL0-yqsiI/AAAAAAAAAII/YKJI5Ro8QtE/s288/11-08-08_1701.jpg&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;Hard to believe it&amp;#8217;s been &lt;a href=&quot;http://www.ian.dees.name/born&quot;&gt;a whole year&lt;/a&gt;. Back then, all she could do
was eat, sleep, and poop. Now, she can walk. And talk! She knows I&amp;#8217;m
&amp;#8220;Daddy&amp;#8221; (actually, sometimes anything bigger than her is &amp;#8220;Dajjy&amp;#8221;),
Mommy is &amp;#8220;Baba,&amp;#8221; sister is &amp;#8220;Adeeeeee,&amp;#8221; and a cat or anything else
you have to be gentle with is &amp;#8220;Sof&amp;#8217;.&amp;#8221;&lt;/p&gt;


	&lt;p&gt;Some parents teach their children a simplified sign language. In our
case, Robin taught &lt;em&gt;us&lt;/em&gt; her own signs. A tug of the ear means, &amp;#8220;I&amp;#8217;m
hungry.&amp;#8221;  Slapping the knees simultaneously means, &amp;#8220;Yes, very
amusing.&amp;#8221;  Slapping the knees alternately means, &amp;#8220;You&amp;#8217;ve got about
three seconds to pick me up or I start shrieking.&amp;#8221; And when she
grabs her bare belly at bath time, we&amp;#8217;re pretty sure she&amp;#8217;s saying,
&amp;#8220;I appear not to be wearing a shirt any more. I find this hilarious
for some reason.&amp;#8221;&lt;/p&gt;


	&lt;p&gt;We did manage to get a couple of our signs to sink in with her. The
standard stuff you&amp;#8217;d expect: point at the mouth for &amp;#8220;Eat,&amp;#8221; touch the
hands together for &amp;#8220;More,&amp;#8221; and reach out one-handed to say, &amp;#8220;Give me
that.&amp;#8221; But my favorite sign that she picked up from us is this: when
we do our best Homer Simpson and say, &lt;a href=&quot;http://www.tv.com/the-simpsons/homerpalooza/episode/1437/trivia.html&quot;&gt;Don&amp;#8217;t stop a-rockin&amp;#8217;!&lt;/a&gt; she
grins wildly and shakes her head from side to side.&lt;/p&gt;</description></item><item><title>i think it translates as...</title><link>http://www.ian.dees.name/life/i-think-it-translates-as.html</link><guid isPermaLink='false'>life/i-think-it-translates-as@http://www.ian.dees.name</guid><dc:subject>life</dc:subject><dc:subject>life</dc:subject><dc:creator>undees</dc:creator><dc:date>2008-12-02T08:57:35+00:00</dc:date><description xml:space='preserve'>&lt;p&gt;&lt;a href=&quot;http://picasaweb.google.com/lh/photo/UMKF1LncEiU_mBZI5sep2g&quot;&gt;&lt;img src=&quot;http://lh3.ggpht.com/_Q9q7vqzAkY4/STULzIAhnWI/AAAAAAAAAH4/yXACr-btZPA/s288/DSCN0798.JPG&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;Another months-overdue post. Catching up on my posting backlog,
though, which is is more than I can say for nearly every other
sector of my life. This one&amp;#8217;s about my summer vacation.&lt;/p&gt;


	&lt;p&gt;Well, I say vacation. But it wasn&amp;#8217;t quite that, since my family came
along, too. Har, har.&lt;/p&gt;


	&lt;p&gt;We&amp;#8217;d been trying to find something to please everybody. Big sister
wanted a pool. Little sister wanted an endless supply of
booboo. Mommy wanted a spa. And Daddy wanted something bucolic and
Northwest-y, so that (har, har) I could hole up and write&amp;#8212;my idea
of a break from writing stuff I have to is writing stuff I want to.&lt;/p&gt;


	&lt;p&gt;So we found Kah-Nee-Ta, a mysteriously-named casino slash resort on
reservation land. Perfect! A little something for everyone,
including my dad, who was in town from Texas.&lt;/p&gt;


	&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;KNT&lt;/span&gt;, as I&amp;#8217;ll refer to it from now on, is out in the high desert not
too far from Bend, a few hours from Portland. We stopped at the
Timberline Lodge atop Mount Hood (thank you, &lt;span class=&quot;caps&quot;&gt;FDR&lt;/span&gt;, for building it!)
for lunch and enjoyed the sight of snow-starved skiers and boarders
lugging their equipment up to &amp;#8220;enjoy&amp;#8221; a whole ten square yards of
grey slush. Poor things. Winter will be here soon, dears.&lt;/p&gt;


	&lt;p&gt;Back on the road with the kids uncharacteristically and mercifully
asleep, we wound down through the mountains and into the desert. I&amp;#8217;d
never seen that kind of terrain at such a high elevation. It&amp;#8217;s a
whole different ecosystem. At least the resort was easy to spot,
sticking out of the desert like a slot machine in church.&lt;/p&gt;


	&lt;p&gt;We checked in as quickly as we could, since the pixie was itching to
get to the pool. I took a moment to take in the paradox of a cedar
log burning white-hot in the fireplace of a crisply air-conditioned
lobby in the middle of the blasting heat of the desert. Oh
well. Smelled nice.&lt;/p&gt;


	&lt;p&gt;Swim, road leftovers, talk, sleep. Up, breakfast, activities.&lt;/p&gt;


	&lt;p&gt;Today was horseback-riding day. The plan was to put the pixie on the
tame, amble-around-the parking-lot ride. She wanted me to ride, too,
so they put me on this poor pony that&amp;#8217;s used to having kids on
him. Sorry, fella. At least it was a short ride.&lt;/p&gt;


	&lt;p&gt;We also spent ages at the water park. Astoundingly, this was Lynn&amp;#8217;s
first trip ever to one. (I keep forgetting that there are parts of
the country that aren&amp;#8217;t totally saturated with the things.) Anyway,
little one enjoyed splashing in the baby pool, while her big sister
delighted in forcibly dunking her long-suffering supervisor.&lt;/p&gt;


	&lt;p&gt;The dinner options were singularly uninspiring. The buffet was
literally a trough of food. Yes, trough. The expensive restaurant
had exactly the same menu as the cheap one, but with much higher
numbers after the items. The family gamely went for takeout, while I
stormed back to the room and picked at what was left of the road
food that hadn&amp;#8217;t rotted yet.&lt;/p&gt;


	&lt;p&gt;You have to f&amp;#8230; up pretty badly to come up with menu items so
unappealing that even I can&amp;#8217;t eat them, but &lt;span class=&quot;caps&quot;&gt;KNT&lt;/span&gt; managed it that
night. The greasy sauces and wilted salads that the family
good-naturedly styrofoamed back to the room were worse than nothing.
Things were rapidly approaching the &lt;a href=&quot;http://findarticles.com/p/articles/mi_qn4158/is_20060617/ai_n16495253/pg_4&quot;&gt;three meals away from
revolution&lt;/a&gt;
stage: here we were two meals in, and I was ready to overthrow the
whole vacation idea, toss everyone in the car, and drive back to
Portland that night. To my embarrassment, I caught myself thinking
really uncharitable thoughts about my fellow man, in particular the
folks who seemed to be filing through the lobby in happy ignorance
of the ripoff ride we were all being taken on. &amp;#8220;How can you smile
when you&amp;#8217;re paying this kind of money to be treated like this?!?&amp;#8221; I
wanted to shout.&lt;/p&gt;


	&lt;p&gt;It&amp;#8217;s worth pointing out that &lt;span class=&quot;caps&quot;&gt;KNT&lt;/span&gt; doesn&amp;#8217;t have to compete on price or
quality, since they&amp;#8217;re the only game for miles around when it comes
to food. Would it kill &amp;#8216;em to have a grocery store next door and a
kitchenette somewhere near the rooms? The only alternatives are
Bend, which is half an hour away, or going back home, the option I
almost got away with.&lt;/p&gt;


	&lt;p&gt;But Lynn, the no-bullshit soul that she is, talked me back down with
the expert technique of a hostage negotiator. (See, folks, this is why
it&amp;#8217;s crucial to choose a spouse with the right skill set.) Somehow,
she got me through the night without a coup, and without my needing
to eat the bedsheets.&lt;/p&gt;


	&lt;p&gt;Good thing, too, because things suddenly started looking
up. Beginning with breakfast, the food quality started improving
steadily. And the activities drifted away from the crowded,
enforced-fun style, to the more relaxed, self-reliant feel. For
instance, we took a much-needed cooling kayak trip down the Warm
Springs River. My dad, easily the most experienced among us, was the
first one tossed overboard. Hee hee! The pixie squealed as we
blasted through the rapids, bounced off rocks, and generally ran
circles around the other boats.&lt;/p&gt;


	&lt;p&gt;That night, we discovered that the poolside lounge had food that was
orders of magnitude better than elsewhere, and they didn&amp;#8217;t (ahem)
soak us quite so much on the prices. So we got to eat at a relaxed
pace, let the pixie swim safely on into the evening, and then just
hop a few steps to the room when we were tired. Nice!&lt;/p&gt;


	&lt;p&gt;And that&amp;#8217;s about all there is to tell. None of us set foot in the
casino the whole time there; the only thing we gambled with was our
sanity.&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://picasaweb.google.com/lh/photo/i1wnw0lV2IKRMch5vISElA&quot;&gt;&lt;img src=&quot;http://lh6.ggpht.com/_Q9q7vqzAkY4/STUL0cQH45I/AAAAAAAAAIA/HZaNwXlXFRk/s288/DSCN0857.JPG&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description></item></channel>
</rss>
