Clean way to dynamically expand string with "#{expression}"?

T

Taisuke Yamada

Hi.

I'm trying to find a clean way to expand string with "#{...}".
What I want to do is essentially as follows:

data = 123
expr = 'data = #{data}'

puts dosomething(expr)

and get 'data = 123' as a result. Actual content of 'expr' can
be anything, as long as it is a String object.

I came up with following:

puts eval(%Q{"#{expr.gsub('"', '\"')}"})

But this is ugly, and I'm wondering if there's some other,
cleaner way to do the same thing.

Can anyone enlighten me?

Best Regards,
 
D

David A. Black

Hi --

Hi.

I'm trying to find a clean way to expand string with "#{...}".
What I want to do is essentially as follows:

data = 123
expr = 'data = #{data}'

puts dosomething(expr)

and get 'data = 123' as a result. Actual content of 'expr' can
be anything, as long as it is a String object.

Can't you just double-quote your string?

expr = "data = #{data}"


David
 
D

dm1

David said:
Hi --



Can't you just double-quote your string?

expr = "data = #{data}"


David


I guess what Taisuke Yamada want is 'interpolation on demand', as opposed to
interpolation when the string is first read by the ruby interpreter. This is
needed when you want to interpolate strings that are builded from external
sources. This subject was actually already discussed in ruby-talk/129959
(delayed string interpolation)

Denis
 
A

Ara.T.Howard

Hi.

I'm trying to find a clean way to expand string with "#{...}".
What I want to do is essentially as follows:

data = 123
expr = 'data = #{data}'

puts dosomething(expr)

and get 'data = 123' as a result. Actual content of 'expr' can
be anything, as long as it is a String object.

I came up with following:

puts eval(%Q{"#{expr.gsub('"', '\"')}"})

But this is ugly, and I'm wondering if there's some other,
cleaner way to do the same thing.

Can anyone enlighten me?

this is a stupid question by why not simply use double quotes?

data = 123
expr = "data = #{ data }"
puts dosomething(expr)

??

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| although gold dust is precious, when it gets in your eyes, it obstructs
| your vision. --hsi-tang
===============================================================================
 
T

Taisuke Yamada

Yes, what I was looking for is 'perfect interpolation on demand'
that'll work whatever content is in interpolated string. I guess

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

is the best (and robust) solution available as you can choose
random string that probably won't show up in interpolated string.

Many interpolation code, including mine and several people
suggested will break if '"' or certain string is contained
in string to interpolate.

Practically, it doesn't need to be perfect, but it was my
technical interest that there may be better way to do it.
Above code is cleaner and more robust, so I'll go with it.
Thanks for the pointer.

BTW, I'm using this on-demand interpolation to supply options
dynamically to random shell commands read from configuration
file. Using template processing library was bit overkill, so
I went with eval-based one liner to do the job.
 
D

dm1

Taisuke said:
Yes, what I was looking for is 'perfect interpolation on demand'
that'll work whatever content is in interpolated string. I guess

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

is the best (and robust) solution available as you can choose
random string that probably won't show up in interpolated string.

Ah the quest for perfection, we are still not there :

irb(main):001:0> str = "blah\nEND_REEVAL\n catch me if you can"
=> "blah\nEND_REEVAL\n catch me if you can"
irb(main):002:0> eval("<<END_REEVAL\n" + str + "\nEND_REEVAL\n", binding)
NameError: undefined local variable or method `can' for main:Object
from (irb):5
from (irb):2


i.e. it will fail for every string containing the "\nEND_REEVAL\n" string
delimiter.
Many interpolation code, including mine and several people
suggested will break if '"' or certain string is contained
in string to interpolate.

Practically, it doesn't need to be perfect, but it was my
technical interest that there may be better way to do it.
Above code is cleaner and more robust, so I'll go with it.
Thanks for the pointer.

I do share that technical interest. I really wonder if there is a one liner
for 'perfect interpolation on demand'. Everything i can think of is a bit
longer. Let the quest continue :)

Ciao

Denis
 
D

Douglas Livingstone

I do share that technical interest. I really wonder if there is a one liner
for 'perfect interpolation on demand'. Everything i can think of is a bit
longer. Let the quest continue :)

The perfection might look something like this:

"string with #{data}" == 'string with #{data}'.interpolate

"abc" would just be syntax sugar for 'abc'.interpolate

I don't know how to express that in ruby though :(

Douglas
 
D

David A. Black

Hi --

The perfection might look something like this:

"string with #{data}" == 'string with #{data}'.interpolate

"abc" would just be syntax sugar for 'abc'.interpolate

I think you'd lose a lot of speed adding a method call to string
literals. I also don't think one would want the whole profile of
string behavior to be built up from a pretty marginal, fragile,
eval-based use case. The whole idea of delaying evaluation leads to
things like coupling of local variable names (one method knowing what
another's local variables will be called), which is pretty unscaleable
and shaky. It's better to leave this kind of thing in the realm of
"doing it is hard enough that we won't do it much" :)


David
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top