[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

delayed string interpolation

Navindra Umanee

2/7/2005 5:24:00 AM

Hi,

I'm generating an HTML header as a String that makes heavy use of
interpolation. Essentially I have something like:

def make_html_header()
str <<END
blah #{blah} blah #{blah} blah #{blah}
END
end

This works great. Most of the interpolations are essentially
configuration parameters that I've elegantly stuffed into the instance
variables of a Singleton class, some are method invocations. These
parameters don't change often, if at all, and the header is more or
less identical for each HTML page that is generated.

So I would like to generate the header once and stuff it in an
instance variable. However, there are one or two variable
interpolations that are unique to each page e.g. the title of the
page.

How can I specify that some interpolations should be interpolated
immediately whilst a few others should be delayed until the next time
the String is evaluated? I can think of some hacky ways i.e. doing
subsequent string processing and substitions, I'm just wondering if
there is a more elegant way.

Also, where is the "<<MARKER" syntax (nothing in ri?) and Ruby string
interpolation officially documented, if anywhere?

Thanks,
Navin.





13 Answers

Navindra Umanee

2/7/2005 5:36:00 AM

0

> the String is evaluated? I can think of some hacky ways i.e. doing
> subsequent string processing and substitions, I'm just wondering if
> there is a more elegant way.

To add to that, I thought about leaving a few "%s" in the string and
replacing them later, but that too seems ugly because I have feed in
variables in order and sometimes even repeatedly.

Thanks,
Navin.


Bill Kelly

2/7/2005 6:24:00 AM

0

From: "Navindra Umanee" <navindra@cs.mcgill.ca>
>
> I'm generating an HTML header as a String that makes heavy use of
> interpolation. Essentially I have something like:
>
> def make_html_header()
> str <<END
> blah #{blah} blah #{blah} blah #{blah}
> END
> end
>
> This works great. Most of the interpolations are essentially
> configuration parameters that I've elegantly stuffed into the instance
> variables of a Singleton class, some are method invocations. These
> parameters don't change often, if at all, and the header is more or
> less identical for each HTML page that is generated.
>
> So I would like to generate the header once and stuff it in an
> instance variable. However, there are one or two variable
> interpolations that are unique to each page e.g. the title of the
> page.
>
> How can I specify that some interpolations should be interpolated
> immediately whilst a few others should be delayed until the next time
> the String is evaluated? I can think of some hacky ways i.e. doing
> subsequent string processing and substitions, I'm just wondering if
> there is a more elegant way.

I dunno if this counts as elegant or not, :)
but a couple years ago, I used:

class String
def reeval(b = TOPLEVEL_BINDING)
eval(%Q{<<"END_REEVAL"\n} + self + "\nEND_REEVAL\n", b)
end
end

in similar circumstances. I would just put a backslash
in front of any interpolations I wanted to defer. Then
I'd call reeval at some later point at run-time. I would
also pass in a binding, so that my (deferred) interpolations
would have access to instance methods of the class performing
the reeval.

I'd described it in more detail in:
http://ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-...
(the external links in that post no longer work, sorry.)


HTH,

Regards,

Bill




Charles Mills

2/7/2005 6:30:00 AM

0


Navindra Umanee wrote:
> > the String is evaluated? I can think of some hacky ways i.e. doing
> > subsequent string processing and substitions, I'm just wondering if
> > there is a more elegant way.
>
> To add to that, I thought about leaving a few "%s" in the string and
> replacing them later, but that too seems ugly because I have feed in
> variables in order and sometimes even repeatedly.
>

You could write your interpolater. Here is an example:

$ irb
irb(main):001:0> require 'tmp.rb'
=> true
irb(main):002:0> s = ":hey :day"
=> ":hey :day"
irb(main):003:0> s.interpolate(:hey => "hello", :day=>"yo")
=> "hello yo"

$ cat tmp.rb
class String
def interpolate(hash)
self.gsub(/:(\w+)/) { hash[$1.to_sym] }
end
def interpolate!(hash)
self.gsub!(/:(\w+)/) { hash[$1.to_sym] }
end
end

$

-Charlie

Robert Klemme

2/7/2005 9:04:00 AM

0


"Navindra Umanee" <navindra@cs.mcgill.ca> schrieb im Newsbeitrag
news:20050207002403.A12145@cs.mcgill.ca...
> Hi,
>
> I'm generating an HTML header as a String that makes heavy use of
> interpolation. Essentially I have something like:
>
> def make_html_header()
> str <<END
> blah #{blah} blah #{blah} blah #{blah}
> END
> end
>
> This works great. Most of the interpolations are essentially
> configuration parameters that I've elegantly stuffed into the instance
> variables of a Singleton class, some are method invocations. These
> parameters don't change often, if at all, and the header is more or
> less identical for each HTML page that is generated.
>
> So I would like to generate the header once and stuff it in an
> instance variable. However, there are one or two variable
> interpolations that are unique to each page e.g. the title of the
> page.
>
> How can I specify that some interpolations should be interpolated
> immediately whilst a few others should be delayed until the next time
> the String is evaluated? I can think of some hacky ways i.e. doing
> subsequent string processing and substitions, I'm just wondering if
> there is a more elegant way.

One option is two levels of interpolation:

generator = "my gen"
application = "my test app"
header = "\"<html>.....#{generator} .... #{application} .... \#{title}\""
....
title = "foo"
real_header = eval header

Or you create a lambda for that:

def create_header(generator, application)
eval "lambda {|title| \"<html>.....#{generator} .... #{application} ....
\#{title}\" }"
end

>> x = create_header generator, application
=> #<Proc:0x100c2990@(eval):1>
>> x.call "foo"
=> "<html>.....my gen .... my test app .... foo"

> Also, where is the "<<MARKER" syntax (nothing in ri?) and Ruby string
> interpolation officially documented, if anywhere?

http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_stdtyp...

Kind regards

robert

Martin DeMello

2/7/2005 9:59:00 AM

0

Robert Klemme <bob.news@gmx.net> wrote:
>
> One option is two levels of interpolation:
>
> generator = "my gen"
> application = "my test app"
> header = "\"<html>.....#{generator} .... #{application} .... \#{title}\""
> ...
> title = "foo"
> real_header = eval header

By this point I'd have switched to a proper template engine, just to
make sure the eval didn't bring in some hairy corner cases (am I being
overly paranoid?) I was going to suggest this earlier, in fact, but I
felt amrita was probably a bit too heavy for this case.

martin

James Gray

2/7/2005 2:12:00 PM

0

On Feb 7, 2005, at 4:00 AM, Martin DeMello wrote:

> Robert Klemme <bob.news@gmx.net> wrote:
>>
>> One option is two levels of interpolation:
>>
>> generator = "my gen"
>> application = "my test app"
>> header = "\"<html>.....#{generator} .... #{application} ....
>> \#{title}\""
>> ...
>> title = "foo"
>> real_header = eval header
>
> By this point I'd have switched to a proper template engine, just to
> make sure the eval didn't bring in some hairy corner cases (am I being
> overly paranoid?) I was going to suggest this earlier, in fact, but I
> felt amrita was probably a bit too heavy for this case.

This was my first thought when reading the original message as well.
Might want to have a look at erb in the standard library.

James Edward Gray II



Navindra Umanee

2/7/2005 4:06:00 PM

0

Hi,

Thanks a lot for both eval solutions (exactly what I was looking for)
and the template suggestion.

I still have nightmares about Zope's DTML, so I wasn't sure I wanted
to go with templating this time. I think as I encounter more and more
issues however I might have to consider to a templating solution
afterall.

Of the two templating solutions suggested so far, Amrita seems too
indirect for my tastes. I'd rather directly code what my HTML looks
like than have it be the result of some fancy/unknown
computation... Not to mention that's just going to come back and bite
me when the implementation changes (or doesn't change).

As for ERB, I'm not yet sure how it's better or easier than the simple
2-level string eval I wanted to do. It seems pretty much the same
except with different enclosing tags and more overhead. ERB::Util has
some interesting subroutines though. I'll have to look more closely
to understand the advantages.

Thanks,
Navin.





Navindra Umanee

2/7/2005 4:52:00 PM

0

Bill Kelly <billk@cts.com> wrote:
> I dunno if this counts as elegant or not, :)
> but a couple years ago, I used:
>
> class String
> def reeval(b = TOPLEVEL_BINDING)
> eval(%Q{<<"END_REEVAL"\n} + self + "\nEND_REEVAL\n", b)
> end
> end

I have to say this is such a really neat hack... it says so much
about Ruby too.

I had a hard time understanding it until I realised that the first
END_REEVAL doesn't need to be in quotes. Writing it as:

eval("<<END_REEVAL\n" + self + "\nEND_REEVAL\n", b)

seems to work just as well. Any reason you did it that way?

Cheers,
Navin.


Bill Kelly

2/7/2005 5:24:00 PM

0

From: "Navindra Umanee" <navindra@cs.mcgill.ca>
> Bill Kelly <billk@cts.com> wrote:
> > I dunno if this counts as elegant or not, :)
> > but a couple years ago, I used:
> >
> > class String
> > def reeval(b = TOPLEVEL_BINDING)
> > eval(%Q{<<"END_REEVAL"\n} + self + "\nEND_REEVAL\n", b)
> > end
> > end
>
> I have to say this is such a really neat hack... it says so much
> about Ruby too.

Thanks! And, indeed: thanks Matz !! =D

> I had a hard time understanding it until I realised that the first
> END_REEVAL doesn't need to be in quotes. Writing it as:
>
> eval("<<END_REEVAL\n" + self + "\nEND_REEVAL\n", b)
>
> seems to work just as well. Any reason you did it that way?

I'm guessing I got into the habit early on to remind
myself that ruby lets you specify single-quote semantics
if you want them, like:

x = <<'ENDTEXT'
now things like \n are literal
as they would be in 'single quote' strings
ENDTEXT

So I probably used <<"END_REEVAL" trying to be specific
about my request for double-quote semantics.... However
it seems to have just become a habit. :) Maybe I'll
stop doing it... Hehe..


Regards,

Bill




Navindra Umanee

2/7/2005 6:08:00 PM

0

Bill Kelly <billk@cts.com> wrote:
> I'm guessing I got into the habit early on to remind
> myself that ruby lets you specify single-quote semantics
> if you want them, like:
>
> x = <<'ENDTEXT'
> now things like \n are literal
> as they would be in 'single quote' strings
> ENDTEXT

Oh, hmph. I didn't even know that. It's not really documented is it?

I didn't even realise \n would be converted to a newline in heredoc as
well. Going to have to be really really careful about things like
user-input, I guess.

Thanks for the useful information. :)

Cheers,
Navin.