nkuitse's Journal http://use.perl.org/~nkuitse/journal/ nkuitse's use Perl Journal en-us use Perl; is Copyright 1998-2006, Chris Nandor. Stories, comments, journals, and other submissions posted on use Perl; are Copyright their respective owners. 2012-01-25T02:28:38+00:00 pudge pudge@perl.org Technology hourly 1 1970-01-01T00:00+00:00 nkuitse's Journal http://use.perl.org/images/topics/useperl.gif http://use.perl.org/~nkuitse/journal/ xor virgin no more http://use.perl.org/~nkuitse/journal/22335?from=rss <p>There's a rosy glow in my cheeks as I write this, for today I am an xor virgin no more.</p><p>That's right; I've just used Perl's <code>xor</code> operator for the first time, and it was a thrill!</p><p><b>The story of <code>hoy</code> </b></p><p><code>hoy</code> (<b>h</b>ack <b>o</b>n <b>y</b>aml) is a script I wrote that lets me manipulate YAML documents from the command line. I can do things like create hashes and arrays:</p><blockquote><div><p> <tt>$ hoy array &lt;/dev/null<br>--- #YAML:1.0 []</tt></p></div> </blockquote><blockquote><div><p> <tt>$ echo -e "name Yolanda P. Ipswich\nage 3" | hoy hash<br>--- #YAML:1.0<br>age: 3<br>name: Yolanda P. Ipswich</tt></p></div> </blockquote><p>Fetch values from a YAML hash:</p><blockquote><div><p> <tt>$ hoy get -p name -i ulysses.yaml<br>Ulysses K. Fishwick</tt></p></div> </blockquote><p>...and so on. Each action is specified as a subcommand: <code>hoy <i>array</i><nobr> <wbr></nobr>...</code>, <code>hoy <i>foreach</i><nobr> <wbr></nobr>...</code>, etc.</p><p><code>hoy</code> is very handy for what I do, and I love to say <code>hoy</code>. (hoy! hoy! hoy!)</p><p><b>The deed itself</b></p><p>While making a few changes in <code>hoy</code> today, I realized that after reading options from the command line, subcommands that don't take any non-option arguments were ignoring extra, unused arguments. That's not good, so I added a hash <code>%takes_arguments</code>:</p><blockquote><div><p> <tt>my %takes_arguments = (<br>&nbsp; &nbsp; 'foreach' =&gt; 1,<br>);</tt></p></div> </blockquote><p>Then I added some code right after a call to <code>GetOptions(...)</code> that checks for argument "overflow":</p><blockquote><div><p> <tt>exit usage()<br>&nbsp; &nbsp; if $takes_arguments{$cmd} and not scalar(@ARGV);</tt></p></div> </blockquote><p>Then I realized I might as well check for argument "underflow" at the same time, and that's when it happened: the <code>xor</code> revelation <i>(*blush*)</i>:</p><blockquote><div><p> <tt>exit usage()<br>&nbsp; &nbsp; if $takes_arguments{$cmd} xor scalar(@ARGV);</tt></p></div> </blockquote><p> <b>Postscript</b></p><p>It took me a while to realize I should use <code>xor</code>; I first changed it to this:</p><blockquote><div><p> <tt>exit usage()<br>&nbsp; &nbsp; if ($takes_arguments{$cmd} != 0) eq (scalar(@ARGV) != 0);</tt></p></div> </blockquote><p>Only then did I realize I was on the cusp of something new and amazing. And now, things will never be the same...</p> nkuitse 2004-12-16T18:52:06+00:00 journal Pleasantly surprised http://use.perl.org/~nkuitse/journal/20604?from=rss <p>Here I am catching up on reading use.perl.org journals having just gotten broadband access once again after 3+ weeks without, when I run across <a href="http://use.perl.org/~Ovid/journal/20452">this</a>. <b>Hmm,</b> I think, <b>why does that sound familiar?</b></p><p>Oh, <a href="http://search.cpan.org/~nkuitse/Hash-AsObject-0.05/lib/Hash/AsObject.pm"> <i>now I remember!</i> </a><nobr> <wbr></nobr><code>:-)</code> It sure is nice when you stumble upon kind words about your own code!</p> nkuitse 2004-08-27T22:10:08+00:00 journal Coding frenzy http://use.perl.org/~nkuitse/journal/18956?from=rss <p>Lately I've really been coding to beat the band. Mostly command-line utilities written in Perl, plus a shell script here and there.</p><p>For example:</p><ul> <li> <b>pprom</b> - write and use portable shell prompts (<a href="http://sourceforge.net/projects/pprom/">coming soon</a>)</li><li> <b>mac2unix</b> - convert line endings in a file <i>or</i> filter stdin</li><li> <b>aftermath</b> - run a command and show what files are changed, added, or deleted</li><li> <b>hoy</b> - Hack On Yaml from the command line</li><li> <tt>ok</tt> and <tt>is</tt> - shell functions for testing shell scripts</li><li> <b>cvsmigrate</b> - munge CVS files in sandbox to point to a different repository</li><li> <b>manpdf</b> - view man pages as PDF (Mac OS X only at this point, but that should be easy to remedy)</li></ul><p><b>aftermath</b> will come in handy when I want to quickly see which files are being changed, added, or removed by my project Makefiles. For example, the output to the command <tt>aftermath --command 'rm foo; mkdir bar/baz'</tt> might look like this:</p><blockquote><div><p> <tt>A bar/baz<br>D foo</tt></p></div> </blockquote><p>Plus I've already started using it with <tt>ok</tt> and <tt>is</tt> to test shell scripts:</p><blockquote><div><p> <tt>--------------------- t/test1.sh ---------------------<br>#!/bin/sh<br>is $(aftermath 'myscript --foo') $(cat test1.foo) foo<br>is $(aftermath 'myscript --bar') $(cat test1.bar) bar<br>is $(aftermath 'myscript --baz') $(cat test1.baz) baz<br>----------------------- output -----------------------<br>ok 1 - foo<br>ok 2 - bar<br>ok 3 - baz</tt></p></div> </blockquote><p>It turned out to be surprisingly easy to write - the key was to get the right incantation of <tt>diff</tt>.</p><p>This recent flurry of coding is obviously connected to the fact that my girlfriend is out of the country for seven weeks, and I don't have much of anything better to do.</p><p>My only worry is, how much longer can I keep going at this rate?</p><p>(My only <i>other</i> worry is, how long can I go without washing the dishes?)<nobr> <wbr></nobr><tt>:-)</tt></p> nkuitse 2004-05-26T20:46:59+00:00 journal Debugging *hurts* http://use.perl.org/~nkuitse/journal/18552?from=rss <p>So my new distribution, <a href="http://search.cpan.org/dist/Time-AutoRes/">Time-AutoRes</a>, just failed a cpansmoke test:</p><blockquote><div><p> <code>Can't locate object method "export_to_level" via package "Time::HiRes" at<nobr> <wbr></nobr>/root/.cpanplus/5.8.0/build/Time-AutoRes-0.02/blib/lib/Time/AutoRes.pm line 24.</code></p></div> </blockquote><p>The current version of Time::HiRes inherits this method from Exporter, so it would seem that I just need to change <code>use Time::HiRes</code> to <code>use Time::HiRes m.n</code> where <i>m.n</i> is the earliest version in which Time::HiRes inherited from Exporter.</p><p>Unfortunately, Time::HiRes has apparently <i>always</i> inherited from Exporter. And upon checking the test file in question (note to self: always a good first step), I see that the failing test relies on Time::HiRes <b>not</b> being found -- it uses Test::Without::Module to mimic a situation in which Time::HiRes is not installed. (That's the whole purpose of Time::AutoRes -- provide access to Time::HiRes::sleep et al. when Time::HiRes is available, and fall back to CORE::sleep et al. when it's not.)</p><p>So is the bug in Test::Without::Module, Time::AutoRes, Time::HiRes, or what? I'm confused!</p><p>Here's the relevant code from Time::AutoRes:</p><blockquote><div><p> <tt>package Time::AutoRes;<br> &nbsp; <br>use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $use_hires);<br> &nbsp; <br>$VERSION = 0.02;<br> &nbsp; <br>@ISA = qw(Exporter);<br>require Exporter;<br> &nbsp; <br>BEGIN {<br>&nbsp; &nbsp; eval 'require Time::HiRes';<br>&nbsp; &nbsp; $use_hires = not $@;<br>&nbsp; &nbsp; if ($use_hires) {<br>&nbsp; &nbsp; &nbsp; &nbsp; @EXPORT&nbsp; &nbsp; = @Time::HiRes::EXPORT;<br>&nbsp; &nbsp; &nbsp; &nbsp; @EXPORT_OK = @Time::HiRes::EXPORT_OK;<br>&nbsp; &nbsp; } else {<br>&nbsp; &nbsp; &nbsp; &nbsp; @EXPORT&nbsp; &nbsp; = qw();<br>&nbsp; &nbsp; &nbsp; &nbsp; @EXPORT_OK = qw(sleep alarm usleep ualarm time);<br>&nbsp; &nbsp; }<br>}<br> &nbsp; <br>sub import {<br>&nbsp; &nbsp; if ($use_hires) {<br>&nbsp; &nbsp; &nbsp; &nbsp; Time::HiRes-&gt;export_to_level(0, @Time::HiRes::EXPORT_OK);<br>&nbsp; &nbsp; &nbsp; &nbsp; Time::HiRes-&gt;export_to_level(1, @_);<br>&nbsp; &nbsp; } else {<br>&nbsp; &nbsp; &nbsp; &nbsp;<nobr> <wbr></nobr>...<br>&nbsp; &nbsp; }<br>&nbsp; &nbsp;<nobr> <wbr></nobr>...<br>}</tt></p></div> </blockquote><p>How in the world do I approach fixing this when the test passes on my system (Perl 5.6.0 on Mac OS X)? Levels within levels... My brain hurts!</p> nkuitse 2004-04-29T19:01:21+00:00 journal lof (don't laugh!) http://use.perl.org/~nkuitse/journal/18291?from=rss <p>The C program <a href="http://use.perl.org/~nkuitse/journal/18267">I wrote about the other day</a> has been released: <a href="http://www.nkuitse.com/sw/dist/lof-1.01.tar.gz">source tarball</a> and <a href="http://www.nkuitse.com/sw/dist/lof-1.01-README.txt">README</a>. It's called <b>lof</b> and it's dead simple to use. Probably not of much use to anyone else but it scratched an itch of mine.</p><p>XP to-do list: <b>Release early?</b> <i>Check.</i> <b>Release often?</b> <i>We'll see...</i></p> nkuitse 2004-04-12T02:12:12+00:00 journal C smells down in the cellar http://use.perl.org/~nkuitse/journal/18267?from=rss <p>(As in, <b>C smells musty and familiar</b>, like a basement full of old books long forgotten and now rediscovered.)</p><p>So I'm writing a simple C program to spit out the byte offsets of the lines in a file (or stdin). I'd forgotten just how much I like coding close to the machine. Well, closer than Perl anyhow. Pointers! Ah, how I love them...</p><p>Though I discovered (as expected) that my C is rusty, I was happy to find that my experience with Perl helps my C: I feel I'm coding smarter than I did before. (I found this to be true when I started shell scripting, too.)</p><p>I do feel the lack of namespaces, however. (And no, although the OOP principles I learned from C++ were helpful, there's no love there like what I feel for Perl or C.)</p><p>Hmm... what's next: back to M68K assembly language? I have fond memories but would sorely miss TMON, the lovely assembly-level debugger I used back in the day. I wish PowerPC assembler was nicer. And simpler. <i>Sigh.</i></p> nkuitse 2004-04-10T15:11:14+00:00 journal Harmless drudgery http://use.perl.org/~nkuitse/journal/18240?from=rss <p>I don't know if anyone's interested, but I've released a new version of my English word list:</p><p><a href="http://www.nkuitse.com/freli/">http://www.nkuitse.com/freli/</a></p><p>It's small, sleek, and the cause of much typing and eye strain for yours truly.</p><p>Factoids...</p><p>Number of entries: <b>50,000</b></p><p>Number of entries that I've checked: <b>50,000</b></p><p>Number of entries added since the last release: <b>ca. 11,000</b></p><p>Number of part-of-speech indications: <b>50,000</b></p><p>Number of definitions: <b>0</b></p><p>Number of proper nouns: <b>0</b></p><p>How I add entries:</p><blockquote><div><p> <tt>$ frop add 'kerfuffle (n)'<br>$ cat new-words | frop add<br>$ frop review<br>** Press 'y' to add a word, 'n' to reject it, or space to skip it **<br>...<br>$ frop commit</tt></p></div> </blockquote><p>Resources I use to discover words and decide what to add:</p><ul><li> <a href="http://www.gutenberg.net/">Project Gutenberg</a> </li><li><nobr> <wbr></nobr><tt>/usr/share/dict/web2</tt> </li><li> <a href="http://www.dict.org/">dict</a> </li><li>google</li><li>Random House Webster's Unabridged Dictionary (2nd ed.)</li><li>The American Heritage Dictionary of the English Language (2nd ed.)</li><li>The Compact Oxford English Dictionary</li><li>My poor overtaxed brain</li></ul><p>To make a long story short: <b>Lexicography is hard work</b> (and FRELI's only a word list, not a dictionary).</p> nkuitse 2004-04-08T20:25:21+00:00 journal Please release me http://use.perl.org/~nkuitse/journal/18059?from=rss <p> I have three Perl modules just <b>begging</b> to be released: </p><ul> <li>IO::Accumulator</li><li>IO::YAML</li><li>Search::TokenIndex (or <a href="http://www.mail-archive.com/module-authors@perl.org/msg01749.html">whatever I end up calling it</a>)</li></ul><p> Plus a new version of <a href="http://www.nkuitse.com/FRELI/">FRELI</a>, my English wordlist. </p><p> But somehow <i>I just can't seem to let them go.</i> I find myself racking my brains to think of every little detail: </p><ul> <li>Do I have everything in my MANIFEST?</li><li>Are my tests OK?</li><li>Did I remember to add a SEE ALSO section to that module's POD?</li> <li>Don't forget to <code>cvs tag</code>!!</li></ul><p> With tools like <code>make distcheck</code>, <code>t/pod.t</code>, and <code>cpan-upload</code> there's really no reason to worry. But for some reason I do anyhow. </p><p> It's like I'm a parent whose child is getting ready to leave home and go to college. All for a few little bits of code and data. Sheesh! So pathetic... </p><p> <b>It's hard to let go.</b> </p> nkuitse 2004-03-25T15:35:29+00:00 journal New module released. Bugs found. Argh! http://use.perl.org/~nkuitse/journal/17879?from=rss <p><a href="http://search.cpan.org/dist/Hash-AsObject/">Hash::AsObject</a> is now available from CPAN.</p><blockquote><div><p> <tt>$h = Hash::AsObject-&gt;new(%myhash);<br>$h-&gt;foo(123);<br>print $h-&gt;foo;&nbsp; # 123</tt></p></div> </blockquote><p>It's all implemented in <code>AUTOLOAD</code> so there are absolutely no verboten keys. All is permitted - even <code>new</code>, <code>AUTOLOAD</code>, and <code>DESTROY</code> may be used as accessors/mutators.</p><p><b>Oops.</b> Dang. My tests weren't checking for <code>VERSION</code>, <code>can</code>, <code>import</code>, and <code>isa</code>. (*Sigh*). And I always wondered why I kept seeing people uploading two or more versions of the same distribution on the same day...</p> nkuitse 2004-03-12T16:20:02+00:00 journal They can pry my G4 from my cold, dead hands http://use.perl.org/~nkuitse/journal/16717?from=rss <p>My employer is replacing a bunch of Macs because of an important new Windows-only piece of software. Apparently, they didn't bother testing it using Virtual PC (if they thought of that at all) and now it's too late.</p><p>As I said, <b>they can pry my G4 from my cold, dead hands.</b></p><p>Ahem.</p><p>Fortunately, they won't have to; I've been allowed to keep it. I'll be using Virtual PC, which I've heard (from people at other sites using the software in question) does indeed work just fine. Sadly, all the other Macs in my office will be replaced.</p><p>The funny thing is, my employer's policy is that a "replaced" computer can actually be kept on an unsupported basis. Picture a bunch of new Wintel boxes gathering dust in the corner...</p><blockquote><div><p><nobr> <wbr></nobr><tt>:-)</tt></p></div> </blockquote> nkuitse 2004-01-08T20:38:43+00:00 journal HyperCard and shell scripting http://use.perl.org/~nkuitse/journal/15942?from=rss <p>So I have this HyperCard stack that serves as a CGI backend...</p><p>It runs on the 1GHz G4 server that sits in my office, about 18 inches from my computer.</p><p>Both machines run Mac OS X. HyperCard runs in Classic (of course).</p><p>Since my HyperCard stack requires hands-on intervention any time something goes wrong or I need to make any changes, I find myself scuttling back and forth from time to time.</p><p>Needless to say, cutting and pasting from one to the other is out of the question (well, I suppose I could use <b>pbpaste</b> and <b>scp</b>). Writing custom scripts for ad hoc reports, etc. is a problem because the stack runs as a standalone; hence you can't just pull up a card script and edit it.</p><p>So I wrote this little shell script...</p><blockquote><div><p> <tt>#!/bin/sh<br> &nbsp; <br>if [ -z "$1" ]; then<br>&nbsp; &nbsp; args=$(cat &lt;&amp;0)<br>else<br>&nbsp; &nbsp; args="$*"<br>fi<br> &nbsp; <br>htscript=$( { echo 'lock error dialogs'; echo "$args"; } \<br>&nbsp; &nbsp; | perl -pe 's/\n/\\r/g; s/"/\\"/g' )<br>echo "tell app \"tls.cgi\" to do script \"$htscript\"" \<br>&nbsp; &nbsp; | osascript | perl -pe 's/\r/\n/g'</tt></p></div> </blockquote><p>(tls.cgi is the name of the standalone stack.)</p><p>And now I can ssh into the server and do things like this:</p><blockquote><div><p> <tt>% tls return number of cds in bg 1</tt></p></div> </blockquote><blockquote><div><p> <tt>% tls &gt;recipes.txt<br>put "" into reports<br>repeat with i = 1 to number of cds in bg "Recipes"<br>&nbsp; put (bg fld "Title" of cd i) &amp; return after reports<br>end repeat<br>return reports</tt></p></div> </blockquote><blockquote><div><p> <tt>% tls 'return somethingOrOther()' | grep<nobr> <wbr></nobr>...</tt></p></div> </blockquote><p>HyperCard is dead! Long live HyperCard!</p><p>(Next up: remote script editing using BBEdit!?)</p> nkuitse 2003-11-22T14:54:35+00:00 journal Non-essential http://use.perl.org/~nkuitse/journal/14138?from=rss <p>Ann Arbor lost power at about 16:12 EDT yesterday, along with everybody else. (Well, not <i>everyone</i> of course...) 50 million people lost power in the U.S. and Canada, apparently.</p><p>I popped in at work this morning to see what was what and was amazed to see we've got power again. (I'm currently being treated very nicely by a Lasko "Wind Machine" fan, sitting about 2 feet away.)</p><p>The University has its own power-generating capabilities (duh!) and the medical library (my workplace) is currently hooked up to the hospital's power. To conserve energy all non-essential staff are supposed to stay home, and I'm afraid I fall in that category (flash to that Twilight Zone episode where Burgess Meredith is obsolete) so I'll have to leave the fan behind and mosey on home and sweat it out. The air outside is thick and torpid, and when I awoke this morning I felt as though I had lain in a pool of sweat all night. On the bright side, the toilet there is flushing OK. At least for now.</p><p>Well, I've put the computers to bed and they should be all right when I come back on Monday. Hopefully we'll get power back soon. More importantly, I hope everybody else out there is OK.</p><p>Signing off for now...</p> nkuitse 2003-08-15T13:22:10+00:00 journal When tests fail: a human comedy in one act. http://use.perl.org/~nkuitse/journal/14119?from=rss <p> <i>Curtain rises. The sun sets slowly over a snowy countryside...</i> </p><p> <i>CHORUS, chanting offstage:</i> </p><blockquote><div><p>Running package tests,<br>Many eyes gaze on failure;<br>Few understand why.</p></div></blockquote><p> <i>Enter FORLORN LITTLE GIRL, in rags:</i> </p><blockquote><div><p>What happens when a test fails? How do we respond?</p></div></blockquote><p> <i>Enter chorus in confusion:</i> </p><ul> <li> <b>Panic.</b> <i>The deadline loometh and woe is me!</i> </li><li> <b>Indifference.</b> <i>&Ccedil;a m'est &eacute;gal.</i> </li><li> <b>Resignation.</b> <i>Oh well, so much for that package.</i> </li></ul><p> <i>FORLORN LITTLE GIRL:</i> </p><blockquote><div><p>What happens when a test fails and the test's documentation explains what it was testing, why, and how?</p></div></blockquote><p> <i>CHORUS, regaining their confidence:</i> </p><ul> <li> <b>Enlightenment.</b> <i>Oh. Well, I don't really need that functionality anyhow.</i> </li><li> <b>Righteous anger.</b> <i>Silly package author doesn't know how to write %@#$*!? tests! Here, give me that keyboard!</i> </li><li> <b>Forgiveness.</b> <i>Yea, we have all written sinful code that fails in unexpected ways. Let me just whip up a patch to fix this...</i> </li></ul><p> <i>FORLORN LITTLE GIRL:</i> </p><blockquote><div><p>Who writes documentation for their tests?</p></div></blockquote><p> <i>CHORUS, muttering angrily and casting eyes accusingly from side to side:</i> </p><blockquote><div><p>Do you? Do you? And you? Do you? Hey you over there! How about you?</p></div></blockquote><p> <i>Enter THE AUTHOR, blushing:</i> </p><blockquote><div><p>Ah, the shame! But I'll change, you'll see!</p></div></blockquote><p> <i>CHORUS, softening their rebuke:</i> </p><blockquote><div><p>Tests should be documented using POD, just like any other Perl code.</p></div></blockquote><p> <i>Exit THE AUTHOR.</i> </p><p> <i>FORLORN LITTLE GIRL:</i> </p><blockquote><div><p>I think we've all learned an important lesson today.</p></div></blockquote><p> <i>Un ange passe.</i> </p><p> <i>CHORUS exits, embarrassed:</i> </p><blockquote><div><p>(Cough.)</p></div></blockquote> nkuitse 2003-08-14T17:01:17+00:00 journal SQL templates http://use.perl.org/~nkuitse/journal/13972?from=rss <p>I'm not crazy about positional parameters in DBI, but I don't want to use a heavy-duty module like Tangram or Alzabo* to get away from them.</p><p>What I decided was to use simple SQL templates with placeholders like <code>$foo</code> instead of <code>?</code>, then write a simple module to expand the template given a hash of placeholder names and values.</p><blockquote><div><p> <tt>my $str = 'SELECT id FROM People'<br>&nbsp; &nbsp; . 'WHERE age &gt;= $min AND age &lt;= $max';<br>my $template = SQL::Template-&gt;new($str);<br>my ($sql, @args) = $template-&gt;process(<br>&nbsp; &nbsp; 'min' =&gt; 20,<br>&nbsp; &nbsp; 'max' =&gt; 29<br>);<br># $sql = 'SELECT id FROM People'<br># . 'WHERE age &gt;= ? AND age &lt;= ?'<br># @args = (20, 29)<br>$dbh-&gt;prepare_cached($sql, @args);</tt></p></div> </blockquote><p>That was simple enough. But then I also wanted multiple substring searching like this:</p><blockquote><div><p> <tt>my $str = 'SELECT id FROM People'<br>&nbsp; &nbsp; . 'WHERE { name ILIKE $name }:AND';<br>my $template = SQL::Template-&gt;new($str);<br>my ($sql, @args) = $template-&gt;process(<br>&nbsp; &nbsp; 'name' =&gt; 'tolk% %chris%'<br>);<br># $sql = 'SELECT id FROM People'<br># . 'WHERE name ILIKE ? AND name ILIKE ?'<br># @args = ('tolk%', '%chris%')<br>$dbh-&gt;prepare_cached($sql, @args);</tt></p></div> </blockquote><p>That was easier than I had thought it would be.</p><p>The hardest part is what to call my module. <code>SQL::Template</code> is the most obvious choice, but to me that sounds like a big, fancy module whereas mine is very simple (and likely to remain that way).</p><p>Meanwhile, the module isn't quite ready for release, since I think there are some Postgresisms to root out.</p><p><i>* Not that there's anything with Tangram or Alzabo!</i></p><p><b>Update 18 Aug:</b> Fixed the quotes in the sample code (should have been single quotes, not double. D'oh!)</p> nkuitse 2003-08-07T15:46:59+00:00 journal Idle dreaming on a hazy, lazy day... http://use.perl.org/~nkuitse/journal/13253?from=rss <p><b>clew</b> </p><p>Command-Line Easy Wiki. Console-based wiki and blog.</p><blockquote><div><p> <tt>% clew list --last-first<br>Today 11:43:49 - Pie in the sky #11<nobr> <wbr></nobr>/project/pie rev:37<br>[...]<br>% clew new<nobr> <wbr></nobr>/foo/bar<br>---+ Bar<br>I like [bar], but [BAZ] is better!<br>% clew path -a<nobr> <wbr></nobr>/foo/bar | sed 's/like/luv/' | clew store -v -m 'luv!' bar<br>Storing new revision of node bar...<br>Multiple matching nodes:<br>&nbsp; [1]<nobr> <wbr></nobr>/iron/bar #90<br>&nbsp; [2]<nobr> <wbr></nobr>/bar/bar/bar #226<br>&nbsp; [3]<nobr> <wbr></nobr>/foo/bar #870<br>Pick one or enter 'c' to cancel: [3]<br>Node<nobr> <wbr></nobr>/foo/bar revision 2 checked in.<br>% EDITOR='bbedit -w -c' clew edit baz</tt></p></div> </blockquote><p> <b>freli</b> </p><p>Shell to manage <a href="http://www.nkuitse.com/FRELI/">FRELI</a>.</p><blockquote><div><p> <tt>% freli add blogroll (n) "list of related weblogs"<br>Added 1 entry.<br>% freli find<nobr> <wbr></nobr>/gry/<br>angry (adj) #1776<br>hungry (adj) #15622<br>% freli find blogroll -q &amp;&amp; echo "It's in there."<br>It's in there.<br>% freli stem --show-confidence insidiousness<br>100% insidious -ness</tt></p></div> </blockquote><p> <b>nkc</b> </p><p>A command-line utility to manage a versioned, files-built-from-many-sources Web site. Think lots of small makefiles and plenty of YAML.</p><blockquote><div><p> <tt>% nkc discover -i '/tt2$/'<br>Found 3 unknown files:<br>foo/bar/baz.html.tt2 - add? [y]<br>[...]<br>% nkc shell<br>nkc&gt; build<br>Making web site...<br>[...]<br>nkc&gt; test --all-links<br>localtest/foo/bar/index.html Bad link &lt;URL:http://www.example.com/etc/&gt; 404</tt></p></div> </blockquote><p> <b>nkpr</b> </p><p>Project manager, where a <i>project</i> might be a Perl module, a script, a web site, a book of bad poetry, or any of the things listed above.</p><p><i>Dream, dream, dream...</i></p> nkuitse 2003-07-04T16:30:31+00:00 journal LOCmania http://use.perl.org/~nkuitse/journal/13235?from=rss <p>Arg. People who squash together their Perl code excessively just to keep the line count down (<i>only <b>n</b> lines long!</i>) should...</p><p>Well, they should please stop it.</p><p>Thank you.</p> nkuitse 2003-07-03T17:44:40+00:00 journal Brain. Hurts. Must. Stop. http://use.perl.org/~nkuitse/journal/13109?from=rss <p>My current project is a database for work. To save myself future headaches, I've been sticking to the <i>code it once</i> principle. Specifically, I've been coding table and class information in YAML, then defining templates (using the Template Toolkit, of course) to produce SQL code, Perl modules, and (ta da!) a Makefile.</p><p>With lots of Perl glue.</p><p>And now I've got the biggest headache of them all.</p><p>Moral: trying to save myself headaches later is pointless if <b>my brain explodes in the process!</b></p><p><b>Update:</b> Happily, the headache is quickly fading. I added a target in my makefile spec to produce a (longish) SQL command file that populates the database in one transaction, and the resulting file is looking good. It's not running to completion, because my data has a few hiccups in it that my data preparation scripts didn't catch, but that's easy enough to fix.</p><p>Moral #2: When trying to save yourself headaches later, don't try to save them all at once. One aspirin at a time, my friend!</p> nkuitse 2003-06-27T18:53:20+00:00 journal Amazon sucks http://use.perl.org/~nkuitse/journal/10810?from=rss <p>(That's amazon.com, not The Amazon.)</p><p>Well, <a href="http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&amp;Sect2=HITOFF&amp;d=PALL&amp;p=1&amp;u=/netahtml/srchnum.htm&amp;r=1&amp;f=G&amp;l=50&amp;s1=6,525,747.WKU.&amp;OS=PN/6,525,747&amp;RS=PN/6,525,747">they've done it again</a>. So much for Jeff Bezos's claim that he "shares my concern for both customers and innovation" (according to <a href="http://www.oreilly.com/ask_tim/amazon_patent.html">Tim O'Reilly</a>).</p><p>Here's what I'm doing about it:</p><blockquote><div><p> <tt>From: (me)<br>To: help@amazon.com<br>Cc: jeff@amazon.com<br>Subject: Please help<br> <br>I want to cancel my account with amazon.com,<br>because of its abuse of the US patent system.<br>(Sorry, the stupidity of the USPTO is no excuse.)<br> <br>Instead of shopping with amazon.com, I'll shop with its competitors.<br> <br>Please tell me how to cancel my account.<br> <br>Thanks,<br> <br>(signed)</tt></p></div> </blockquote><p>It isn't much (heck, it's hardly anything at all) but their latest abuse was the last straw for me.</p> nkuitse 2003-02-27T02:43:17+00:00 journal Stars in my eyes http://use.perl.org/~nkuitse/journal/10765?from=rss I'm just back from a trip to East Lansing, Michigan, where my girlfriend was kind enough to accompany me to the star show at Abrams Planetarium. After the show, she bought me some glow-in-the-dark stars. What more could a geek who never really grew up ask for? nkuitse 2003-02-24T22:48:27+00:00 journal Runtime rigmarole http://use.perl.org/~nkuitse/journal/10676?from=rss <p> I've just finished testing my initial implementation of a simple module you can use to get and set variables, define and call functions, and evaluate arbitrary Perl code. It simply formalizes calls to <code>eval($src)</code> and <code>${"${pkg}::$varname"}</code> and whatnot: fairly common things that can be tricky to get right. It works by creating a unique, randomly named package and then accessing variables and functions in that package. (Duh.) </p><p> Right now it's called <code>JOM::Shell::RunTime::UsingPackages</code> (I'm using it in a simple shell); it inherits from the abstract class <code> JOM::Shell::RunTime</code> at some point I'll rename these for general consumption and post them to CPAN. </p><p> The following example is a nearly complete picture of what the module provides: </p><blockquote><div><p> <tt>use JOM::Shell::RunTime::UsingPackages;<br>my $runtime = JOM::Shell::RunTime::UsingPackages-&gt;new();<br> <br>$runtime-&gt;setvar('@fib' =&gt; (0, 1, 1));<br>$runtime-&gt;defsub('fib' =&gt; &lt;&lt;'--EOS--');<br>{<br>&nbsp; &nbsp;my ($n) = @_;<br>&nbsp; &nbsp;push @fib, $fib[-2] + $fib[-1]<br>&nbsp; &nbsp; &nbsp; while $#fib &lt; $n;<br>&nbsp; &nbsp;return $fib[-1];<br>}<br>--EOS--<br>$runtime-&gt;callsub('fib', (9)) == 34<br>&nbsp; &nbsp;|| die "Not 34";<br>$runtime-&gt;evaluate(&lt;&lt;'--EOS--');<br>&nbsp; &nbsp;$fib9 = fib(7) + fib(8);<br>&nbsp; &nbsp;die unless $fib9 == fib(9);<br>);<br>$foo = $runtime-&gt;getvar('$fib9');</tt></p></div> </blockquote><p> There are some wrinkles to work out (notably, <code>die</code> and <code>warn</code> and their ilk won't produce very helpful error messages) but all in all it's pretty useable as is. Now to get my PAUSE ID and roll it up for release. But what name to use?? </p> nkuitse 2003-02-20T02:18:35+00:00 journal Too Kool for Words http://use.perl.org/~nkuitse/journal/10599?from=rss <p> <a href="http://kmirror.deskmod.com/">Konfabulator</a>. </p><p> Wow. Mac OS X goodness. Shiny widgets. Cool tools. </p><p> A <a href="http://konfabulator.deskmod.com/?show=showskin&amp;skin_id=25825">comic strip viewer</a>, a <a href="http://konfabulator.deskmod.com/?show=showskin&amp;skin_id=25700">game</a>, a <a href="http://konfabulator.deskmod.com/?show=showskin&amp;skin_id=25379">puzzle</a>, an <a href="http://konfabulator.deskmod.com/?show=showskin&amp;skin_id=25321">HTML validator</a>, RSS streamers, and a gazillion clocks. </p><p> I just whipped up a widget to display random words. All it does is invoke my Perl script <b>kwet</b> on a profile selected from a pop-up in the Preferences window. </p><p> A new random word every <i>n</i> seconds. Now to code up a visual history display... </p><p> If only I had the graphics savvy to make mine look as purty as other peoples'. <i>Sigh...</i> </p> nkuitse 2003-02-15T04:16:33+00:00 journal The incredible silliness of being an uncle http://use.perl.org/~nkuitse/journal/10591?from=rss <p> I just received a <a href="http://greetings.yahoo.com/">Yahoo greeting</a>: </p><p> <i>To: Uncle Paul</i> <br> <i>Have a wonderful Valentine!</i> <br><nobr> <wbr></nobr><i>...</i> </p><p> Being an uncle is cool. You get to buy them toys and books, teach them words in strange languages, tell them stories about your shoes, make jokes about rutabagas, and when you arrive at their house for a weekend visit they gang-tackle you as you walk in the door. </p><p> And of course <b>my</b> nephew and nieces are the best of all! </p> nkuitse 2003-02-14T19:47:05+00:00 journal Angelo's http://use.perl.org/~nkuitse/journal/10572?from=rss <p> An apple fritter. </p><p> A cup of apple juice. </p><p> Thanks, <a href="http://www.angelosa2.com/home.htm">Angelo's</a>: these simple things keep me going in the afternoon when hunger strikes after too much coding. </p><p> No thanks for the <a href="http://www.angelosa2.com/">Flash spasm</a>, though. </p><p> * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * </p><p> "Too much coding"? <b>Who am I kidding?</b> </p> nkuitse 2003-02-13T21:06:40+00:00 journal Did I kill use.perl.org? http://use.perl.org/~nkuitse/journal/10570?from=rss <p> Every once in a while I'll submit a form in a Web site, and the next thing I know the site isn't working properly. </p><p> Usually, it's my own server, and the problem is a bug in my own code. I scoot my chair over to the server (just two feet from my desk) to see what new torture I've put my long-suffering HyperCard stack <i>cum</i> CGI handler through. Or maybe long-lived HyperCard is showing its age again: it happens every once in a while, usually during automated backup, and ever since upgrading to Mac OS X closing the stack invariably leaves cruft in the stack. Or maybe the older version of Classic I'm using (not upgraded for fear of breaking my HyperCard stack) is driving up CPU usage. Or maybe it's a synergy of many things. </p><p> In any event, it's usually my fault but I'm able to fix it in a few minutes. If it's not my server that's acting up, I go nervously on my way hoping it wasn't my garbage in that triggered the server's garbage out, looking around to make sure no one was watching and feeling the emptiness around me (computers and hubs and a router off in a closet somewhere). </p><p> * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * </p><p> Twenty minutes ago, it happened when I was visiting <a href="http://use.perl.org/">use.perl.org</a>. </p><p> No more do I submit a new HTML-formatted journal entry for preview than I find myself staring at <b>Internal Server Error</b>. Was my HTML malformed? Yes. Did I think to syntax-check it first? No. When I fix the mistake (just one little '<tt>&gt;</tt>' forgotten) and resubmit, do I get the same error? Yes. When I chop off all but the opening paragraph (nothing but a <tt>&lt;p&gt;</tt> and some text inside) and resubmit, do I see the same error? Yes. When I try to go to <a href="http://use.perl.org/">http://use.perl.org/</a> (don't forget the final slash!), do I see the same error? Yes. </p><p> <b>Did I kill use.perl.org?</b> </p><p> Between that last paragraph and this, I went back to try again. The internal server error is gone. I pull up my diary to write <a href="http://use.perl.org/~nkuitse/journal/10569">the new entry</a> I'd been previewing. All is well. I preview, I edit; I submit: happiness all around. I sigh in relief. </p><p> But a hint of worry remains. My lunch hour is over, and I'll never know: did I kill use.perl.org? </p><p> <i>Sometimes the loneliness of the Internet is a mile wide.</i> </p> nkuitse 2003-02-13T18:55:04+00:00 journal Hammers and nails http://use.perl.org/~nkuitse/journal/10569?from=rss <p> <i>When all you have is a hammer, everything looks like a nail.</i> </p><p> Evidently, this can be generalized: </p><p> <i>When you get a nice shiny new hammer, everything looks like a nail. Even the things you pounded on with the last shiny new hammer you got. And the one before that. And the one before that. And so on. Hammers and nails everywhere, and all so shiny and new!</i> </p><p> * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * </p><p> My most recently acquired shiny new hammer is <tt> <a href="http://search.cpan.org/perldoc?YAML">YAML</a> </tt>. Earlier, it was XML. Now, entries in the lexicon for my invented language are going from something like this: </p><blockquote><div><p> <tt>&lt;e&gt;<br>&lt;l&gt;sempe&lt;/l&gt;<br>&lt;d&gt;<br>&nbsp; &nbsp;&lt;sg cat="noun"&gt;<br>&nbsp; &nbsp; &nbsp; &lt;s&gt;gold&lt;/s&gt;<br>&nbsp; &nbsp;&lt;/sg&gt;<br>&nbsp; &nbsp;&lt;sg cat="adj"&gt;<br>&nbsp; &nbsp; &nbsp; &lt;sg label="a"&gt;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;xp&gt;similar to gold in appearance&lt;/xp&gt;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;s&gt;gold&lt;/s&gt;<br>&nbsp; &nbsp; &nbsp; &lt;/sg&gt;<br>&nbsp; &nbsp; &nbsp; &lt;sg label="b"&gt;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;xp&gt;made of gold&lt;/xp&gt;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;s&gt;golden&lt;/s&gt;<br>&nbsp; &nbsp; &nbsp; &lt;/sg&gt;<br>&nbsp; &nbsp;&lt;/sg&gt;<br>&lt;/d&gt;<br>&lt;/e&gt;</tt></p></div> </blockquote><p><nobr> <wbr></nobr>...to something like this: </p><blockquote><div><p> <tt>---<br>sempe:<br>&nbsp; &nbsp;- noun: gold<br>&nbsp; &nbsp;- adj:<br>&nbsp; &nbsp; &nbsp; - a:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- xp: similar to gold in appearance<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- gold<br>&nbsp; &nbsp; &nbsp; - b:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- xp: made of gold<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- golden</tt></p></div> </blockquote><p> That's a mighty nice, shiny new hammer. And look! -- <b>nails!</b> </p> nkuitse 2003-02-13T18:40:15+00:00 journal superslotworldobjectmodel http://use.perl.org/~nkuitse/journal/10548?from=rss <p> Consider a classless object model with these simple principles: </p><p> * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * </p><p> A <b>world</b> is a collection of <b>objects</b>. </p><p> Each world is wholly independent from all other worlds. </p><p> Each world has a single <b>root object</b>. </p><p> Every object has a unique identifier (its OID). </p><p> Every object has exactly one <b>parent</b>, except a root object, which has none. </p><p> An object may have any number of <b>slots</b>. </p><p> An object inherits its parent's slots. </p><p> A root object needn't have any slots. </p><p> A slot has code. </p><p> A slot may have a parent, which is another slot. </p><p> An object has no code. </p><p> Objects receive <b>messages</b>. </p><p> A message has a name, arguments, and a sender. </p><p> When an object receives a message, it <b>invokes</b> its slot of the same name. If it has no such slot, the message is forwarded to the object's parent. </p><p> An error occurs when the root object receives a message and has no slot of the same name. </p><p> A slot may have data. </p><p> Upon being invoked, a slot may access its data. </p><p> Upon being invoked, a slot may invoke its parent, the sender of the message which resulted in the slot being invoked, or any object to which its data contains a reference. </p><p> Slots may share code. </p><p> Slots may <i>not</i> share data. </p><p> A slot knows of no other slot except its parent (if it has one). </p><p> Objects can't send messages, because they don't have code. Their task is simply to handle messages by finding and invoking the right slots. </p><p> A slot is given a reference to its owning object when the slot is invoked, but may not keep it (unless for some reason the slot wishes to keep the reference in its data). </p><p> An object (call it <b>X</b>) may be <b>cloned</b> to produce another object (call it <b>B</b>). <b>X</b> is then the parent of <b>Y</b>. </p><p> * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * </p><p> In a nutshell: an object is simply a collection of slots, each of which may inherit from some other slot. </p><p> This is what is keeping me busy now at work. There are a few more principles (reflection, translucency, acyclicity, etc.) but this is the gist of it. </p> nkuitse 2003-02-12T18:54:54+00:00 journal Getting test religion http://use.perl.org/~nkuitse/journal/10547?from=rss <p> <a href="http://search.cpan.org/perldoc?Test%3A%3AInline">Test::Inline</a> is wonderful. </p><p> <a href="http://search.cpan.org/perldoc?Test%3A%3AMore">Test::More</a> is terrific. </p><p> It's only in the past month or so that I've begun writing lots of small tests. It's only in the past month or so that I've begun writing <i>any</i> test code to speak of. My eyes are wide open now to new vistas. </p><p> I'm a very happy camper. </p><p> I'm tickled pink. </p><p> I'm pleased as Punch. </p><p> But in the last few days, I've found myself coding so fast that I haven't paused to write tests. Well, maybe two or three short ones. And a longer one. I guess that's not so bad: a few is better than none at all... </p><p> I wonder: am I coding fast because my newfound <i>test religion</i> makes working code easier to produce? No, I don't think so. </p><p>But suppose I hit that familiar wall and the code engine dries up. What then? Well, I go back to writing tests; that may just be my ticket back to Happy Hack Mode Land. </p> nkuitse 2003-02-12T18:10:37+00:00 journal WikiWishing http://use.perl.org/~nkuitse/journal/10541?from=rss <p> What I want is a <a href="http://www.google.com/search?q=%22command+line+wiki%22">command-line wiki</a>. </p><p> A backend, not a curses- (or suchlike-)based interface <i>&agrave; la</i> <a href="http://lynx.isc.org/">lynx</a>. </p><p> <a href="http://www.emacswiki.org/cgi-bin/wiki.pl?EmacsWikiMode">emacs WikiMode</a> sounds interesting, but I'm a <a href="http://www.bbedit.com/">BBEdit</a> monkey myself. </p><p> I suppose I'll have to write one myself. </p><p> At least I have a name for it: <b>clew</b>. </p><blockquote><div><p>ModE <i>clue, clew</i> &lt; ME <i>clewe</i> &lt; OE <i>cleowen, cliewen</i>; cf. OHG <i>kliu</i> 'ball'.</p></div> </blockquote><p><nobr> <wbr></nobr>...and here I thought it came from Latin <i>clavis</i> 'key'. Etymolomumbojumbo narrowly averted! </p> nkuitse 2003-02-12T12:29:41+00:00 journal Day one http://use.perl.org/~nkuitse/journal/10532?from=rss <p>Despite a terrible track record in journals and diaries and such (oh my!), I'm going to give this a shot.</p><p>Look here for occasional accounts of adventures in Perl and whatnot. Emphasis on the whatnot.</p> nkuitse 2003-02-12T00:09:39+00:00 journal