First, don't top-post (like this). It's annoying.
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?
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>(.*?)<\/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 = "<body>#{text}</body>"
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