15

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?

3 Answers 3

24

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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.
@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.
Thanks, didn't think about the trick of using eval and wrapping the double quotes.
2

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!"

1 Comment

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).
1

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

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.