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.
It works with eval:
proc = Proc.new { |var| eval(%Q{"#{string}"}) }
(If you trust the value of string.)
In my case I needed to have configuration stored inside a yml, with interpolation, but which is only interpolated when I need it. The accepted answer with the Proc
seemed overly complicated to me.
In ruby 1.8.7 you can use the %
syntax as follows:
"This is a %s verb, %s" % ["nice", "woaaaah"]
When using at least ruby 1.9.x (or ruby 1.8.7 with i18n) there is a cleaner alternative:
my_template = "This is a %{adjective} verb, %{super}!"
my_template % { adjective: "nice", super: "woah" }
=> "This is a nice verb, woah!"
You can achieve the DRY that you're seeking by creating a "curried" function (ie: a Proc that returns a Proc) where the inner function contains the base string with variables for every part that differs.
Correct me if I'm wrong, but in your code behind your commented link, the only difference between the two strings is a single char at the end. (Even if it isn't, you can still use this technique to achieve the same goal.) You can create a Proc that returns a Proc that contains your string, then call the outer Proc twice for your two trailing characters:
rails_root = "whatever" # Not variant for the string
rails_env_prompt = "whatever" #not variant for the string
spec = Proc.new { |tail_char|
Proc.new {|obj, nest_level, *|
"#{rails_root} #{rails_env_prompt} #{obj}:#{nest_level}#{tail_char} "
}
}
Pry.config.prompt = [ spec.call(">"), spec.call("*") ]
Pry.config.prompt[0].call("My obj", "My Nest Level")
# result: "whatever whatever My obj:My Nest Level> "