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}
.
In Ruby, can you perform string interpolation on data read from a file?
Instead of interpolating, you could use erb
. This blog gives simple example of ERB usage,
require 'erb'
name = "Rasmus"
template_string = "My name is <%= name %>"
template = ERB.new template_string
puts template.result # prints "My name is Rasmus"
Kernel#eval
could be used, too. But most of the time you want to use a simple template system like erb
.
Eval a string without string interpolation
You can do this via regex by ensuring that there are an even number of backslashes before the character you want to escape:
def safe_eval(str)
eval str.gsub( /([^\\](?:\\\\)*)#(?=[{@$])/, '\1\#' )
end
…which says:
- Find a character that is not a backslash
[^\\]
- followed by two backslashes
(?:\\\\)
- repeated zero or more times
*
- repeated zero or more times
- followed by a literal
#
character - and ensure that after that you can see either a
{
,@
, or$
character. - and replace that with
- the non-backslash-maybe-followed-by-even-number-of-backslashes
- and then a backslash and then a
#
Using interpolation within an attribute name (avoiding eval)
You could use the fact that assignments like user.name = 'John'
are actually method calls and can be written like this: user.name=('John')
, where name=
is the name of the method. We can invoke methods dynamically with send
(call any method) or public_send
(call a public method, will raise error if method exists but is private).
car.public_send("entered_text_#{i}=", new_car.public_send("entered_text_#{i}"))
puts car.public_send("entered_text_#{i}")
Related Topics
Ruby Sandboxing VS. Integrating a Scripting Language
Run Code Only If Script Called from the Command Line
How to Do Case-Insensitive Order in Rails with Postgresql
How to Find a Memory Leak on Heroku
How Does Ruby Handle Bytes/Binary
How to Get Name of the Month in Ruby on Rails
How to Split String into Paragraphs Using First Comma
How to Make a Before_Save Conditional
"Certificate Verify Failed" Error When Installing Ruby Gems on Windows
Using Will_Paginate Without :Total_Entries to Improve a Lengthy Query
Add a Callback Function to a Ruby Array to Do Something When an Element Is Added
How to Enable Compression in Ruby on Rails
Carrierwave How to Get the File Extension
Whenever Gem: I Set :Output But the Logfile Doesn't Show Up Where I'D Expect It To