[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

delaying string evaluation

Navindra Umanee

7/16/2005 8:24:00 AM

Hi,

I would like to partially expand a string and then further expand it
later on when more information is available. I am currently using
string interpolation with a reeval method suggested by Bill Kelly.

class String
def reeval(b = TOPLEVEL_BINDING)
eval("<<END_REEVAL\n" + self + "\nEND_REEVAL\n", b).chomp!
end
end

This lets me do stuff like this:

expanded = "one"
delayed = "two"

s = "#{expanded} \#{delayed}" # => "one #{delayed}"
s = s.reeval(binding) # => "one two"

As a more complex example, this is a string I wish to partially expand:

options = [ 10, 20, 30, 40, 50 ]

combobox =<<"END"
...
#{options.map {|n|
%{<option value="#{n}"\#{thread_threshold == n ? ' SELECTED' : ''}>#{n} comments</option>}
}.join("\n")
}
...
END

The idea is to create the combobox and then later insert the SELECTED
part, when I know the value of thread_threshold. Unfortunately, the
above partial expansion is:

<option value="10"#{thread_threshold == n ? ' SELECTED' : ''}>10 comments</option>
<option value="20"#{thread_threshold == n ? ' SELECTED' : ''}>20 comments</option>
<option value="30"#{thread_threshold == n ? ' SELECTED' : ''}>30 comments</option>
<option value="40"#{thread_threshold == n ? ' SELECTED' : ''}>40 comments</option>
<option value="50"#{thread_threshold == n ? ' SELECTED' : ''}>50 comments</option>

This would have been great, except that I have all these values for
'n' that have been left out of the expressions that I want to evaluate
afterwards. That is, I want the partial expansion to be this:

<option value="10"#{thread_threshold == 10 ? ' SELECTED' : ''}>10 comments</option>
<option value="20"#{thread_threshold == 20 ? ' SELECTED' : ''}>20 comments</option>
<option value="30"#{thread_threshold == 30 ? ' SELECTED' : ''}>30 comments</option>
<option value="40"#{thread_threshold == 40 ? ' SELECTED' : ''}>40 comments</option>
<option value="50"#{thread_threshold == 50 ? ' SELECTED' : ''}>50 comments</option>

and later when I reeval the string:

thread_threshold = 50
combobox.reeval(binding)

the result should be:

<option value="10">10 comments</option>
<option value="20">20 comments</option>
<option value="30">30 comments</option>
<option value="40">40 comments</option>
<option value="50" SELECTED>50 comments</option>

Anyone have any ideas for how I can get a correct partial expansion?

I have a lambda/closure feeling about how this should work, but I
can't quite see the solution in the context of strings.

Thanks,
Navin.


19 Answers

Eric Hodel

7/16/2005 9:11:00 AM

0

On 16 Jul 2005, at 01:23, Navindra Umanee wrote:

> Hi,
>
> I would like to partially expand a string and then further expand it
> later on when more information is available. I am currently using
> string interpolation with a reeval method suggested by Bill Kelly.

is sprintf (aka %) unable to fulfill your requirements?

> class String
> def reeval(b = TOPLEVEL_BINDING)
> eval("<<END_REEVAL\n" + self + "\nEND_REEVAL\n", b).chomp!
> end
> end
>
> This lets me do stuff like this:
>
> expanded = "one"
> delayed = "two"
>
> s = "#{expanded} \#{delayed}" # => "one #{delayed}"
> s = s.reeval(binding) # => "one two"

s = "#{expanded} %s"
s = s % delayed

> As a more complex example, this is a string I wish to partially
> expand:
>
> options = [ 10, 20, 30, 40, 50 ]
>
> combobox =<<"END"
> ...
> #{options.map {|n|
> %{<option value="#{n}"\#{thread_threshold == n ? ' SELECTED' : ''}
> >#{n} comments</option>}
> }.join("\n")
> }
> ...
> END

combobox = <<END
...
%s
...
END

opts = options.map { |n| "<option value=\"#{n}\"%s>#{n} comments</
option>" }.join "\n"

combobox = combobox % opts

> and later when I reeval the string:
>
> thread_threshold = 50
> combobox.reeval(binding)
>
> the result should be:
>
> <option value="10">10 comments</option>
> <option value="20">20 comments</option>
> <option value="30">30 comments</option>
> <option value="40">40 comments</option>
> <option value="50" SELECTED>50 comments</option>

Hrm, maybe not...

How about:

opts = options.map { |n| "<option value=\"#{n}\"SEL_#{n}>#{n}
comments</option>" }.join "\n"

combobox = combobox % opts

combobox.gsub!(/SEL_(\d+)/) do
thread_threshold == $1.to_i ? ' SELECTED' : ''
end

> Anyone have any ideas for how I can get a correct partial expansion?
>
> I have a lambda/closure feeling about how this should work, but I
> can't quite see the solution in the context of strings.

I think the reeval thing is the wrong way to go about it. I find it
much more useful to use a library that generates HTML programatically
or from a template than to try fancy substitution tricks (unless its
really small). Eventually you end up with either a template language
or programatic HTML generation in the end.

--
Eric Hodel - drbrain@segment7.net - http://se...
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04



Pit Capitain

7/16/2005 11:48:00 AM

0

Navindra Umanee schrieb:
> I would like to partially expand a string and then further expand it
> later on when more information is available. (...)
>
> combobox =<<"END"
> ...
> #{options.map {|n|
> %{<option value="#{n}"\#{thread_threshold == n ? ' SELECTED' : ''}>#{n} comments</option>}
|
#{n}
> }.join("\n")
> }
> ...
> END
>
> (...)

Change the second "n" to "#{n}", just like the others.

Regards,
Pit


Daniel Brockman

7/16/2005 1:33:00 PM

0

Ara.T.Howard

7/16/2005 2:20:00 PM

0

Navindra Umanee

7/16/2005 3:04:00 PM

0

Pit Capitain <pit@capitain.de> wrote:
> Change the second "n" to "#{n}", just like the others.

Hah! I had no idea that would work.

Thanks,
Navin.


Navindra Umanee

7/16/2005 3:35:00 PM

0

Eric Hodel <drbrain@segment7.net> wrote:
> > I would like to partially expand a string and then further expand it
> > later on when more information is available. I am currently using
> > string interpolation with a reeval method suggested by Bill Kelly.
>
> is sprintf (aka %) unable to fulfill your requirements?

I am aware that there are solutions such as these, but I keep finding
the string interpolation solution to be the most attractive/elegant
one as a general solution.

> s = "#{expanded} %s"
> s = s % delayed

If there are multiple occurrences of delayed, you have to repeatedly
apply it in the second line in proper order, and if you have any
independent occurrence of % in the string, I'm not entirely sure how
to escape it. This solution isn't very symmetric either.

> I think the reeval thing is the wrong way to go about it.

What do you have against reeval? I have been trying to convince
myself there are better solutions, but after looking I keep coming
back to it. It just seems more natural or at least it works as a
general solution.

> I find it much more useful to use a library that generates HTML
> programatically

You mean like the CGI.* stuff or Amrita? CGI.* stuff looks very
painful and verbose to use, and Amrita, while it looks interesting in
simple cases, gives me the feeling that I will have to use too many
contortions to get it to work the way I want.

I mean constructs like <p id="var"></p> in Amrita look brilliant.
But then you get to stuff like <a id='a2' amrita:type='link'>Amrita2</a>
which starts to look more ugly and as you get to complex conditional
code generation it gets worse and worse.

It just seems easier to "just do it the way I want" in Ruby instead of
artificially constraining myself in Amrita, since I have the feeling I
would have to resort to Ruby programming in addition to Amrita just to
get the sort of effects I want anyway.

It could well be I'm not giving Amrita its due. I have been
considering re-implementing my stuff in it, but at the depressing
prospect, I thought I'd try making the string interpolation template
stuff more elegant (which it obviously isn't yet).

> or from a template than to try fancy substitution tricks (unless its
> really small). Eventually you end up with either a template language
> or programatic HTML generation in the end.

I agree that this is what I will end up with -- I'm just trying to get
it to work in the most elegant way I can.

What do you use?

Cheers,
Navin.


Navindra Umanee

7/16/2005 3:59:00 PM

0

Ara.T.Howard <Ara.T.Howard@noaa.gov> wrote:
> why not make up a mini interpolator?
>
> ~ > cat a.rb
> class String
> def expand! h = {}
> gsub!(%r/:\w+/o){|k| h[k.delete(':').intern] || k}
> end
> def expand(*a, &b)
> dup.expand!(*a, &b); self
> end
> end

Interesting.

As a general solution I'm not sure it's what I want.
I am also expanding complex objects (e.g #{posting.attribute}) and
with your custom interpolator I would end up either having to copy
information around (e.g. :posting_attribute => posting.attribute) or
using it with the regular delayed string interpolation strategy anyway.

Thanks,
Navin.


James Gray

7/16/2005 5:18:00 PM

0

On Jul 16, 2005, at 10:34 AM, Navindra Umanee wrote:

>> Eventually you end up with either a template language
>> or programatic HTML generation in the end.
>>
>
> I agree that this is what I will end up with -- I'm just trying to get
> it to work in the most elegant way I can.

Are you aware that Ruby ships with a templating language in its
standard library?

irb(main):001:0> require "erb"
=> true
irb(main):002:0> expand, delay = "Expanded!", "Delayed!"
=> ["Expanded!", "Delayed!"]
irb(main):003:0> template = "#{expand} <%= delay %>"
=> "Expanded! <%= delay %>"
irb(main):004:0> ERB.new(template).result(binding)
=> "Expanded! Delayed!"

James Edward Gray II



Navindra Umanee

7/16/2005 8:24:00 PM

0

James Edward Gray II <james@grayproductions.net> wrote:
> Are you aware that Ruby ships with a templating language in its
> standard library?

Yes I know of ERB. I am not sure what the advantage of using a
different syntax is, when I can simply use the same Ruby syntax but
escape it when necessary.

<%= delay %> is at least as verbose as \#{delay}.

What advantage do you see to using a new syntax instead of just Ruby?

Cheers,
Navin.


James Gray

7/16/2005 8:39:00 PM

0

On Jul 16, 2005, at 3:23 PM, Navindra Umanee wrote:

> James Edward Gray II <james@grayproductions.net> wrote:
>
>> Are you aware that Ruby ships with a templating language in its
>> standard library?
>>
>
> Yes I know of ERB. I am not sure what the advantage of using a
> different syntax is, when I can simply use the same Ruby syntax but
> escape it when necessary.
>
> <%= delay %> is at least as verbose as \#{delay}.
>
> What advantage do you see to using a new syntax instead of just Ruby?

Off the top of my head:

* ERb's <% ... %> flow control construct.
* The ability to control spacing as you can with the special string
ERb's constructor takes.
* ERb's handy "% ... entire line of code ..." shortcut.
* ERb's utility methods for HTML and URL escaping.

But if you've found what works for you, far be it from me to
complain. I was just making sure you were aware of another option.

James Edward Gray II