# Interpolation question

**URL:** <https://www.ruby-forum.com/t/interpolation-question/197027>\
**Category:** Ruby\
**Created:** [February 27, 2010, 7:59pm UTC](https://www.ruby-forum.com/t/interpolation-question/197027 "2010-02-27T19:59:14Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dudebot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e495f1/32.png) [@Dudebot](https://www.ruby-forum.com/u/Dudebot)\
**Post date:** [February 27, 2010, 7:59pm UTC](https://www.ruby-forum.com/t/interpolation-question/197027/1 "2010-02-27T19:59:14Z")

</div>

Why does

text = \<\<ENDTEXT  
this is an wibble  
of stuff bobble  
ENDTEXT

wibble = 2.0  
bobble = 3.0

newtext = text.gsub( /(.\*?)\</field\>/, “#{\1}” )

puts newtext

throw this error:  
./test.rb:13: syntax error, unexpected $undefined  
newtext = text.gsub( /(.\*?)\</field\>/, “#{\1}” )

and not interpolate to produce  
this is an 2.0  
of stuff 3.0

?

And how can I do that interpolation? (adding \s to \1, e.g. \1  
doesn’t help)

Many TIA,  
Craig

---

<div class="post-metadata">

**Author:** ![Dudebot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e495f1/32.png) [@Dudebot](https://www.ruby-forum.com/u/Dudebot)\
**Post date:** [February 27, 2010, 8:16pm UTC](https://www.ruby-forum.com/t/interpolation-question/197027/2 "2010-02-27T20:16:48Z")

</div>

On 27 févr. 2010, at 19:58, Dudebot wrote:

> newtext = text.gsub( /(.\*?)\</field\>/, “#{\1}” )

newtext = text.gsub( /(.\*?)\</field\>/, ‘\1’ )

---

<div class="post-metadata">

**Author:** ![Dudebot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e495f1/32.png) [@Dudebot](https://www.ruby-forum.com/u/Dudebot)\
**Post date:** [February 27, 2010, 8:25pm UTC](https://www.ruby-forum.com/t/interpolation-question/197027/3 "2010-02-27T20:25:35Z")

</div>

Thanks, Luc, but that’s not what I need. That produces

this is an wibble  
of stuff bobble

instead of

this is an 2.0  
of stuff 3.0

I need it to interpolate the value of the expressions, not the  
expressions themselves. Is this not possible in Ruby?

---

<div class="post-metadata">

**Author:** ![Dudebot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e495f1/32.png) [@Dudebot](https://www.ruby-forum.com/u/Dudebot)\
**Post date:** [February 27, 2010, 9:48pm UTC](https://www.ruby-forum.com/t/interpolation-question/197027/4 "2010-02-27T21:48:40Z")

</div>

First, don’t top-post (like this). It’s annoying.

On Saturday 27 February 2010 01:25:02 pm Dudebot wrote:

> I need it to interpolate the value of the expressions, not the  
> expressions themselves. Is this not possible in Ruby?

It’s certainly possible, but not with gsub. Think about what you’re  
asking.:

newtext = text.gsub( some\_regex, some\_string )

By the time gsub sees those arguments, both some\_regex and some\_string  
will  
have been evaluated. That is, the standard Ruby string interpolation  
will have  
already resolved. As an example:

count = 0  
newtext = text.gsub( /(.\*?)\</field\>/, “#{count+=1}” )

You’ll just get 1, not 1,2 as you might expect. Think about why that  
happens.

It happens that way because by the time gsub gets called, “#{count+=1}”  
has  
already been replaced by the results of evaluating that expression, and  
is now  
just a string.

What you want is to replace it with the results of evaluating a block,  
which  
is an entirely different animal. It’s possible gsub can do that, but  
before I  
provide any kind of solution there, are you sure this is how you want to  
do  
this? Because it looks like you’re trying to use regexes to parse XML.

DO NOT USE REGEX TO PARSE XML.

It is the wrong tool for the job. There are a billion special-cases in  
XML,  
let alone HTML. It may be possible to write a correct regex, but you  
won’t be  
able to – nor would I want to try. There are already dozens of  
libraries to  
do this for you, it’s a thoroughly-solved problem, and there’s no good  
reason  
to try to do it again yourself… I’d suggest Nokogiri.

Once you’ve actually parsed it, the solution is much easier:

# It’s not valid XML without a root element.

# It doesn’t have to be called body, but it has to exist.

text = “#{text}”  
doc = Nokogiri.parse(text)  
(doc / ‘field’).each{|e| e.content = eval e.text}

Of course, the use of ‘eval’ should scare you. Your original  
implementation,  
and this one, is ridiculously insecure. Don’t use local variables for  
this!  
(That comes up about as often on this list as people trying to use  
regexes to  
parse XML, and it makes about as much sense.) Instead, use a hash:

h = {‘wibble’ =\> 2.0, ‘bobble’ =\> 3.0}  
(doc / ‘field’).each{|e| e.content = h[e.text]}

And to turn it back into XML:

doc.to\_s

---

<div class="post-metadata">

**Author:** ![Dudebot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e495f1/32.png) [@Dudebot](https://www.ruby-forum.com/u/Dudebot)\
**Post date:** [February 27, 2010, 9:45pm UTC](https://www.ruby-forum.com/t/interpolation-question/197027/5 "2010-02-27T21:45:38Z")

</div>

Paul H. wrote:

> Seeeeems like you’re looking for eval.
> 
> Of course, this mean you absolutely trust your input.
> 
> Alternatively, nothing stops you from just storing the values in a hash,  
> doing something likke
> 
> fields = {“wibble” =\> 2.0, “bobble” =\> 3.0}  
> newtext = text.gsub(%r{(.\*?)}) {|value| fields[value]}
> 
> _Still_ this assumes that you absolutely know your input will always be  
> in this exact format, otherwise (for example if you’re not the person  
> generating the input) use an actual XML parser (like Nokogiri).
> 
> Dudebot wrote:
> 
> > Thanks, Luc, but that’s not what I need. That produces
> > 
> > this is an wibble  
> > of stuff bobble
> > 
> > instead of
> > 
> > this is an 2.0  
> > of stuff 3.0
> > 
> > I need it to interpolate the value of the expressions, not the  
> > expressions themselves. Is this not possible in Ruby?

Wow let me try that post again.

$1, $2, etc are the capture globals; the value passed to the block  
passed to gsub is the match itself.

So you want text.gsub(%r{(.\*?)}) {fields[$1]}

---

<div class="post-metadata">

**Author:** ![Dudebot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e495f1/32.png) [@Dudebot](https://www.ruby-forum.com/u/Dudebot)\
**Post date:** [February 27, 2010, 9:55pm UTC](https://www.ruby-forum.com/t/interpolation-question/197027/6 "2010-02-27T21:55:41Z")

</div>

On Feb 27, 12:58 pm, Dudebot [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> newtext = text.gsub( /(.\*?)\</field\>/, “#{\1}” )
> 
> ?
> 
> And how can I do that interpolation? (adding \s to \1, e.g. \1  
> doesn’t help)
> 
> Many TIA,  
> Craig

It seems that this will work:

newtext = text.gsub(/(.\*?)\</field\>/) {|match| eval $1}

but I can’t explain why what you attempted didn’t work. Hopefully  
somebody else can explain what’s going on.

Jeremy

---

<div class="post-metadata">

**Author:** ![Dudebot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e495f1/32.png) [@Dudebot](https://www.ruby-forum.com/u/Dudebot)\
**Post date:** [February 27, 2010, 11:16pm UTC](https://www.ruby-forum.com/t/interpolation-question/197027/7 "2010-02-27T23:16:26Z")

</div>

Regarding my question about interpolation (sorry, David, for top-  
posting, blame Google for making it the default, and me for being  
lazy) thanks super Paul and David for the detailed posts, and Jeremy  
for the stab at it. I found a nice write-up on Freshmeat:  
[Best Open Source Mac Software Development Software 2023](http://freshmeat.net/articles/templates-in-ruby) Hope this helps those  
who may be browsing in the future for this kind of solution.

Point taken, Paul, about security. Only trusted users are allowed  
this functionality in my app.

Thanks again, all

---

<div class="post-metadata">

**Author:** ![Dudebot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e495f1/32.png) [@Dudebot](https://www.ruby-forum.com/u/Dudebot)\
**Post date:** [February 27, 2010, 9:35pm UTC](https://www.ruby-forum.com/t/interpolation-question/197027/8 "2010-02-27T21:35:23Z")

</div>

Seeeeems like you’re looking for eval.

Of course, this mean you absolutely trust your input.

Alternatively, nothing stops you from just storing the values in a hash,  
doing something likke

fields = {“wibble” =\> 2.0, “bobble” =\> 3.0}  
newtext = text.gsub(%r{(.\*?)}) {|value| fields[value]}

_Still_ this assumes that you absolutely know your input will always be  
in this exact format, otherwise (for example if you’re not the person  
generating the input) use an actual XML parser (like Nokogiri).

Dudebot wrote:

> Thanks, Luc, but that’s not what I need. That produces
> 
> this is an wibble  
> of stuff bobble
> 
> instead of
> 
> this is an 2.0  
> of stuff 3.0
> 
> I need it to interpolate the value of the expressions, not the  
> expressions themselves. Is this not possible in Ruby?
