How can one have a string object like this...
a = '#{some_value}'
and have it get evaluated as a double quoted string (with the value for
some_value being automatically replaced) at a later time?
I would prefer that it is evaluated in context from which it is called.
I would like to do something like this...
def func(param)
test = 42
puts param.quote_substitution
end
func('my number is #{test}') #=> "my number is 42"
_Kevin
--
Posted via http://www.ruby-forum.com/.
How about:
template = lambda { |x| "my number is: #{x}" }
# some time passes
template.call(42) # "my number is: 42"
Gary Wright
You can delay evaluation like this:
string = '"#{foo}"'
# ...
value = eval string # Add a binding if you want
> _Kevin
E
Try this:
class String
def evaluate(*args)
eval inspect.gsub(/\\#/, '#'), *args
end
end
def func(str)
x = 42
str.evaluate(binding)
end
puts func('the answer is #{x}')
--
Paolo
def func(param)
some_value = 42
value = eval %Q{%Q{#{param}}}
end
func('my number is #{some_value}') #=> 'my number is 42'
> Lots of good responses here, but the one that turns out to be the
> easiest is...
>
> def func(param)
> some_value = 42
> value = eval %Q{%Q{#{param}}}
> end
>
> func('my number is #{some_value}') #=> 'my number is 42'
What you really want here is ERB:
>> require "erb"
=> true
>> def expand( template )
>> some_value = 42
>> ERB.new(template).result(binding)
>> end
=> nil
>> expand "My number is <%= some_value %>."
=> "My number is 42."
James Edward Gray II
A good suggestion, but I would rather avoid unnecessary dependencies if
there is an adequate pure ruby way to do it.
erb *is* pure Ruby. It is part of the standard library, so every Ruby
installation has it.
> erb *is* pure Ruby. It is part of the standard library, so every Ruby
> installation has it.
So it is, my bad.
This solution has the problem that it doesn't work for:
func('{ #{1+2}')
A solution I have used in the past is:
param.gsub(/\#\{([^\}]*)\}/) { eval($1) }
but that wont work for:
param='#{"12#{1+2}4"}'
I would be very interested if anyone has a robust solution...
The problem is that the #{code} construct can contain arbitrary
code, including being multi-line code, with comments, other blocks,
nested strings ...
If using Oniguruma is allowed (with subexpression calling and cuts) then we
can make a bit of progress hacking up a rudimentary parser that can try to
grab #{}-like things for evaluation:
class Parse
QLIKE = %r/(?:'(?:\\'|[^'])*' |
"(?:\\"|[^"])*" |
%[qQrxw]\!(?:\\!|[^\!])*\! |
%[qQrxw]\#(?:\\\#|[^#])*\# |
%[qQrxw]\|(?:\\\||[^|])*\| |
%[qQrxw]\/(?:\\\/|[^\/])*\/ |
%[qQrxw](?<qb>\[(?:(?>\\[\]\[]|[^\[\]])|\g<qb>)*\]) |
%[qQrxw](?<qa>\<(?:(?>\\[<>]|[^<>])|\g<qa>)*\>) |
%[qQrxw](?<qc>\{(?:(?>\\[{}]|[^{}])|\g<qc>)*\}) |
%[qQrxw](?<qp>\((?:(?>\\[()]|[^()])|\g<qp>)*\)) )/x
COMMENT = %r/(?:#[^\n]*\n)/
SBLOCK = %r/(?<block>\{(?:(?>#{COMMENT} |
#{QLIKE} |
[^{}]
) |
\g<block>)*
\})/x
def Parse.expand str
test = "ple"
str.gsub!(/(?<!\\)##{SBLOCK}/){eval $1.gsub(/\A\{|\}\z/,'')}
end
end
param='#{"12#{1+2}4"}'
Parse.expand(param)
puts param
test = 42
param = 'this is \#{not} a #{"sil".succ + # blah } blah comments
(%Q!}! << lambda{?b - ?5}.call) + # }}more comments{{}
"{#{test}" # yet more (*&@QI#{J$)*DF}{Junk
} exercise' # <- string ends down here
Parse.expand(param)
puts param
__END__
results in:
1234
this is \#{not} a sim}-{ple exercise
Is this robust? It is only a small bit of required parsing (for instance,
there are more potential delimiters for quote-like expressions) -- However,
it does make failure-prediction less obvious, which some might substitute
for robustness :-)
cheers,
andrew
--
Andrew L. Johnson http://www.siaris.net/
I don't want to achieve immortality through my work; I want to
achieve immortality through not dying.
- Woody Allen