RCR to modify #puts and #print inside ERB

Hi --

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"

Yes, that captures the problem exactly. #{} executes what's in side
it and interpolates the value as a string, and having it do otherwise
based on the name of the method would be anomalous and awkward.

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.

If you want puts and print to behave anomalously, that's OK. But
there's no mystery to why they don't. They behave exactly the same
way every other method behaves. I don't think the *absence* of a
"magic" or special case should be a source of wonder :slight_smile:

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.

The "coming from PHP" argument, I fear, is illogical. It predicates
that whoever designed templating in PHP was empowered to make
decisions for authors of future templating systems -- and by
extension, presumably, everything else about future programming
languages. That, in turn, would mean that there could be no further
languages after PHP.

In fact, there could only be one language at all, because the people
who learned the first language would "come from" that language and
therefore be constrained to do things as they were done in that
language.

I know you're not really suggesting that Ruby become PHP. But the
"coming from" thing, while interesting in terms of our various
biographies, has nothing to do with Ruby per se, and has no persuasive
weight when it comes to discussing possible changes to Ruby. How
could it? How could Ruby do everything everyone did in the last
language they used? And *why* should Ruby play that kind of
self-effacing, chameleon-like role? Why doesn't Ruby get to be Ruby,
like PHP gets to be PHP?

My advice is that you break the cycle: come from PHP when you're using
PHP, and come from Ruby when you're using Ruby. It makes things more
harmonious. It's also much more fair to Ruby: instead of viewing Ruby
as "broken" because it doesn't do X like PHP, Y like C++, or Z like
Perl, you get to explore and understand Ruby on its own terms.

That doesn't mean you never think anything in Ruby should be changed.
(It doesn't even mean that puts and print shouldn't be made to behave
in a bizarre manner in ERB :slight_smile: It's just an acknowledgement of the
fact that there's a design to Ruby, and of the fact that it is not
incumbent on Ruby to play the role of a language-idiom sponge.

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?

Yes, you should be able to do: $stdout = _erbout and have stuff go
to that stream if _erbout is a StringIO object.

I'm not sure about the template/program distinction. If you've got:

    Hello, my name is <%= name %>.

and call that a "program", to me it implies that "Hello, my name is"
is part of a programming language. Also I don't think redirecting
$stdout causes a template not to be a template. But I may be looking
at it wrongly (and it's more or less "academic", as they say :slight_smile:

David

···

On Sun, 11 Sep 2005, Mark Hubbart wrote:

--
David A. Black
dblack@wobblini.net

Mark Hubbart wrote:

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)

Observant. The JSP way (which is also the Rails way) embraces MVC, and avoids sticking domain logic in the template. The kind of code that sits in a Rails view is "for foo in barlist" and "link_to :action => 'someaction'". (In truth, the design of the JSP spec didn't really have this in mind; rather, it flowed out through a couple years in the "real world" as the most natural usage of JSP.)

#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"

It really is about inconsistency in behavior. Java falls prey to inconsistent behavior for the sake of making some particular special case "so easy you don't have to think about it." For me, Ruby was sort of a safe haven from that.

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?

That's not an altogether horrible idea. Changing mindsets about ERB turns it into one big embedded interpreter (capturing output the same way that Kernel#` does) rather than one big string interpolation. I would then be more likely to want *every* form of standard output to get captured, then -- whether from puts, print, p, $stdout.write, log4r, ... and I don't really want that. :confused:

I have a proposal, too. What if ERB exposed (and documented) eputs, eprint, and ep methods to the templates? I would be coo wit dat.

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

Nope, all very sensical.

Devin
oops! my opinion's showing. *zip*

In article <de63abca05091103111ef36f79@mail.gmail.com>,
discordantus@gmail.com says...

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.

Excellent summary. As someone who came from neither PHP nor JSP (PL/I,
if you must know), and whose first exposure to ERB was Rails, my mental
model is #2, even though deep down I know it's actually implemented as
#1. Which is why "puts" outputting to the doc, not stdout, is the non-
anomalous (omalous?) behavior to my mind.

···

--
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

Hi,

Hi --

> 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"

Yes, that captures the problem exactly. #{} executes what's in side
it and interpolates the value as a string, and having it do otherwise
based on the name of the method would be anomalous and awkward.

> 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.

If you want puts and print to behave anomalously, that's OK. But
there's no mystery to why they don't. They behave exactly the same
way every other method behaves. I don't think the *absence* of a
"magic" or special case should be a source of wonder :slight_smile:

That's the thing; to those of us who don't see it as just "fancy
string interpolation", the *current* behavior is anomalous, not the
suggested behavior. The current behavior actually seems rather magic,
until you discover why it behaves that way, after which it just feels
poorly implemented.

> 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.

The "coming from PHP" argument, I fear, is illogical. It predicates
that whoever designed templating in PHP was empowered to make
decisions for authors of future templating systems -- and by
extension, presumably, everything else about future programming
languages. That, in turn, would mean that there could be no further
languages after PHP.

In fact, there could only be one language at all, because the people
who learned the first language would "come from" that language and
therefore be constrained to do things as they were done in that
language.

I know you're not really suggesting that Ruby become PHP. But the
"coming from" thing, while interesting in terms of our various
biographies, has nothing to do with Ruby per se, and has no persuasive
weight when it comes to discussing possible changes to Ruby. How
could it? How could Ruby do everything everyone did in the last
language they used? And *why* should Ruby play that kind of
self-effacing, chameleon-like role? Why doesn't Ruby get to be Ruby,
like PHP gets to be PHP?

My advice is that you break the cycle: come from PHP when you're using
PHP, and come from Ruby when you're using Ruby. It makes things more
harmonious. It's also much more fair to Ruby: instead of viewing Ruby
as "broken" because it doesn't do X like PHP, Y like C++, or Z like
Perl, you get to explore and understand Ruby on its own terms.

That doesn't mean you never think anything in Ruby should be changed.
(It doesn't even mean that puts and print shouldn't be made to behave
in a bizarre manner in ERB :slight_smile: It's just an acknowledgement of the
fact that there's a design to Ruby, and of the fact that it is not
incumbent on Ruby to play the role of a language-idiom sponge.

I provided the "coming from PHP" simply for context. I know that
"language X does it this way" is not a final argument for making Ruby
do things a certain way.

However, if the (arguably) definitive templating language has a
certain major concept built in, then it could merit a look if you are
building a system that is basically the same.

> 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?

Yes, you should be able to do: $stdout = _erbout and have stuff go
to that stream if _erbout is a StringIO object.

I'm not sure about the template/program distinction. If you've got:

    Hello, my name is <%= name %>.

and call that a "program", to me it implies that "Hello, my name is"
is part of a programming language. Also I don't think redirecting
$stdout causes a template not to be a template. But I may be looking
at it wrongly (and it's more or less "academic", as they say :slight_smile:

I think I may have explained myself poorly last night. (it was after
3, after all!) I'll give one more try.

In PHP, pages are being streamed from the server to the client. At the
beginning of a PHP document, you are in streaming text mode; all the
characters are printed to the output stream until the sequence "<?" is
reached. Then, everything is considered code up until the closing
bracket. Any print/echo statements are printed directly to the output
stream, in sync with the surrounding text. In fact, the "<?=foo?>"
type construction that some here are saying should be used instead of
print/puts is considered a shorthand replacement for "<? echo foo ?>",
and isn't even available unless short tags are turned on.

So that's the PHP background that I was referring to. Now the StringIO idea...

A simple ERB template that looks like this:

···

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

On Sun, 11 Sep 2005, Mark Hubbart wrote:

---
<% who = "world" %>
Hello, <%=who%>!
---

Gets translated into code something like this:
---
_erbout = ""
who = "world"
_erbout.concat "Hello, "
_erbout.concat who.to_s
_erbout.concat "!"
_erbout
---

Using the streaming output idea, this could be expected to look more like this:

---
who = "world"
print "Hello, "
print who.to_s
print "!"
---

One could capture the output by setting the default output to a
StringIO; this is similar to what I did in a previous solution. It is
rather easy to put together a simple, thread-safe version that does
this. Currently, the default is to capture the output as a string, but
a webserver-related use would probably just send the output directly
to the browser *as it is being output*, rather than building the
string and sending it all at once.

I don't see this as being about adding "magic" to the implementation.
If you are of the mindset that the template is concatting to a string,
the puts idea doesn't make sense; but if you see it as printing to an
output stream (with the whole _erbout thing just being an
implementation issue), then the lack of a working print/puts is what
doesn't make sense.

cheers,
Mark

One could capture the output by setting the default output to a
StringIO; this is similar to what I did in a previous solution. It is
rather easy to put together a simple, thread-safe version that does
this. Currently, the default is to capture the output as a string, but
a webserver-related use would probably just send the output directly
to the browser *as it is being output*, rather than building the
string and sending it all at once.

I don't see this as being about adding "magic" to the implementation.
If you are of the mindset that the template is concatting to a string,
the puts idea doesn't make sense; but if you see it as printing to an
output stream (with the whole _erbout thing just being an
implementation issue), then the lack of a working print/puts is what
doesn't make sense.

Indeed, their are certain efficiencies not having to pre-generate all output
before transmission. Think file downloads, dynamic image generation etc.

As a general tool, being able to reassign STDOUT/STDIN/STDERR to an IO would
be very powerfull.

means that its natural to think of all program output going 'to a web
browser' rather than to a console.

···

From my perspective, ERB's main usage is as a dynamic web page generator

Hi --

Hi,

If you want puts and print to behave anomalously, that's OK. But
there's no mystery to why they don't. They behave exactly the same
way every other method behaves. I don't think the *absence* of a
"magic" or special case should be a source of wonder :slight_smile:

That's the thing; to those of us who don't see it as just "fancy
string interpolation", the *current* behavior is anomalous, not the
suggested behavior. The current behavior actually seems rather magic,
until you discover why it behaves that way, after which it just feels
poorly implemented.

When a method is called in a <%= %> block, that part of the template
gets filled in with a string representation of its return value. This
behavior, as far as I know, is consistent across all method calls. If
any one or two methods get special treatment, that's an anomaly (or
exception, or special case, or whatever). That's all I mean. There
is *already* a technical principle at work.

[...]

I don't see this as being about adding "magic" to the implementation.
If you are of the mindset that the template is concatting to a string,
the puts idea doesn't make sense; but if you see it as printing to an
output stream (with the whole _erbout thing just being an
implementation issue), then the lack of a working print/puts is what
doesn't make sense.

If you decide a priori that ERB is a failed implementation of
something other than itself, rather than a successful implementation
of what it actually is, then of course you will conclude that it needs
to be changed :slight_smile: But I don't know of any reason to think that the
_erbout design is a failed implementation of an output stream, rather
than a successful implementation of a string buffer. (It's more than
possible that I'm not familiar with all the past discussions and
statements from the author(s) though.)

In any case, I think the wind-up toy has hit the wall, and I'd like to
turn it around so it can keep moving. I guess the main thing I'd like
to see, if ERB is to gain a way to do the kind of streaming you're
describing, would be for it to happen without loss: that is, without
loss of consistency (don't just shoehorn the behavior into methods
that already have a clearly defined behavior) and without loss of
functionality (make sure that stringwise template-filling is not
discarded or made difficult).

David

···

On Mon, 12 Sep 2005, Mark Hubbart wrote:

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

--
David A. Black
dblack@wobblini.net