tags:

views:

195

answers:

3

I have a Ruby script that used string interpolation to build error messages.

p "#{vName} is not a defined variable"  => 'xxx is not a defined variable'

Another programmer came through and attempted to externalize the string literals to a separate configuration file. Of course, he doesn't get the substitution.

p err_string_from_config  => '#{vName} is not a defined variable'

I've looked around, but couldn't come up with anything better than converting to sprintf strings and using printf.

Does anybody know how to get the #{} substitution to work on strings that are not double quote literals within the Ruby script?

+5  A: 

Actually Ruby has functionality very similar to John's Python example:

$ irb
>> greeting = 'hello %s, my name is %s!'
>> interpolated = greeting % ['Mike', 'John']
=> "hello Mike, my name is John!"
>>

This is also useful if your argument is an array constant. If you must use #{} style interpolation you could use eval:

>> greeting = 'hi #{name}'    # notice name is not defined yet
>> name = "mike"
>> eval '"' + greeting + '"'

The eval approach is going to be much slower than using % style interpolation, so it's a trade-off.

Mark A. Nicolosi
Whoops! I stand corrected. I'll remove my answer.
John Feminella
Yeah, I was hoping to find a way that didn't involve him modifying the strings. It's not a big deal, but after he asked about it, I had to see if there was a way to get the #{} substitution to work without it being in a literal string. Just seemed as though there ought to be a way.
Mike Cargal
@John: No problem if I had a dollar for every small mistake... (I actually didn't know Python did this either) ;)@Mike: I updated my answer with info on how to do this using #{} style interpolation.
Mark A. Nicolosi
Thanks, didn't think about the trick of using eval and wrapping the double quotes.
Mike Cargal
A: 

Here's how I do it, just for the record. A bit clearer imo.

gief = '#{later} please'
later = "later"

puts eval(%Q["#{gief}"])
# => later please

But honestly, that is such a hack. Unless you have a really good reason to use a string, use a proc instead. I always try to use plain ruby instead of evaling strings.

gief = Proc.new {|l| "#{l} please" }
later = "later"

puts gief.call(later)
# => later please
August Lilleaas
Yeah, I certainly tend to agree that using eval is something I would tend to avoid. If this were part of a larger "system" that needed an error strategy, I'd probably condier the templating solution or turning each message into a Proc (interesting solution by the way). We'll probably use eval.
Mike Cargal
A: 

I suggest that you look at Liquid templating language which provides more powerful features (e.g. you can reference parameters by name). Previous example would look like:

greeting = Liquid::Template.parse("hello {{your_name}}, my name is {{my_name}}!")
interpolated = greeting.render('your_name' => 'Mike', 'my_name' => 'John')
# => "hello Mike, my name is John!"
Raimonds Simanovskis
thanks, that's good to know about. It's a bit more than I think we want to add into what is really a fairly simple script (I'm not exactly sure why they felt compelled to externalize the strings for it to be honest).
Mike Cargal