115

I'm looking for a better way to merge variables into a string, in Ruby.

For example if the string is something like:

"The animal action the second_animal"

And I have variables for animal, action and second_animal, what is the prefered way to put those variables in to the string?

7 Answers 7

272

The idiomatic way is to write something like this:

"The #{animal} #{action} the #{second_animal}"

Note the double quotes (") surrounding the string: this is the trigger for Ruby to use its built-in placeholder substitution. You cannot replace them with single quotes (') or the string will be kept as is.

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

5 Comments

Sorry, maybe I simplified the problem too much. The String will be pulled from a database, and the variable dependant a number of factors. Normally I would use a replace for 1 or two varibles, but this has the potential to be more. Any thoughts?
The #{} construct is probably the fastest (although that still seems counterintuitive to me). As well as gix's suggestion, you can also assemble strings with + or <<, but there may be some intermediate strings created, which is costly.
Best way to interpolate variables
what does idiomatic means?
"idiomatic": following the conventions of the language, writing code using the features of the language, rather than trying to force it into looking like another language.
128

You can use sprintf-like formatting to inject values into the string. For that the string must include placeholders. Put your arguments into an array and use on of these ways: (For more info look at the documentation for Kernel::sprintf.)

fmt = 'The %s %s the %s'
res = fmt % [animal, action, other_animal]  # using %-operator
res = sprintf(fmt, animal, action, other_animal)  # call Kernel.sprintf

You can even explicitly specify the argument number and shuffle them around:

'The %3$s %2$s the %1$s' % ['cat', 'eats', 'mouse']

Or specify the argument using hash keys:

'The %{animal} %{action} the %{second_animal}' %
  { :animal => 'cat', :action=> 'eats', :second_animal => 'mouse'}

Note that you must provide a value for all arguments to the % operator. For instance, you cannot avoid defining animal.

Comments

21

I would use the #{} constructor, as stated by the other answers. I also want to point out there is a real subtlety here to watch out for here:

2.0.0p247 :001 > first_name = 'jim'
 => "jim" 
2.0.0p247 :002 > second_name = 'bob'
 => "bob" 
2.0.0p247 :003 > full_name = '#{first_name} #{second_name}'
 => "\#{first_name} \#{second_name}" # not what we expected, expected "jim bob"
2.0.0p247 :004 > full_name = "#{first_name} #{second_name}"
 => "jim bob" #correct, what we expected

While strings can be created with single quotes (as demonstrated by the first_name and last_name variables, the #{} constructor can only be used in strings with double quotes.

Comments

15
["The", animal, action, "the", second_animal].join(" ")

is another way to do it.

Comments

11

This is called string interpolation, and you do it like this:

"The #{animal} #{action} the #{second_animal}"

Important: it will only work when string is inside double quotes (" ").

Example of code that will not work as you expect:

'The #{animal} #{action} the #{second_animal}'

1 Comment

Thank you for using the proper term so new programmers can learn: interpolation.
3

The standard ERB templating system may work for your scenario.

def merge_into_string(animal, second_animal, action)
  template = 'The <%=animal%> <%=action%> the <%=second_animal%>'
  ERB.new(template).result(binding)
end

merge_into_string('tiger', 'deer', 'eats')
=> "The tiger eats the deer"

merge_into_string('bird', 'worm', 'finds')
=> "The bird finds the worm"

Comments

0

You can use it with your local variables, like this:

@animal = "Dog"
@action = "licks"
@second_animal = "Bird"

"The #{@animal} #{@action} the #{@second_animal}"

the output would be: "The Dog licks the Bird"

Comments

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.