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?
Also, there’s been some interesting discussion of an early draft of this blog post on [this thread in the Erector Google Group](http://groups.google.com/group/erector/browse_thread/thread/f02c1405fd962173).
October 8, 2009 at 11:11 am
Here’s a thought experiment: imagine you had no exposure to Ruby or RoR, but – poof! – it all came into being one day, along with all the gems we have available to us now. You’d look around, probably judge Rails to be good (reasonable O/R mapper + web request dispatch).
Then we’d turn our attention to how we write our views. Can you imagine wanting to give up the power of Ruby for a slightly weird, procedural template language? I can’t imagine that.
ERB gets the job done very nicely in some settings – templatizing a conf file in Chef, for example. But view code, like good CSS or js or controller code, is core to what you’re writing and maintaining and refactoring every day in web applications. Yet we stand for a situation in which we willingly (because 50-million-ERB-templates-in-Rails-can’t-be-wrong) chuck OO and better testability overboard and instead wade around in bracket-land.
Erector is a hardened, fast, minimalist, proven, powerful view development toolset with a great little community around it. You might judge that it’s not right for your project, but you’d be remiss if you didn’t strongly consider it. Yay plain old Ruby, and thank you Erector crew.
October 8, 2009 at 1:39 pm
I hadn’t heard of it. I’ve been wishing for a better/faster/maintained Markaby, so this looks promising (though you should probably compare yourself to Erubis instead of ERB on the speed front).
October 8, 2009 at 4:05 pm
For the app I’m working on, end users/designers must be able to create content themselves. Therefore the idea of giving them something in Ruby is either scary or laughable, depending on your attitude.
To provide both power and safety, I’m using [liquid](http://liquidmarkup.org) as the template language.
October 8, 2009 at 5:22 pm
Paul – OK, we’ll add that to the list of *non*-specious reasons. Yikes!
October 9, 2009 at 9:58 am
It would be nice to be able to output HTML comments (for conditional commenting) and also be able to specify the media type when using the css command (i.e. css ‘some.css’, :media => ‘screen, projection’ )
October 19, 2009 at 2:50 pm
Here’s what’s holding me back:
Haml is beautiful.
Forget closing tags with end, how about closing tags with indentation? I’m a bit odd in that I love the significant indentation in Python, but hate everything else about it — most people seem to be just the opposite.
Also, from what I’ve seen of Erector, it’d be like this:
div :class => ‘sidebar’ do
div :class => ‘advertisement’ do
span :class => ‘caption’ do
text ‘advertisement’
end
…
end
end
Contrast this to Haml’s
.sidebar
.advertisement
span.caption=advertisement
…
And then there’s Sass.
Basically, Haml seems to be a DSL built around building not just beautiful, semantic HTML, but building it around CSS selectors, which I can then reuse for jQuery. It is that first, and a generic XML tool second.
By contrast, Erector seems to simply be a generic HTML builder, or perhaps a generic XML builder. It’s smaller than HTML, but still much bigger than Haml.
On the other hand, it’s code, so maybe it’s possible to overcome that limitation? I think I would mind less if I could do something like this:
div.sidebar do
…
end
The biggest reason I want to use it is, I suspect something like this would work:
def sidebar_ad
div :class => ‘sidebar’ do
div :class => ‘advertisement’ do
span :class => ‘caption’ do
text ‘advertisement’
end
yield
end
end
end
def google_ad
sidebar_ad do
…
end
end
That looks so much easier than a partial. In fact, offhand, I’m not even sure how to do it in a partial. I must be forgetting something.
And no, I’m not actually planning to do a bunch of ads. It’s just been on my mind, since I’ve been writing an adblocker lately…
December 12, 2009 at 1:59 pm
@David – Yes, “yield”ing to a helper function is totally possible and is indeed one of the joys of Erector. I’ve got an “Expando” helper that I’ve been using (and used as an example in my Lightning Talk at RubyConf) that wraps whatever block you pass it in a expando/collapso triangle thingy, like this:
expando(“Acme Products”) do
h1 “Buy Acme”
span “Acme is the best for catching road runners.”
end
It uses “arrows.png” which is a sprite that I think I got from jQuery. One other nice thing illustrated by this widget is the “externals” mechanism which allows you to put HTML, CSS, and JS all in one file. Now if only I could convince TextMate to nicely format the JS and CSS inside the here docs…
Gisted at < http://gist.github.com/255534>
December 13, 2009 at 9:54 am
One more thing — a lot of people have requested the “dot” syntax for classes from Markaby. Turns out it’s hard to implement in Erector, since that relies on calling a method on an object returned by the element method, and by that time the element has already been rendered.
However, I just finished a refactoring that might help, potentially allowing us to go back and rewrite elements that have already been emitted. Stay tuned…!
December 13, 2009 at 9:58 am
That gist actually shows one of the main things I like about Sass. You’re repeating “.expando” four times, “.expando .title” twice, and “.expando .arrow” twice, when really, you want to be doing some sort of nesting, like Sass does:
.expando
.title
:cursor pointer
:cursor hand
b
:font-size 14px
div.arrow
:background transparent url(/icons/arrows.png) no-repeat scroll 0px -16px;
:width 16px
:height 16px
:display block
:margin-right .5em
&.closed
:background-position 0px 0px
Aside from the cleaner syntax, CSS also wants to talk to your code — that /icons/arrows.png should be relative to your app, or better yet, to your “slice” in the Merb concept. It shouldn’t be hardcoded as root in a giant string.
So I guess I’m saying, if I was going to go this route, I’d want something similar for CSS — though it could be argued that CSS should be mostly static, and I could just use Sass for it.
As for the “dot” syntax, there’s a better solution, I think — as far as the engine is concerned,
div
by itself is just a self-closing div, right? That is, all it’s outputted so far is:
That’s not a lot to buffer. I’d say, delay rendering an element until one of three things happens:
- You start the next element
- You close the parent element
- You provide actual content for this element
So, a contrived example:
body do
h1.one.two ‘Hello’
div.three.four do
p ‘five’
end
hr.six.seven
hr.eight.nine
end
So, the h1 doesn’t output after the first class, but the second actually adds the text ‘Hello’, so it outputs and closes. The div doesn’t output by itself, or with “three”, but “four” is called with a block, so it outputs before it starts the block. The first hr doesn’t output until the second hr starts, at which point, the first one outputs and closes. The second hr doesn’t output until the body closes…
Does that make sense?
Of course, I say this without looking at the Erector source, so I have no idea how difficult it would be to implement. But it means you’d at most be holding the element name and a couple of classes for a bit longer than you otherwise might have. I think that’s a lot cleaner than going back and altering previously-emitted text.
That helps a bit, with the classes, but that’s not all there is to Haml. I’d still miss:
- The item#foo syntax for ids. They are more efficient than classes, where they make sense. Even if you’re using jQuery, $(‘#foo’) just calls getElementById, whereas $(‘.foo’) has to do a bit more work. I have no idea how this should look in Ruby, though.
- The implied ‘div’ for .foo and #foo. I could live without this, as it starts to mean less with semantic HTML, but still.
- An easy syntax for HTML comments.
- Significant indentation. This is also quite high on my wish list for Ruby itself, so solving it in Ruby would solve it in Erector.
In particular, I would love it if blocks were the default behavior of indentation, where it makes sense — if I didn’t even have to use “do” to do that. If Ruby did that, I think Erector would actually beat Haml for the common case. Taking your gist, I think this would be pretty close to ideal — but again, unfortunately, requires changing Ruby:
div.expando
div.title
classes = %w(arrow left)
classes < < "closed" unless @expanded
div :class => classes
b @title
div.expando_content :style => @expanded ? ” : ‘display: none’
call_block
Even then, there’s still the fact that Erector would tend to lead to ruby_underscore_conventions instead of css-dash-conventions, but I could live with that.
What do you think? Would significant indentation be appropriate for Ruby in general?
Actually, lazibi looks cool, except it probably isn’t supported in my editor, seems dead (since mid-2008), and there’s more than a few corner cases it can’t handle. I suspect it’d be much better to hack support into Ruby itself… but maybe I should take this part to the ruby-talk list.
However, it does seem things like Erector would really bring out my hatred of end statements more than usual.
December 13, 2009 at 11:30 am
It’d take about 15 minutes for Erector to support SASS, and another 5 to support LESS. And yes, I’ve also done #{} string interpolations of ruby code/vars inside CSS and JS to make it cleaner. So yup, we’re thinking along the same lines there.
—
On dot-means-class — yeah, you’re right, we could get the same effect from delaying output. I think either way would be fine, pending performance evaluations.
Markaby also had/has a “!” syntax for id, which means it’s not precisely a CSS selector but it’s getting close.
Here’s another thought: if a symbol is passed as an argument, use it as the class. So that would allow
div :foo =>
or even
div :foo, :bar, :baz!, :onclick => “alert(‘hi’)”
=>
Does that sweeten the deal? Or is it still just not close enough to HAML/CSS?
You could even do a *real* css selector syntax subset if you’re willing to suffer through the colon-quote syntax of Ruby, e.g.
div :’.foo.bar#baz’
—
One of the early decisions we made when we went public with this project was whether to promote curly-braces or do-end to define Erector blocks. We decided “ruby is ruby” and to go with do-end. You, of course, are welcome to use {}.
Your indentation obsession really is an issue with Ruby and I think something like Lazibi would be the way you’d have to go. One problem with that is it makes refactoring harder — and of course, makes your code hard for normal Rubyists to maintain.
—
“An easy syntax for HTML comments” — why do you need this to be easier than “comment ‘foo’”?
December 13, 2009 at 1:31 pm
Absolutely, that does sweeten the deal — I was actually almost assuming that a lot of those issues were solvable, once I saw the class issue. The bang is fine, so long as I can always theoretically override it with:
div :class => ‘some_strange_class!’
You’re right, it is an issue with Ruby. The main question I have is whether I’m the only one… and it’d have to be “something like” Lazibi, I’m not sure Lazibi itself is appropriate.
Comments, you’re right, I suppose — better especially in that I’d use Ruby comments to actually comment something out, and “comment” to provide an HTML comment. One thing I liked about Haml was the ability to comment out an entire tree by adding a -# at the appropriate level of indentation, or use / to turn it into an HTML comment — but I’m not attached to these, my editor can comment/uncomment Ruby easily enough.
December 14, 2009 at 1:33 am
How would you go about using fragment caching with erector? Since everything is emitted to the output stream do I need to somehow capture that, or is it as simple as wrapping the widget render in a Rails cache block and I am just overlooking the obvious?
December 17, 2009 at 1:58 pm
No, you’re not missing anything. Fragment caching is on the road map but not there yet. We’ve been talking about doing it automatically based on a widget’s class and data. But we might just follow Rails’ lead and do it manually with a “cache do” block.
December 20, 2009 at 12:18 am
Hey, I just implemented widget caching! Ask and ye shall receive…
< http://groups.google.com/group/erector/browse_thread/thread/77babecb9b86d240>
Currently it’s just using a hash but it won’t be hard to move to Moneta, and thence to memcache or Redis or whatever…
December 21, 2009 at 5:27 pm
I’ve just started actually using Erector on a project (despite my indentation-sensitive ranting). I am missing that class/id syntax.
Question: Is someone working on that? Or, would it be a lot of work? I’m thinking I’d like to actually do that.
Intuitively, I’d guess delaying output would be faster. Strings are slow. I’m willing to be shown wrong, though.
December 24, 2009 at 4:02 pm