Alex Chaffee's blog
No, seriously. Why wouldn't you use Erector? Cause I think it's a pretty awesome view framework, but for some reason it hasn't caught fire yet. So if you think writing actual Ruby to emit HTML, with a clean, nestable syntax with full support for Ruby features like inheritance, delegation, and yield is neat, but there's something holding you back, then please let us know what it is. At best we can fix it, and at worst, at least we'll know why.
Here are some reasons I think you might not use Erector:
You love angle brackets. If this is the case then I can't help you. I don't think anybody can.
You like typing every tag name twice. Since Erector elements are Ruby statements, every open tag gets automatically closed.
You like invalid HTML. Since Erector elements are Ruby statements, every open tag gets automatically closed. (See how that works?)
You always remember to call 'h'. Rails 3.0 is going to HTML-escape all output by default. Erector's been doing this the whole time. Cause, you know, why wouldn't you?
You like having to rewrite your code when you extract a partial, and then again when you extract a helper method. In ERB, templates, partials, and helpers all have slightly (and annoyingly) different syntax for things like referring to variables and calling other code. Erector is all Ruby, so you can use your favorite refactoring browser, or just cut and paste, to move your code around. Check out this excerpt from Jeff Dean's RailsConf talk to see this in action, or read the slides from the whole talk on SlideShare.
You hate encapsulation. You think that your views should have direct access to all the instance variables of your controller. Unless they're partials, in which case you shouldn't, even though you can, although the names might be different. Confused yet? So am I.
You like putting code for one component in three separate files. Erector's new "externals" feature allows you to put all the code -- HTML, CSS, and JavaScript -- inside a single Ruby class. The CSS and JavaScript then get output inside the HEAD, once per HTML page, while the HTML gets rendered in the BODY as usual, as many times as necessary. This follows the OO paradigm of cohesion, otherwise known as "put similar stuff together," which is the complement of loose coupling, which means, "keep different stuff apart."
Okay, so those were sarcastic reasons. Here are some more possible reasons why you wouldn't use Erector. I suspect that these next ones hit closer to the mark. But I believe that they're all specious, if not downright false.
Your site contains a whole lot of complex HTML and a few inserted Ruby variables. OK, this makes sense. Erector's not great for static sites. But I've never personally worked on a web application where the code inside the views didn't quickly get complex enough to require codey things like loops and functions. And if you're writing code, then why not do it in a programming language?
Your designers don't know Ruby. I've heard this complaint a lot, but I have yet to meet this mythical designer who's smart enough to understand modern HTML, CSS, JavaScript, ERB, and partials, but is not smart enough to learn that "div 'foo', :class=>'bar'" outputs "<div class='bar'>foo</div>". On the contrary, I've worked with several designers who, after a few tutorial pairing sessions, were comfortable checking code in and out and editing Erector view code at will. Like any junior coder, they need to stay away from the tough stuff, but they're pretty good at knowing what they don't know and asking for help when they need it. (Which they would also do if working inside ERB.)
View code needs to look as similar to HTML as possible. Well, I hear this, but have you looked at HAML? That language is hella popular, and it doesn't look anything like HTML. Its structure is similar, in the abstract, but so's Erector's, and at least in Erector the method for emitting a div is called, you know, "div". And it's a method. And I don't want to turn this into a war between HAML and Erector -- I think HAML is gorgeous -- but HAML suffers from the same design flaw as every templating technology: views are not objects, and markup isn't code. After a certain point of complexity, HAML's elegance breaks down and you'd be better off doing loops and functions in code.
You've already got a bunch of stuff in ERB and it'd take too long to convert it. Yes, legacy code is a pain, but we have a command-line tool that converts ERB (or HTML) to Erector to make it a bit smoother. And you don't have to convert your whole app to Erector at once. Erector views can interoperate with ERB or HAML in Rails and Sinatra.
You're stuck on an old version of Erector. Yes, legacy code is a pain, but we have an upgrade guide for getting to 0.6.0, and people on the mailing list ready to help.
Erector's too slow. Lies! Erector is faster than a greased rattlesnake going downhill. Check out these benchmarking results. Erector is about 2x as fast as ERB and 4x as fast as HAML about the same speed as ERB and HAML(*) under typical conditions. We make sure to use the same output stream to minimize string copy or realloc, and using Ruby objects means much lower parsing overhead.
(*) Update: the "2x/4x" figure was based on a benchmark program that didn't use template caching, which speeds things up for both ERB and Haml. With template caching, Erector and Haml are about the same speed; Haml is about 20% faster when rendering a page with no partials. See this ongoing thread on the Erector list.
There's no documentation. More lies! We have a whole bunch of documentation at http://erector.rubyforge.org, including a FAQ and a user guide.
You got burned by Markaby. Underneath the elegant facade of Markaby lay a confusing and often counter-intuitive engine. Its use of instance_eval and other tricks made simple things break in weird ways and made debugging a real chore. Erector was born out of those frustrations, and one of its main design goals is "no magic." Also, there was a long time where Markaby wasn't being maintained (although that's changed recently); we have a core group of developers committed to responding on the mailing list and github, and we run integration tests against the latest stable Rails release (and soon, against Edge) to catch incompatibilities early on.
Rails has all these great helpers and I want to keep using them. Okay, go right ahead! Erector's Rails integration allows you to call any helper, either directly through a proxy method, or indirectly through the helpers object. If you find a helper that doesn't work, let us know and we'll add it to the list of supported helpers. (We haven't done all of them yet because it's a pain in the neck to look at each function and figure out what its input and output semantics are. Does it return a string or emit directly onto the output stream? Does it take a block? An options hash? An html_options hash? Etc.) We're also slowly putting some Rails functionality into Erector, either in the base class or in custom widgets. If there's something you need, ask on the mailing list, or better yet, send us a patch.
Its name is a dirty word. I've heard this more from people who didn't grow up in the United States, where the Erector Set was a popular toy among the 6-to-12-year-old DIY set in the 70s and 80s. (Apparently it was called Meccano in the UK.) Erector is a normal word, used all the time in the news and in business names. And as the name of a view library it's evocative in a way that's relevant and interesting, in that it's a builder, and you build a view up out of parts.
But we have heard this complaint, and in sympathy, changed the name of the command-line tool (oh, sorry, guess I can't say "tool" either)-- uh, executable-- from "erect" to "erector" even though the former is a venerable English verb that's grammatically appropriate ("I asked him to erect the scaffolding."). If you introduce the library and your coworkers get all giggly then I think if you just say the name with a straight face and then roll your eyes and mock your bawdy buddies when they snicker then all will be well. After a few repetitions it won't sound odd at all.
You've never heard of it. Help spread the word! Post a review on your blog! Ask your favorite app framework whether they support it! Post code samples in Erector and when people say "What's that?" then point them at http://erector.rubyforge.org! Give a talk at a meetup! Write your congressman and ask if she supports the Erector Mandate Bill of 2009! Buy ad space on the moon!
So, in conclusion, and despite my somewhat snarky tone throughout, I am honestly and desperately curious to know why the world has not yet beat a path to Erector's door. Anybody got any more ideas?
def capturing_output
output = StringIO.new
$stdout = output
yield
output.string
ensure
$stdout = STDOUT
end
then...
it "exits immediately from --version" do
output = capturing_output do
lambda {
Erector.new(["--version"])
}.should raise_error(SystemExit)
end
output.should == Erector::VERSION + "\n"
end
Sayings I use, only some of which are actually originally attributable to me. Anyone with research on a saying's provenance, feel free to comment. This page, unlike a normal blog entry, will be updated as needed with stuff I find myself saying with air quotes.
A comment is a lie waiting to happen.
"Legacy" means any program that people are actually using.
(Feathers: "Legacy" means "no tests.")
If you try hard enough, you can make anything fail.
There's no such thing as human error. (Only system error.)
If you pay attention to something, it gets better.
It's always a people problem. (Jerry Weinberg)
You can see a lot by looking. (Yogi Berra)
Yogi wrote a book called "You Can Observe A Lot By Watching" but I prefer to think he was misquoting himself.
Language Log has a take on this quote: She was seeing at me
Object-Oriented Programming is like teenage sex: everyone says they're doing it; few actually are; and those who are rarely know what they're doing. (Anonymous, via Misko)
Here's a simple test for whether you're doing it right: Is your data in the same class as the methods accessing it? Oh, really? Check again.
Double negatives are not unconfusing.
Encapsulation means putting similar things together, and keeping dissimilar things apart.
Of course, the trick of design is knowing along what axes to group or differentiate items. One rule of thumb that has served me well since the days of Gamelan -- when we were sorting dozens of incoming applets per day into categories -- is:
Don't look at the item and think, "What category does this item belong in? Look at the category and think, "If I were looking for items in this category, would I want to find this item?"
In other words, make your API fit the mindset of the user, not that of the provider.
Conway's Law: "Any piece of software reflects the organizational structure that produced it."
Or, "The structure of the code reflects the structure of the coders."
Read the error message.

(Update -- version 0.3 released 2-Oct-07. Release notes are here.)
We use subversion for our source control. We love it. But we've noticed a few flaws, and a few weeks ago I decided I'd had enough and wrote a wrapper for it that fixes a few of the most glaring ones:
- Externals get messed up pretty frequently. If you remove or rename an external, the old one gets left around on disk, and if you convert an external to a "real" directory or vice versa then the next update simply fails.
- Externals are updated in series, not in parallel, meaning that if you have a lot of externals your updates can take an excruciatingly long time.
- Externals are updated even if they're frozen to a specific revision number, which wastes even more time on update.
- If you want a clean checkout -- say, for an automated build -- the only way to do it is to do a full checkout, even if 99% of the files are already there on disk.
- The
cocommand is not compatible with the convention of putting files under/trunk, requiring you to type out your whole repository URL followed by/foo/trunk foo - The name of the executable is hard to pronounce -- either "ess vee enn" or "seven", but nobody says "seven" except when they're saying "seven up", which is, I admit, a pretty good pun, but come on, how much cooler is it to say, "sub"?
The current version of sub fixes all of the above (except for converting directories to and from externals, and I'm going to make that work pretty soon).
Install with
sudo gem install sub
Help text is below the fold.

ping is awesome, but it's a little simple-minded. I often find myself running several pings at a time, especially when debugging network configurations. And when you're watching ping run in several windows, as routers go up and down and packets spurt and congeal like blood in a trauma center, extra features spring naturally to mind...
Enter pong. It's a Ruby app I wrote that runs ping in the background and decorates the results, tracking statistics in realtime, refreshing the screen every 5 seconds. Here, I'll show you:
% pong localhost 192.168.1.240 192.168.1.1 google.com yahoo.com pivotalblabs.com
Last 10 seconds:
Mean Missing Host
0.073 msec 0 (0.00%) localhost (127.0.0.1)
2.884 msec 0 (0.00%) 192.168.1.240 (192.168.1.240)
25.745 msec 0 (0.00%) 192.168.1.1 (192.168.1.1)
98.905 msec 0 (0.00%) google.com (72.14.207.99)
38.761 msec 0 (0.00%) yahoo.com (66.94.234.13)
113.418 msec 0 (0.00%) pivotalblabs.com (72.9.100.34)
Last 60 seconds:
Mean Missing Host
0.092 msec 0 (0.00%) localhost (127.0.0.1)
5.757 msec 0 (0.00%) 192.168.1.240 (192.168.1.240)
24.198 msec 0 (0.00%) 192.168.1.1 (192.168.1.1)
98.840 msec 1 (1.67%) google.com (72.14.207.99)
38.504 msec 0 (0.00%) yahoo.com (66.94.234.13)
110.687 msec 0 (0.00%) pivotalblabs.com (72.9.100.34)
Entire run (97 sec):
Mean Missing Host
0.088 msec 0 (0.00%) localhost (127.0.0.1)
5.716 msec 0 (0.00%) 192.168.1.240 (192.168.1.240)
23.713 msec 1 (1.03%) 192.168.1.1 (192.168.1.1)
99.261 msec 1 (1.03%) google.com (72.14.207.99)
35.403 msec 0 (0.00%) yahoo.com (66.94.234.13)
105.349 msec 4 (4.12%) pivotalblabs.com (72.9.100.34)
I've packaged it up as a gem and put the source on RubyForge. Install it with
sudo gem install pong
and let me know what you think. Bug reports, feature requests, and (naturally) patches welcome. Currently it's only been tested on OS X and might work on other Unixes.
(Image of Edmond Lau's two-player analog oscilloscope Pong.)
Wes and Parker pointed us to this article:
Misunderstanding the Law of Demeter by Dan Manges
which is a very nice discussion of the "law" (actually just a suggestion, but a very strong one) that encourages your objects, like small children, not to talk to strangers. Some people seem uneasy with the LoD since it requires them to refactor their objects to have proxy methods all over them. Instead of Paperboy calling customer.wallet.cash you have to put an extra method on Customer -- either cash (attribute delegation -- check out Forwardable in Rails btw) or pay (behavior delegation). But these proxy methods are not clutter, they're the essence of encapsulation. Do not fear encapsulation. Fear is the mind killer.
Anyway, Dan does a great job explaining this concept, until the very end of the article, when he totally chickens out.

Mark and I were just waxing poetic about how great it is to delete code, especially code you just wrote. We pity the attitude of people who think deleting code is somehow wrong -- they feel so guilty that they won't even delete it right off, they just comment it out, and then check it in... We came up with the following simile:
Writing code is circling your way around a solution, like a dog on the hunt. When you're done, the final solution is going to be a lot smaller than your original perimeter.
This reminds me (Alex) of my favorite quote about writing: "Murder your darlings," said by Sir Arthur Quiller-Couch... or was it..?
I was just sitting around my living room listening to NPR, and heard the following Car Talk puzzler:
I want you to get a pencil and write down the numbers, 1 - 9, inclusive, and leave enough space between them. At your disposal you have one plus sign and two minus signs. You can insert those plus and minus signs wherever you want, to make the total come out to 100.
Naturally, I thought, "Gee, that would be tedious to solve it by hand. But it would be fun to write a Ruby program to solve it!" 9 minutes later I was sending the result (and the source code) to Car Talk Plaza.
So here's your challenge: can you write a program to solve this puzzle? And can you beat my time?
My solution is below the fold... don't click "more" until you've taken a stab at it yourself.
Hoping to improve performance, we changed a query to use the :include condition like this:
Project.find(id, :include => :stories)
and we noticed two things:
- ActiveRecord decided to turn that into a LEFT OUTER JOIN. Egads! This drastically slowed things down (although we didn't notice until several days later, when we ran a real load test with production data).
- acts_as_paranoid did not manage to stick it's little "and deleted_at = nil" phrase into the query. This meant that "deleted" stories showed up when they weren't supposed to.
So that's two gotchas for the price of one.
In email, Nick pointed out that the joining behavior is documented and appropriate ("otherwise if there is a nil association (eg a project without any stories) you wouldn't get a project back even though it exists!") and Miho rejoined that AR can be dangerous because it changes what looks like beautiful, elegant Ruby into nasty, ugly, hard-to-understand SQL under the hood.
Ever do "less log/development.log" and see the following?
ESC[4;35;1mSQL (0.001084)ESC[0m ESC[0mSET character_set_results = utf8;ESC[0m
ESC[4;36;1mSQL (0.001792)ESC[0m ESC[0;1mSHOW TABLESESC[0m
Wouldn't it be nicer to see the colorization like when you're tailing the log with tail -f? Try using -R:
less -R log/development.log
Then you'll see
SQL (0.001084) SET character_set_results = utf8;
SQL (0.001792) SHOW TABLES
A bit more legible, eh wot old chaps?
Works on Mac and Cygwin too.
And -X makes it not clear the screen when you stop less, so you get to keep seeing what you were just seeing.
So that means you may want to put
alias less="less -RX"
or
export LESS="-RX"
in your .bash_profile.
Also, if you don't want the fancy colors at all, specify
ActiveRecord::Base.colorize_logging = false
in your environment file (e.g. test.rb.) We're doing that in our test.rb so we can more clearly read the output from our CruiseControl build.







