output

1 view
Skip to first unread message

Alex Chaffee

unread,
Dec 13, 2009, 8:36:29 PM12/13/09
to erector
I made a branch called 'output' that uses an output object instead of a mere string. This was done for a couple of reasons:

* to fix some prettyprinting indentation bugs
* to allow Page to selectively include externals rather than spamming HEAD with all externals for all classes

(I haven't done the 2nd one yet, but I did the first.)

Predictably, it caused some havoc in the Rails integration code. I've now gotten all the tests to pass.. except one. And this is actually potentially going to cause the removal of a useful (if undocumented) feature -- the ability to call "helpers.foo" and have it grab the 'concat'ed output from whatever wacky Rails helper 'foo' is. 

See, Erector's got this schizophrenia about helper output that it inherited from Rails. When you call a helper, it can either return a string, or emit some output onto the stream directly. And then that helper might call "yield" to allow you to do more stuff, which it may attempt to "capture" (or may just let happen). So translating that into an Erector world where (nearly) everything gets written ASAP makes for some very annoying and confusing roundabout spaghetti.

To account for this (and for equally inconsistent behavior with html-escaping) we've got some specialized proxy methods inside RailsHelpers (ESCAPED_HELPERS, RAW_HELPERS, CAPTURED_HELPERS_WITHOUT_CONCAT, CAPTURED_HELPERS_WITH_CONCAT, DIRECTLY_DELEGATED). But we haven't covered all the helpers, mostly because there's a lot of them, and they're poorly documented, so we'd have to test and proxy each one.

So, to finish the recap, John Firebaugh and Brian and others have been using/promoting the "helpers.whatever" workaround, and I'm reluctant to take that away unless people tell me it's ok. So is it ok? Is there a way to make it work again on the output branch? Should I start the long, hard slog of systematically writing test cases for all the helpers?


---
Alex Chaffee - al...@cohuman.com - http://alexch.github.com
Stalk me: http://friendfeed.com/alexch | http://twitter.com/alexch | http://alexch.tumblr.com

Jim Kingdon

unread,
Dec 14, 2009, 10:02:23 AM12/14/09
to ale...@gmail.com, erector
> going to cause the removal of a useful (if undocumented) feature -- the
> ability to call "helpers.foo" and have it grab the 'concat'ed output from
> whatever wacky Rails helper 'foo' is.

Whenever these discussions come up I kind of get lost in details, but yes,
of course we should be able to call arbitrary rails helpers with a minimum
of fuss. One use case I'm thinking of is converting an ERB application
piecemeal, where the helpers in question are application-specific.

In ERB, this is pretty simple and the only question is whether to call
them with <% or <%= (which correspond to your return a string versus write
to the buffer cases, I believe).


Alex Chaffee

unread,
Dec 14, 2009, 12:26:36 PM12/14/09
to Jim Kingdon, erector
On Mon, Dec 14, 2009 at 7:02 AM, Jim Kingdon <kin...@panix.com> wrote:
> going to cause the removal of a useful (if undocumented) feature -- the
> ability to call "helpers.foo" and have it grab the 'concat'ed output from
> whatever wacky Rails helper 'foo' is.

Whenever these discussions come up I kind of get lost in details, but yes,
of course we should be able to call arbitrary rails helpers with a minimum
of fuss.

I think you just cracked the nut. Instead of "helpers.foo", how about "call_helper(:foo)" that calls through the DIRECTLY_DELEGTED method? Then it would be documented, and people using it would have a migration path.

Or even better: override the "helpers" method to return a *proxy* to the actual helpers object that does delegation via method_missing?
 
 - A

John Firebaugh

unread,
Dec 17, 2009, 12:16:14 AM12/17/09
to ale...@gmail.com, Jim Kingdon, erector
My preferred solution would be to be able to call rails helpers
without any fuss -- not helpers.foo, not call_helper(:foo), just foo.
Thomas Fisher and I have been working on an implementation towards
that goal leveraging the "html safe" notion introduced (to Rails --
erector has of course always had it) in 2.3.5.

The plan as I see it is:

1) Make erector's notion of html safety compatible with Rails's. HTML
produced by erector via to_s or capture should be treated as safe by
Rails, HTML produced by Rails helpers should be treated as safe by
erector.

2) Monkey patch Rails such that it uses erector's output buffer, and
captures via erector's capture method. (This is the approach haml
takes. Erector's current approach is the opposite -- erector uses
Rails's output buffer and delegates capture to Rails. This fails in
the case where you have a Rails helper that tries to capture a erector
block.)

3) Delegate the majority of helpers directly via method_missing.
Hopefully #1 and #2 allow this to "just work". Because of #1, we no
longer need to worry about escaping. Because of #2, output always goes
to erector.

4) Write wrappers for only the subset of helpers that return a string
that you would usually want immediately outputted. For example,
link_to, but not translate. The wrapper is very simple: it just
delegates to rails and then outputs the result.

Thomas has been working on this on his fork:

http://github.com/wless1/erector/tree/experimental

> --
>
> You received this message because you are subscribed to the Google Groups
> "erector" group.
> To post to this group, send email to ere...@googlegroups.com.
> To unsubscribe from this group, send email to
> erector+u...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/erector?hl=en.
>

Jim Kingdon

unread,
Dec 17, 2009, 12:32:12 PM12/17/09
to John Firebaugh, erector
> 2) Monkey patch Rails such that it uses erector's output buffer, and
> captures via erector's capture method. (This is the approach haml
> takes. Erector's current approach is the opposite -- erector uses
> Rails's output buffer and delegates capture to Rails. This fails in
> the case where you have a Rails helper that tries to capture a erector
> block.)

Looking at the haml code (and being dissatisfied with the complexity - and
presumed fragility in light of new rails versions) is part of what
motivated Brian and I to switch to the current erector approach of using
the rails buffer. (Before that, erector had the worst of both worlds -
its own buffer and the rails buffer, and a fairly flaky set of mechanisms
which tried to move output from one to the other).

My impression reading the haml code was that they went to all that trouble
so that they could run the non-haml output through their prettyprinter.

I'm not sure about the rails capture mechanism (and whether it has changed
since I last looked), but why wouldn't it hijack the rails output buffer?
Isn't that what capture generally does?

> 4) Write wrappers for only the subset of helpers that return a string
> that you would usually want immediately outputted. For example,
> link_to, but not translate. The wrapper is very simple: it just
> delegates to rails and then outputs the result.

Why not just make people write "text link_to"? ERB makes people do the
equivalent.


Alex Chaffee

unread,
Dec 17, 2009, 12:36:06 PM12/17/09
to John Firebaugh, Jim Kingdon, erector
Sounds awesome! (as long as I don't have to write the rails monkey
patch :-)

I'll look at the fork soon. Have you guys checked out the 'output'
branch yet?

Sent from my iPhone

On Dec 16, 2009, at 9:16 PM, John Firebaugh <john.fi...@gmail.com>
wrote:

John Firebaugh

unread,
Dec 17, 2009, 1:09:54 PM12/17/09
to Jim Kingdon, erector
>> 4) Write wrappers for only the subset of helpers that return a string
>> that you would usually want immediately outputted. For example,
>> link_to, but not translate. The wrapper is very simple: it just
>> delegates to rails and then outputs the result.
>
> Why not just make people write "text link_to"?  ERB makes people do the
> equivalent.

I thought the same at first, and this is how my fork currently works
and how I'm currently using helpers. But I find it unsatisfactory. In
ERB, where you already need the <% %> tags, the extra = isn't a big
deal. But in the erector context, where the default is for helper
methods to emit rather than return, the extra 'text' call is
cognitively dissonant and error prone. Because my erector helper
methods don't require it, I tend to forget it when using rails
helpers. The returned result string is silently ignored and I spend a
good chunk of time wondering why portions of my view aren't showing
up.

It's certainly attractive not to have to write any wrappers though.
I'd welcome feedback from anyone else using erector+rails as to this
tradeoff.

Reply all
Reply to author
Forward
0 new messages