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 theto_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
Setting Mime Type for .Ogv Files in Rails Development Environment
Specifying Content Type in Rspec
Rails 5.0.0 When Installing "Nio4R":Failed to Build Gem Native Extension
Check If Array of Integers Increments in Ruby
Programmatically Derive a Regular Expression from a String
How to Run All Ruby Scripts with Warnings
Fastercsv Error with Ruby 1.9.2
How to Dynamically Define a Method as Private
Use Delayed::Job to Manage Multiple Job Queues
Ruby Daemons and Jruby - Alternative Options
How to Require a Block in Ruby
How to Cleanly Verify If the User Input Is an Integer in Ruby
Ruby on Rails Map.Root Doesn't Seem to Be Working