Archive for January, 2008

uniq uses hash and eql?

Wednesday, January 30th, 2008

If you’re wondering how to make your objects work correctly with Array#uniq, the answer is: define hash and eql?.

This is one of the most frustrating parts of Ruby: the documentation is frequently just plain bad (or absent).  I guess the advantage is that it drives people to read (and write) Ruby blogs more.

rbgrep, born 2008.1.28: 3 files, 118 lines

Tuesday, January 29th, 2008

Last night, I checked in the first version of my rbgrep program to Rubyforge.

First, the problem.  When I’m working on a program, whether I wrote it or not, I’m constantly asking questions like “where did I define this method?”, or “who uses this class”?  There’s a classic program to search for text in files: grep(1).  Unfortunately, plain grep is stupid.  It doesn’t know not to search .svn/ folders.  It doesn’t know that “find” after a “#” is not a method call.  And if you want to do anything nontrivial, the escaping can quickly become unbearable.

I’ve always just been lazy and solved this with … more grep. Like this:

grep -r "def start" ../../|grep -v svn|grep -v log:|less

What a pain.  At some point, I realized that if I wrote a short program, I could be even lazier.

The turning point was probably seeing Ryan Davis’ ParseTree.  This allows you to pass in some Ruby source code, and get back its AST, roughly, as arrays of symbols.  (It’s kind of like Lisp but not as convenient.)  This actually reaches inside the Ruby interpreter, so if I search the AST for a node that looks like [:defn :start …], I know that Ruby thinks it’s a “def start”, and not a comment or string literal or something like that.  Pretty cool.

To download it:

svn checkout http://rbgrep.rubyforge.org/svn/trunk/ rbgrep

To use it, run ‘rbgrep’.  For the example above, I would search for “def start” with:

rbgrep start some/folder/

Right now, it’s stupidly simple: it just searches for method defs in *.rb files.  There’s more to come in the future, and I’ve got some ideas for really cool features, but I’ll probably only add them if I think they’ll save me more time than it’ll take.

Now the Java#++ programmers are saying “why did you need to write this yourself?  my whiz-bang-IDE-inator does this for me out-of-the-box!”.  One of my current side projects (i.e., I started it a few weeks ago and haven’t really touched it since) is working through The Art of the Metaobject Protocol; one of their premises is that the reason you need a good meta system is so programmers can build tools like this easily.  How much work would it be to do this in Java?  More than 100 lines and an hour of work, I suspect.  Your fancy IDE has this because it needs to: if they didn’t provide this, it would never be worth it for you to implement yourself.

Testing ApplicationHelper

Monday, January 28th, 2008

We wanted to test our ApplicationHelper code.  Unfortunately the obvious approach doesn’t quite work out-of-the-box in Rails 1.2. With the help of various blog postings (The Official Documentation Source of Rails) we figured out an answer: in test/unit/application_helper_test.rb, say something like:

require File.dirname(__FILE__) + '/../test_helper'
class ApplicationHelperTest < Test::Unit::TestCase
  include ApplicationHelper
  include ERB::Util
  def test_something
    ...
  end
end

Including ApplicationHelper lets you call AH methods in tests directly.  Since AH is a module that always gets mixed in to classes that provide ERB, you need to include ERB::Util if you have any helpers that call methods like h().Now you can tell me The Easy Way, or why this is obvious to any Real Programmer, or whatever. If it helps one poor schmuck trying to figure out Rails, that’s good enough for me.

At the Apple store

Thursday, January 24th, 2008

I tried running Disk Utility yesterday, but after more than a day, it seemed to have made no progress.  At the Apple store, Markus tried booting from an external Firewire drive (among other tricks), and my hard drive no longer even appears.  It is quite dead.

So now they’re installing a fresh hard drive for me, under warrantee, in a “0 to 60″ (Apple-ese for “we fix your computer in an hour”).

Lessons learned: I probably need a better backup solution, but “check stuff in every day” is a pretty good one. (Yeah, I know about branches.  Branching and merging in SVN is too painful for me to do unless I really need it.)  Expect even more checkins now that I’m super paranoid!

Sad Mac

Wednesday, January 23rd, 2008

I was writing a program on my Mac…

And it was like, beep, beep, beep, beep, beep…

And then like… half of my program was gone.

And I was like… unh?

It devoured… my program.

It was a really good program.

And then I had to do it again and I had to do it fast, so it wasn’t as good.

It’s kind of… a bummer…

On cultural differences between languages

Thursday, January 17th, 2008

While trying to figure out how to get MysqlAdapter to do something, it occurred to me one big difference between Ruby (which I’m relatively new to) and Lisp (which I’ve played with for years).

Where Lispers use hooks, Rubyists use monkeypatching.

It’s not a technical difference, because you can monkeypatch in Lisp and you can use hooks in Ruby. Maybe it’s a question of maturity: programmers don’t want to add hooks that won’t get used, and so only add them lazily.  It certainly seems true that older Lisp code is more likely to have more hooks: Common Lisp itself has a million hooks, and Emacs, says the jargon file, “is all hooks”.  Maybe it’s natural selection: Lisp libraries either end up with lots of hooks, or dead.

The Ruby way has advantages and disadvantages.  On the plus side, a young project doesn’t have to guess what people might want to extend.  On the downside, well, it’s monkey-patching.

(For example, the problem that inspired this post led me to monkey-patching a private method.  It looks like you can monkey-patch a private method, but you can’t call ’super’ in it, because super is private. Gah.  And ActiveRecord has basically no hooks.)

Even Zed Shaw, flamester extraordinaire, hates it.  Monkey-patching is ghetto.

What I really want is a hybrid Lisp/Ruby solution: CLOS qualifiers in Ruby.  A qualifier is a keyword you pass to defmethod — :before or :after or :around — which causes it to supplement, rather than replace, the (unqualified) method definition that already exists. It’s like hooks everywhere for free.

That is, I want to be able to say:

class MysqlAdapter
  def :after connect
    execute("SET SESSION sql_mode='ANSI'")
  end
end

(Now somebody is going to write me some super-twisted Ruby code to allow exactly that, and it’s going to be like monkey-patching but 10 times worse because it’ll be implemented as one giant monkey-patch.  Thanks, no.)

But in plain old Ruby, what’s the solution?  If you write a library, it needs hooks — especially if you’re part of a big framework, like ActiveRecord is.  And if you design a programming language, it should make allowing hooks virtually free for people writing libraries.

We’ve Arrived

Tuesday, January 15th, 2008

A few weeks ago, our building was tagged:

php tag
It was some gang going by the name “php“.  Note that even though they had a huge empty space to work with,  they didn’t care to stay inside the lines. And olive drab?  Come on.  Have you no taste?

Please discuss

Monday, January 14th, 2008

As we are a “Web 2.0″ startup, we want to be the next Facebook (by which I mean “popular”, not “useless”).  They’re obviously winning big on social, while we’ve spent a lot of time building an actual service.  Rest assured, we have a lot of social features in the pipeline, and we’ll be Facebook-cool before too long.

In the meantime, I don’t want to be anti-social, so I’ve started a “Google Group” for ClayValet.  You can use this to discuss anything related to ClayValet, from a really good or really bad report you got, to features you wish the website had, to spreading nasty rumors about us.

http://groups.google.com/group/clayvalet

We can’t promise we’ll respond, or even read it, but it’s for you to do what you want with.  Enjoy.

Naze Nani ClayValet!

Wednesday, January 9th, 2008

I’m a programmer at ClayValet, a Seattle (cap hill) startup.  We’re building an online shopping service in Ruby.  (No, it’s not just like Amazon or Froogle.)

So, Mikhail tells me we should be blogging.  It’s a good way to get our name out there, and keep in touch with other Ruby / startup / Seattle folks.  Plus it’s the ultimate passive-aggressive weapon.

It gives me the opportunity to rant about how horrible Rails is (like all software), and it gives you the opportunity to feel good about recognizing the subtle (or not) references I drop.  (Google and Wikipedia pretty much spoil this, so I’ll have to come up with some really obscure ones.)  I may even post something useful someday, improbable as that may seem.

Hello, world.