RCR to modify #puts and #print inside ERB

Proposed RCR:

Modify ERB so that calls to #puts, #print, and #p inside the template append the resulting string onto the local ERB output variable, instead of sending the output to $stdout. #warn would still send to STDERR (for debug messages seen but kept out of the result string) and $stdout#<< could also be used.

Does anyone have any compelling reason why I should not make the above RCR? I'll flesh it out as a proper RCR, citing the ruby-talk threads with users wondering why it doesn't work as they expected.

As noted in another recent thread, I have in my possession an implementation (perhaps not ideal) which accomplishes this already, and would just need to be included. Would a C implementation also be required for eruby, to keep feature parity between ERB and eruby?

(Should #p also be modified? Or is that logically a debug action already?)

Hi --

Proposed RCR:

Modify ERB so that calls to #puts, #print, and #p inside the template append the resulting string onto the local ERB output variable, instead of sending the output to $stdout. #warn would still send to STDERR (for debug messages seen but kept out of the result string) and $stdout#<< could also be used.

Does anyone have any compelling reason why I should not make the above RCR? I'll flesh it out as a proper RCR, citing the ruby-talk threads with users wondering why it doesn't work as they expected.

I can't think of any reason to do this other than the fact that people
who haven't learned how to use ERB expect it, and I don't consider
that a compelling reason. I would therefore not be in favor of it.
Further on the negative side, it would have the effect of collapsing
two very different logical levels into one. It just seems odd to have
three methods whose interpolated value is the value of an argument,
while everything else in the language is interpolated on the basis of
its actual value.

David

···

On Sat, 10 Sep 2005, Gavin Kistner wrote:

--
David A. Black
dblack@wobblini.net

Hello Gavin,

Proposed RCR:

Modify ERB so that calls to #puts, #print, and #p inside the template
append the resulting string onto the local ERB output variable,
instead of sending the output to $stdout. #warn would still send to
STDERR (for debug messages seen but kept out of the result string)
and $stdout#<< could also be used.

Does anyone have any compelling reason why I should not make the
above RCR? I'll flesh it out as a proper RCR, citing the ruby-talk

I will vote against this RCR.

I don't think it is good to change this. I'm quite sure you break
backward compatibility in a lot of places and i don't see any real need
to do this.

If you write a RCR please explain more detailed why you want to do
this and where you see compatibility problems, maybe you can convince
me to accept the RCR.

and would just need to be included. Would a C implementation also be
required for eruby, to keep feature parity between ERB and eruby?

If it is accepted, then yes, please.
There is already the "-%>" problem with eruby vs. ERB and its going to
piss off a lot of people.

···

--
Best regards, emailto: scholz at scriptolutions dot com
Lothar Scholz http://www.ruby-ide.com
CTO Scriptolutions Ruby, PHP, Python IDE 's

Why not just change $stdout, e.g.:

<%
require 'stringio'
$orig_stdout = $stdout
$stdout = StringIO.new(_erbout, 'a')
$stdout.sync = true
%>1
<% puts "2" %>3
<% $stdout = $orig_stdout %>

should print:

1
2
3

Then puts keeps the same behavior as it has now, and you get the result
you want using the existing behavior.

Paul

···

On Sat, Sep 10, 2005 at 11:12:21PM +0900, Gavin Kistner wrote:

Proposed RCR:

Modify ERB so that calls to #puts, #print, and #p inside the template
append the resulting string onto the local ERB output variable,
instead of sending the output to $stdout. #warn would still send to
STDERR (for debug messages seen but kept out of the result string)
and $stdout#<< could also be used.

I have to agree. There's no advantage to having puts() work, since you can just slap in the text itself with ERb tags as needed. I personally think it's better that people confused by this aspect ask here and get corrected, than it is to break puts() for them.

James Edward Gray II

···

On Sep 10, 2005, at 9:40 AM, David A. Black wrote:

Hi --

On Sat, 10 Sep 2005, Gavin Kistner wrote:

Proposed RCR:

Modify ERB so that calls to #puts, #print, and #p inside the template append the resulting string onto the local ERB output variable, instead of sending the output to $stdout. #warn would still send to STDERR (for debug messages seen but kept out of the result string) and $stdout#<< could also be used.

Does anyone have any compelling reason why I should not make the above RCR? I'll flesh it out as a proper RCR, citing the ruby-talk threads with users wondering why it doesn't work as they expected.

I can't think of any reason to do this other than the fact that people
who haven't learned how to use ERB expect it, and I don't consider
that a compelling reason.

Others have expressed similar sentiments, so I'm responding in general:

At work, our bug filing system has you rate each bug on several different axes, one of which is "severity". One option is "Missing functionality; workaround exists", and another (weightier) option is "Missing functionality, no workaround". In general, having *a* way to accomplish a task is not the same as having the 'ideal' way to accomplish a task. It's better than nothing, but it's not perfect.

Separate from the "because it's what certain people expect" factor, I consider the current method of appending strings to "_erbout" less convenient/ideal than using muscle-memory-friendly methods like #puts.

To take it to the extreme, what if ERB did not support any Kernel methods, but provided another mechanism for calling them? What if you couldn't write "myobj.foo" but instead had to write "myobj.send( :foo )" to invoke the method? The exact same functionality would still be there...you would just need to remember, when using ERB, to write your code in a different way than you do normally. My belief is that it would be a PITA. The more the code you have to write inside ERB blocks deviates from Ruby (syntax, idioms, or 'general use') the less convenient it is to use. The more ERB 'just works' right out of the box, the greater a tool it becomes to lure people to Ruby.

(I have coworkers who are considering using Ruby for code generation, based on me showing how incredibly simple it was to use.)

Obviously (and thankfully) ERB is not at this far extreme, but it is along this axis that I argue for including #puts and the like inside ERB.

I understand the theoretical argument for backwards-compatibility. Have you (dear reader) personally ever used #puts or #print inside an ERB template for debugging output that you didn't want included in the result? I know I haven't, but I accept that I'm a sample size of one. If backwards compatibility is truly an issue (and this RCR were accepted) then I suppose it would have to be something like an option to the constructor. (But bleah, I really want it to just work, without having to write "ERB.new( foo, nil, '%', nil, true )".)

If my above arguments do not sway the majority, then the feature won't be added. I could just release some sort of "require 'erb_with_puts'" library that wraps around the existing ERB. No worries. I'm just hoping to make Ruby better out of the box (IMHO) for new-adopters and old alike.

···

On Sep 10, 2005, at 8:40 AM, David A. Black wrote:

I can't think of any reason to do this other than the fact that people
who haven't learned how to use ERB expect it, and I don't consider
that a compelling reason.

--
"When I am working on a problem I never think about beauty. I only think about how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong."
- R. Buckminster Fuller

If you're suggesting putting this at the top of every ERB template, then that's the reason not to do it. The purpose of this idea (which I've mostly abandoned, seeing how many are against it) was to make puts and print "just work", so that you don't have to think of ERB as different from any other ruby program. The above certainly provides a way for puts and print to work, but it requires too much effort.

···

On Sep 20, 2005, at 8:12 AM, Paul Brannan wrote:

On Sat, Sep 10, 2005 at 11:12:21PM +0900, Gavin Kistner wrote:

Proposed RCR:

Modify ERB so that calls to #puts, #print, and #p inside the template
append the resulting string onto the local ERB output variable,
instead of sending the output to $stdout. #warn would still send to
STDERR (for debug messages seen but kept out of the result string)
and $stdout#<< could also be used.

Why not just change $stdout, e.g.:

<%
require 'stringio'
$orig_stdout = $stdout
$stdout = StringIO.new(_erbout, 'a')
$stdout.sync = true
%>1
<% puts "2" %>3
<% $stdout = $orig_stdout %>

should print:

1
2
3

Then puts keeps the same behavior as it has now, and you get the result
you want using the existing behavior.

James Edward Gray II <james@grayproductions.net> writes:

Hi --

Proposed RCR:

Modify ERB so that calls to #puts, #print, and #p inside the
template append the resulting string onto the local ERB output
variable, instead of sending the output to $stdout. #warn would
still send to STDERR (for debug messages seen but kept out of the
result string) and $stdout#<< could also be used.

Does anyone have any compelling reason why I should not make the
above RCR? I'll flesh it out as a proper RCR, citing the ruby-talk
threads with users wondering why it doesn't work as they expected.

I can't think of any reason to do this other than the fact that people
who haven't learned how to use ERB expect it, and I don't consider
that a compelling reason.

I have to agree. There's no advantage to having puts() work, since
you can just slap in the text itself with ERb tags as needed. I
personally think it's better that people confused by this aspect ask
here and get corrected, than it is to break puts() for them.

+1

···

On Sep 10, 2005, at 9:40 AM, David A. Black wrote:

On Sat, 10 Sep 2005, Gavin Kistner wrote:

James Edward Gray II

--
Christian Neukirchen <chneukirchen@gmail.com> http://chneukirchen.org

IMHO, they way it behaves currently is what is broken.

My personal mental model says that #puts is for outputting content that is the desired output of your program (unlike #warn). An ERB template is a parametrized program in its own right, and its output is the resulting string. If you want debug output, use #warn.

That's how I look at it, anyhow. Do others actually think of an ERB template as an enormous HEREDOC string in another file that is going to be included in your program, and ERB as an uber-powerful gsub to run on that string?

···

On Sep 10, 2005, at 9:39 AM, James Edward Gray II wrote:

I personally think it's better that people confused by this aspect ask here and get corrected, than it is to break puts() for them.

Gavin Kistner wrote:

Separate from the "because it's what certain people expect" factor, I consider the current method of appending strings to "_erbout" less convenient/ideal than using muscle-memory-friendly methods like #puts.

Can you give me an example of when appending to _erbout is necessary or preferred rather than saying "%>some text<%" or "%><%=some value%><%"?

To take it to the extreme, what if ERB did not support any Kernel methods, but provided another mechanism for calling them? What if you couldn't write "myobj.foo" but instead had to write "myobj.send ( :foo )" to invoke the method? The exact same functionality would still be there...you would just need to remember, when using ERB, to write your code in a different way than you do normally.

The exact same functionality *is* available when you puts or print. With your change, people expecting to spit out debug messages would have to do $stdout.puts...

The more ERB 'just works' right out of the box, the greater a tool it becomes to lure people to Ruby.

Understood. Well, for what it's worth right now, the features it has work almost exactly as they do in JSP, including the separation between puts (System.out.println, as usual) and _erbout (newly conceived out.println).

That's how I look at it, anyhow. Do others actually think of an ERB template as an enormous HEREDOC string in another file that is going to be included in your program, and ERB as an uber-powerful gsub to run on that string?

Well, yes, but that's because I know how it works. I understand that newbs don't see it that way. Those that know say, "Don't hide the truth! Make the newbs learn!" You say, "Make the abstraction so pure that newbs don't /need/ to learn!" There is some validity in that argument, but, sadly, I'm going to side with Joel[1] on this one.

Devin
[1] The Law of Leaky Abstractions – Joel on Software

I would favor your RCR. I think no code will be broken because of the
new behavior.

Michel.

···

On 9/10/05, Gavin Kistner <gavin@refinery.com> wrote:

I understand the theoretical argument for backwards-compatibility.
Have you (dear reader) personally ever used #puts or #print inside an
ERB template for debugging output that you didn't want included in
the result? I know I haven't, but I accept that I'm a sample size of
one. If backwards compatibility is truly an issue (and this RCR were
accepted) then I suppose it would have to be something like an option
to the constructor. (But bleah, I really want it to just work,
without having to write "ERB.new( foo, nil, '%', nil, true )".)

Hi --

I can't think of any reason to do this other than the fact that people
who haven't learned how to use ERB expect it, and I don't consider
that a compelling reason.

Others have expressed similar sentiments, so I'm responding in general:

At work, our bug filing system has you rate each bug on several different axes, one of which is "severity". One option is "Missing functionality; workaround exists", and another (weightier) option is "Missing functionality, no workaround". In general, having *a* way to accomplish a task is not the same as having the 'ideal' way to accomplish a task. It's better than nothing, but it's not perfect.

Separate from the "because it's what certain people expect" factor, I consider the current method of appending strings to "_erbout" less convenient/ideal than using muscle-memory-friendly methods like #puts.

To take it to the extreme, what if ERB did not support any Kernel methods, but provided another mechanism for calling them? What if you couldn't write "myobj.foo" but instead had to write "myobj.send( :foo )" to invoke the method? The exact same functionality would still be there...you would just need to remember, when using ERB, to write your code in a different way than you do normally.

But code isn't normally inserted into a text template. It's a
specialized situation. There's no way, and no reason, to sweep that
under the carpet.

My belief is that it would be a PITA. The more the code you have to write inside ERB blocks deviates from Ruby (syntax, idioms, or 'general use') the less convenient it is to use. The more ERB 'just works' right out of the box, the greater a tool it becomes to lure people to Ruby.

I admit I am very down on luring people to Ruby by introducing
inconsistencies and anomalies into the language and libraries. What
this particular special case would do would be to mask the fact that
puts and print are method calls with return values. That creates the
need to explain one or both of two things: the fact that, elsewhere,
they do behave like normal methods, and the fact that, in ERB, they
don't. It's a double twist in the road; so why not just learn how it
really works in the first place?

In the short term, having the puts/print exception might allow a few
people to indulge habits that correspond to a novice's first
instincts. But in the long term, what makes Ruby simple and
attractive, in my view, is in part the fact that while there *are*
advanced features and techniques, those features and techniques tend
to be built up incrementally and transparently from the simple things.
I would rather see people invest effort in really understanding method
calls and return values, than have to learn ad hoc how particular
method calls operate in different contexts. It's sort of like having
to learn irregular verbs.

David

···

On Sun, 11 Sep 2005, Gavin Kistner wrote:

On Sep 10, 2005, at 8:40 AM, David A. Black wrote:

--
David A. Black
dblack@wobblini.net

Separate from the "because it's what certain people expect" factor, I consider the current method of appending strings to "_erbout" less convenient/ideal than using muscle-memory-friendly methods like #puts.

Can you give me an example of when appending to _erbout is necessary or preferred rather than saying "%>some text<%" or "%><%=some value%><%"?

It's never necessary, as %><%=foo%><% is equivalent to _erbout << foo.to_s
It's preferred (by me) in cases where control whitespace is important, or where the typing of the above is far more cumbersome than typing "puts foo"

Contrived Example 1:
<ul>
<% items.each do |item|
     _erbout << "\t<li>#{item.value}</li>\n"
end
%></ul>

compared with
<ul>
<% items.each do |item|
     <li><%=item.value%></li>
<% end
%></ul>

(Not only is the newline sort of annoying in the above, but "\t" is clearly a single tab character, where indentation on your editor may use spaces to precede the <li>)

Contrived Example 2:
<%
sum = 0
100.times do |i|
     _erbout << i.to_s
     sum += i
end
_erbout << (sum / 100).to_s
foo.bar()
%>

compared with:
<%
sum = 0
100.times do |i|
     %><%=i%><%
     sum += i
end
%><%=sum/100%><%
foo.bar()
%>

compared with:
<%
sum = 0
100.times do |i|
     print i
     sum += i
end
print sum / 100
foo.bar()
%>

The exact same functionality *is* available when you puts or print. With your change, people expecting to spit out debug messages would have to do $stdout.puts...

That's a good point. I suppose it seems 'correct' to me because (for me) it's DWIM. As for for debug messages, I argue that debug messages should be done with #warn anyhow (which would remain unchanged) as STDERR is more appropriate (I think) than STDOUT. And, I simply didn't believe that anyone was actually using the puts-in-erb-for-debug functionality. (And I suppose I still won't, until someone says "Yes, I use that!")

The more ERB 'just works' right out of the box, the greater a tool it becomes to lure people to Ruby.

Understood. Well, for what it's worth right now, the features it has work almost exactly as they do in JSP, including the separation between puts (System.out.println, as usual) and _erbout (newly conceived out.println).

So it currently meshes well for people coming from JSP, eh? That's good to know.

Well, yes, but that's because I know how it works. I understand that newbs don't see it that way. Those that know say, "Don't hide the truth! Make the newbs learn!" You say, "Make the abstraction so pure that newbs don't /need/ to learn!" There is some validity in that argument, but, sadly, I'm going to side with Joel[1] on this one.

Devin
[1] The Law of Leaky Abstractions – Joel on Software

Thanks for the article. I love reading Joel :slight_smile:

···

On Sep 10, 2005, at 12:53 PM, Devin Mullins wrote:

In article <49958C10-DAD0-4E7C-B9AB-44C6D314A637@refinery.com>,
gavin@refinery.com says...

My personal mental model says that #puts is for outputting content
that is the desired output of your program (unlike #warn). An ERB
template is a parametrized program in its own right, and its output
is the resulting string. If you want debug output, use #warn.

Agreed. I find it interesting that most of the responders to the thread
aren't active in the Rails group; Rails is where this sort of thing
*really* would be nice.

I admit I used "puts-as-debug" the other day, but only because I was
doing a quick-and-dirty test and it was the first way I figured out to
get some Rails output into webrick. It's certainly not something I'd
keep in the code for more than 10 minutes.

And in Rails, where ERB owns the view, Gavin's examples don't strike me
as controlled at all - you often end up jumping between ERB and HTML
tags. Here's some code from the Agile Rails book that could look a lot
nicer if the "puts" metaphor were available:

<% for product in @products -%>
        <h3><%= h(product.title) %></h3>
        <%= product.description %>
        <span class="catalogprice"><%= fmt_dollars(product.price) %>
</span>
<% end %>

vs.

<% for product in @products
        puts "<h3>", h(product.title), "</h3>",
          product.description,
          '<span class="catalogprice">', fmt_dollars(product.price),
    "</span>"
   end %>

···

--
Jay Levitt |
Wellesley, MA | I feel calm. I feel ready. I can only
Faster: jay at jay dot fm | conclude that's because I don't have a
http://www.jay.fm | full grasp of the situation. - Mark Adler

Gavin Kistner wrote:

<Contrived Example 1 & Contrived Example 2>

Thanks. #1 seems like a good example. #2 seems a little too contrived - your example obviously doesn't need erb - and I would imagine that the addition of markup would make the erb syntax a little less ugly. That said, I don't feel like trying to make a counter-example, so take that with a grain of salt.

That's a good point. I suppose it seems 'correct' to me because (for me) it's DWIM. As for for debug messages, I argue that debug messages should be done with #warn anyhow (which would remain unchanged) as STDERR is more appropriate (I think) than STDOUT. And, I simply didn't believe that anyone was actually using the puts-in-erb-for- debug functionality. (And I suppose I still won't, until someone says "Yes, I use that!")

I should mention, I don't really use erb, so I'd abstain from the vote. I just piped up to provide a little analysis. I'm starting a Rails project (finally), so maybe I'll have some better opinions in a couple weeks. :slight_smile:

So it currently meshes well for people coming from JSP, eh? That's good to know.

Yeah. (Well, % at the beginning of a line is new.) I don't know what that's worth, though. All the Manly Men of the Java web world would never run into the problem, because 1. they wouldn't place logging code inside JSP (ideally no logic at all, using custom tags where logic would be needed), 2. they'd be using log4j, and 3. they'd never use out.println, if only for the sake of purity.

Thanks for the article. I love reading Joel :slight_smile:

<homer>Mmm... controversy...</homer>

Devin

Have you considered using Rails's programatic Builder views?

James Edward Gray II

···

On Sep 10, 2005, at 5:01 PM, Jay Levitt wrote:

Here's some code from the Agile Rails book that could look a lot
nicer if the "puts" metaphor were available:

<% for product in @products -%>
        <h3><%= h(product.title) %></h3>
        <%= product.description %>
        <span class="catalogprice"><%= fmt_dollars(product.price) %>
</span>
<% end %>

vs.

<% for product in @products
        puts "<h3>", h(product.title), "</h3>",
            product.description,
            '<span class="catalogprice">', fmt_dollars(product.price),
        "</span>"
   end %>

Hi --

In article <49958C10-DAD0-4E7C-B9AB-44C6D314A637@refinery.com>,
gavin@refinery.com says...

My personal mental model says that #puts is for outputting content
that is the desired output of your program (unlike #warn). An ERB
template is a parametrized program in its own right, and its output
is the resulting string. If you want debug output, use #warn.

Agreed. I find it interesting that most of the responders to the thread
aren't active in the Rails group; Rails is where this sort of thing
*really* would be nice.

I love Rails and I use it quite a lot. But I like ERB to behave
in the consistent, non-special-cased way it now does, which is
perfectly straightforward given how method calls work in Ruby (which
is a matter of public record :slight_smile: I also don't like the idea of
changing things around in the language because the changes would suit
a given application, project, or framework (though in this case, for
me, that's a moot point because I don't think it would be suitable
anyway).

David

···

On Sun, 11 Sep 2005, Jay Levitt wrote:

--
David A. Black
dblack@wobblini.net

In article <Pine.LNX.4.61.0509101649240.26048@dblack.wobblini.net>,
dblack@wobblini.net says...

I like ERB to behave
in the consistent, non-special-cased way it now does, which is
perfectly straightforward given how method calls work in Ruby (which
is a matter of public record :slight_smile: I also don't like the idea of
changing things around in the language because the changes would suit
a given application, project, or framework

Then maybe the answer would be for ActionPack to override the behavior
of puts while parsing a view..? That might make everyone happy, ya?

···

--
Jay Levitt |
Wellesley, MA | I feel calm. I feel ready. I can only
Faster: jay at jay dot fm | conclude that's because I don't have a
http://www.jay.fm | full grasp of the situation. - Mark Adler

I'm getting the idea that the people on each side of this discussion
disagree because they have different mental models of what ERB does,
and what a ERB document is:

1. ERB just implements very fancy, flexible, string interpolation.
or
2. ERB documents are executable code (actual programs), where text
prints itself, and code blocks get run.

#1 is, I gather, much like the JSP way (though I've never done JSP stuff)
#2 is much like PHP.

If you are in the #1 camp, I suspect you think this RCR would not be
all that much different from one allowing this:
"#{puts 23}" #==> "23\n"

If you are in camp #2, you probably just wonder why stuff you output
via #print or #puts doesn't end up with the rest of your ERB program's
output.

I'm in camp #2; I came to Ruby from PHP, and think of the template as
an actual program, an executable script with controlling statements
(Ruby code) embedded in self-printing text. I was shocked and greatly
disappointed when I found out that puts didn't work (yes, I thought it
was *broken*). I delved deeper and discovered that it was simply due
to an implementation issue; I assumed no one had fixed it because it
was too complicated a fix.

Now, I have a proposal: What if _erbout was made into a StringIO, and
we shifted the idea from an ERB template to an ERB program? Then would
it make sense for puts to output to _erbout?

cheers,
Mark

(my apologies if any part of this doesn't make sense, it's been a very long day)

···

On 9/10/05, David A. Black <dblack@wobblini.net> wrote:

Hi --

On Sun, 11 Sep 2005, Jay Levitt wrote:

> In article <49958C10-DAD0-4E7C-B9AB-44C6D314A637@refinery.com>,
> gavin@refinery.com says...
>> My personal mental model says that #puts is for outputting content
>> that is the desired output of your program (unlike #warn). An ERB
>> template is a parametrized program in its own right, and its output
>> is the resulting string. If you want debug output, use #warn.
>
> Agreed. I find it interesting that most of the responders to the thread
> aren't active in the Rails group; Rails is where this sort of thing
> *really* would be nice.

I love Rails and I use it quite a lot. But I like ERB to behave
in the consistent, non-special-cased way it now does, which is
perfectly straightforward given how method calls work in Ruby (which
is a matter of public record :slight_smile: I also don't like the idea of
changing things around in the language because the changes would suit
a given application, project, or framework (though in this case, for
me, that's a moot point because I don't think it would be suitable
anyway).

Hi --

In article <Pine.LNX.4.61.0509101649240.26048@dblack.wobblini.net>,
dblack@wobblini.net says...

I like ERB to behave
in the consistent, non-special-cased way it now does, which is
perfectly straightforward given how method calls work in Ruby (which
is a matter of public record :slight_smile: I also don't like the idea of
changing things around in the language because the changes would suit
a given application, project, or framework

Then maybe the answer would be for ActionPack to override the behavior
of puts while parsing a view..? That might make everyone happy, ya?

I think you're making too much of this perceived separation between
people who don't like the magic puts/print idea, and people who use
Rails. I am living proof that there is no such separation :slight_smile: My
dislike of the magic puts/print applies to its use in ActionPack
templates as much as anywhere else. I just don't think it's a good
idea to single these methods out for anomalous behavior in templates.

David

···

On Sun, 11 Sep 2005, Jay Levitt wrote:

--
David A. Black
dblack@wobblini.net