How to Do "Late" String Interpolation in Ruby

How to do late string interpolation in Ruby

Although this is possible, it's not going to work how you intend here without having to use eval, and generally that's a bad idea if there's an alternative. The good news is you have several options.

The most straightforward is to use sprintf formatting which is made even easier with the String#% method:

string = '%s'

proc = Proc.new { |var| string % var }

proc.call(123)
# => "123"

This is a really reliable method as anything that supports the .to_s method will work and won't cause the universe to implode if it contains executable code.

Pass a string as method parameter to be interpolated later

For that purpose, % is used. First, create a string:

s = "location = %{location}"

Later, you can apply % to it:

s % {location: "foo"} # => "location = foo"

If you do not have to name the parameter(s), then it is simpler:

s = "location = %s"
s % "foo" # => "location = foo"

String concatenation vs. interpolation in Ruby

Whenever TIMTOWTDI (there is more than one way to do it), you should look for the pros and cons. Using "string interpolation" (the second) instead of "string concatenation" (the first):

Pros:

  • Is less typing
  • Automatically calls to_s for you
  • More idiomatic within the Ruby community
  • Faster to accomplish during runtime

Cons:

  • Automatically calls to_s for you (maybe you thought you had a string, and the to_s representation is not what you wanted, and hides the fact that it wasn't a string)
  • Requires you to use " to delimit your string instead of ' (perhaps you have a habit of using ', or you previously typed a string using that and only later needed to use string interpolation)

How do I escape #{ from string interpolation

I think the backslash-hash is just Ruby being helpful in some irb-only way.

>> a,b = 1,2        #=> [1, 2]
>> s = "#{a} \#{b}" #=> "1 \#{b}"
>> puts s #=> 1 #{b}
>> s.size #=> 6

So I think you already have the correct answer.

String interpolation when not using a string literal

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.

Ruby string interpolation equivalent to python's .format()

You can use Delayed Interpolation.

str = "My name is %{name}"
# => "My name is %{name}"

puts str % {name: "Sam"}
# => "My name is Sam"

The %{} and % operators in Ruby allows delaying the string interpolation until later. The %{} defines named placeholders in the string and % binds a given input into the placeholders.

Ruby: eval with string interpolation

What's happening, is eval is evaluating the string as source code. When you use double quotes, the string is interpolated

eval '"123 #{456.to_s} 789"'
# => "123 456 789"

However when you use single quotes, there is no interpolation, hence the # starts a comment, and you get

123 #{456.to_s} 789
# => 123

The string interpolation happens before the eval call because it is the parameter to the method.

Also note the 456.to_s is unnecessary, you can just do #{456}.



Related Topics



Leave a reply



Submit