Hi,

On 9/11/05, David A. Black <dblack / wobblini.net> wrote:
> Hi --
> 
> On Sun, 11 Sep 2005, 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)
> > #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 :-)

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

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