String interpolation at will?

Maybe I’m overlooking something obvious,
or maybe it’s not possible.

We all know how convenient string interpolation
can be: msg = “myval = #{myval}”

Is there a way to perform interpolation on
an arbitrary string? For example, if the
above string were read in from a file?

gsub doesn’t count. :slight_smile: Unless you have a
particularly elegant way to use it.

Cheers,
Hal

Maybe this is too dangerous but

File.readlines(“test.txt”).each {|line| print eval(’"’ + line + ‘"’)}

will work. Even if there were a function such as String.interpolate(str) it
would still be dangerous because any code within the #{} blocks would be
evaluated!

Steve

···

-----Original Message-----
From: Hal E. Fulton [mailto:hal9000@hypermetrics.com]
Sent: Friday, September 20, 2002 2:54 PM
To: ruby-talk ML
Subject: String interpolation at will?

Maybe I’m overlooking something obvious,
or maybe it’s not possible.

We all know how convenient string interpolation
can be: msg = “myval = #{myval}”

Is there a way to perform interpolation on
an arbitrary string? For example, if the
above string were read in from a file?

gsub doesn’t count. :slight_smile: Unless you have a
particularly elegant way to use it.

Cheers,
Hal

Hal E. Fulton wrote:

Maybe I’m overlooking something obvious,
or maybe it’s not possible.

We all know how convenient string interpolation
can be: msg = “myval = #{myval}”

Is there a way to perform interpolation on
an arbitrary string? For example, if the
above string were read in from a file?

Unless I’m completely misunderstanding your point, what about using
eval()? For example, given the Ruby script:

 a = 2
 b = 3

 IO.foreach("commands.txt") do |cmd|
   eval(cmd)
 end

 puts $astr
 puts $bstr

and the text file (commands.txt):

 $astr = "The value of a = #{a}"
 $bstr = "The value of b = #{b}"

I get the result:

 The value of a = 2
 The value of b = 3

Hope this helps,

Lyle

File.readlines(“test.txt”).each {|line| print eval(‘"’ + line + ‘"’)}

Well, I guess you’d have to use gsub to escape any existing quotes
first…

will work. Even if there were a function such as String.interpolate(str)
it
would still be dangerous because any code within the #{} blocks would be
evaluated!

Hmm, there have been times I wished for a String.interpolate
method… couldn’t be too hard to expose it. Wonder if it’s
worth it?

Danger is always an issue… guess it’s not so bad as long as
you have control over the data.

Even regular interpolation is potentially dangerous:

string = “Hi, my name is #{format_hard_drive_and_return_name()}.”

:slight_smile:

Hal

···

----- Original Message -----
From: “Steve Tuckner” STUCKNER@MULTITECH.COM
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Friday, September 20, 2002 3:08 PM
Subject: RE: String interpolation at will?

Steve Tuckner STUCKNER@MULTITECH.COM writes:

Maybe this is too dangerous but

File.readlines(“test.txt”).each {|line| print eval(‘"’ + line + ‘"’)}

will work. Even if there were a function such as String.interpolate(str) it
would still be dangerous because any code within the #{} blocks would be
evaluated!

indeed.

im stuck with this version:

def interpolate(str)
reg = Regexp.new(‘#{(($|@|@@)\w+)}’)
ret = ‘’
while (match = reg.match(str))

ret += match.pre_match
for i in 1..(match.length-1)
  ret += yield(match[1])
end

str = match.post_match

end
ret += str
end

testing calls:

a = ‘3012’
b = ‘1322’
str = ‘foo “#{a} #{b}”’

p interpolate(str) {|match| eval(match)}
p interpolate(‘#{a}’) {|match| eval(match)}

and i have 2 questions to the community:

  1. i was not able to find an equivalent to perl’s regexp-substitutes, so i had to do the
    ugly/complex/inefficient loop-contruct in “interpolate”. is there a better way to achieve
    this in ruby?

  2. i have to call interpolate with the eval block appended, so that the variables a
    looked up in the scope of the calling environment. is there a more better way to do
    this, or to make ‘{|match| eval(match)}’ the default, if no block is supplied?

regards
messju

···

Steve

-----Original Message-----
From: Hal E. Fulton [mailto:hal9000@hypermetrics.com]
Sent: Friday, September 20, 2002 2:54 PM
To: ruby-talk ML
Subject: String interpolation at will?

Maybe I’m overlooking something obvious,
or maybe it’s not possible.

We all know how convenient string interpolation
can be: msg = “myval = #{myval}”

Is there a way to perform interpolation on
an arbitrary string? For example, if the
above string were read in from a file?

gsub doesn’t count. :slight_smile: Unless you have a
particularly elegant way to use it.

Cheers,
Hal

Hi –

Even regular interpolation is potentially dangerous:

string = “Hi, my name is #{format_hard_drive_and_return_name()}.”

Although if it’s variable interpolation/expansion, you’ll just get the
string:

irb(main):001:0> s = gets.chomp!;puts “#{s}”
puts ‘blah’ # input
puts ‘blah’ # output

(i.e., it doesn’t actually puts ‘blah’)

And if it’s a string constant, it’s dangerous anywhere :slight_smile:

David

···

On Sat, 21 Sep 2002, Hal E. Fulton wrote:


David Alan Black | Register for RubyConf 2002!
home: dblack@candle.superlink.net | November 1-3
work: blackdav@shu.edu | Seattle, WA, USA
Web: http://pirate.shu.edu/~blackdav | http://www.rubyconf.com

To reply to myself: I’ve just remembered why
this is nontrivial in pure Ruby. If you write
a String#interpolate, it can’t get to your
local variables, i.e. if you do:

bar = “secret”
foo = ‘code is #{bar}’
str = foo.interpolate

it won’t work because #interpolate can’t see
the bar variable. Hmm.

You can still do it outside of a method, of
course.

I’m playing with a Proc now out of curiosity.

Hal

···

----- Original Message -----
From: “Hal E. Fulton” hal9000@hypermetrics.com
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Friday, September 20, 2002 3:30 PM
Subject: Re: String interpolation at will?

Hmm, there have been times I wished for a String.interpolate
method… couldn’t be too hard to expose it. Wonder if it’s
worth it?

Isn’t that what $SAFE is all about?

Gavin

···

----- Original Message -----
From: “Hal E. Fulton” hal9000@hypermetrics.com

Danger is always an issue… guess it’s not so bad as long as
you have control over the data.

Even regular interpolation is potentially dangerous:

string = “Hi, my name is #{format_hard_drive_and_return_name()}.”

:slight_smile:

Hal

And to answer my own post again, I find that
this works OK.

Tempted to put ANN: on the subject line. :wink:

Code below.

Cheers,
Hal

Let’s make a setter for a class variable

class String
def String.interp=(blk)
@@interp = blk
end
end

Back to top-level scope

String.interp = (Proc.new do |s|
__str = s.dup
__str.gsub!(/“/,‘"’)
eval('”’ + __str + ‘"’)
end)

Now define the methods

class String
def String.interpolate(str)
@@interp.call(str)
end
def interpolate
@@interp.call(self)
end
end

Now try it out

str = <<‘END’
He said, “I am the #{alpha} and
the #{omega}.”
Have a nice day.

END

puts str

alpha = “walrus”
omega = “weather is fine”

str2 = str.interpolate
puts str2

str3 = String.interpolate(str)
puts str3

And the output is:

He said, “I am the #{alpha} and
the #{omega}.”
Have a nice day.

He said, “I am the walrus and
the weather is fine.”
Have a nice day.

He said, “I am the walrus and
the weather is fine.”
Have a nice day.

···

----- Original Message -----
From: “Hal E. Fulton” hal9000@hypermetrics.com
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Friday, September 20, 2002 4:06 PM
Subject: Re: String interpolation at will?

----- Original Message -----
From: “Hal E. Fulton” hal9000@hypermetrics.com
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Friday, September 20, 2002 3:30 PM
Subject: Re: String interpolation at will?

Hmm, there have been times I wished for a String.interpolate
method… couldn’t be too hard to expose it. Wonder if it’s
worth it?

To reply to myself: I’ve just remembered why
this is nontrivial in pure Ruby. If you write
a String#interpolate, it can’t get to your
local variables, i.e. if you do:

bar = “secret”
foo = ‘code is #{bar}’
str = foo.interpolate

it won’t work because #interpolate can’t see
the bar variable. Hmm.

You can still do it outside of a method, of
course.

I’m playing with a Proc now out of curiosity.

Hal E. Fulton (in "String[#.]interpolate (was Re: String interpolation
[…]

And to answer my own post again, I find that
this works OK.
[…]

You can also require a Binding as an argument to #interpolate, and then
do the eval with it, which allows you to interpolate from arbitrary
scopes:

class String
def interpolate( scope )
unless scope.is_a?( Binding )
raise TypeError, "Argument to interpolate must be a Binding,
not "
“a #{scope.class.name}”
end

    copy = self.gsub( /"/, %q:\": )
    eval( '"' + copy + '"', scope )
end

end

Test it out:

str = <<‘END’
He said, “I am the #{alpha} and
the #{omega}.”
Have a nice day.

END

puts str

alpha = “walrus”
omega = “weather is fine”

puts str.interpolate( binding )

Output:

He said, “I am the #{alpha} and
the #{omega}.”
Have a nice day.

He said, “I am the walrus and
the weather is fine.”
Have a nice day.

···

at will?)") wrote:


Michael Granger ged@FaerieMUD.org
Rubymage, Believer, Architect
The FaerieMUD Consortium http://www.FaerieMUD.org/

“Hal E. Fulton” hal9000@hypermetrics.com writes:

···

----- Original Message -----
From: “Hal E. Fulton” hal9000@hypermetrics.com
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Friday, September 20, 2002 4:06 PM
Subject: Re: String interpolation at will?

----- Original Message -----
From: “Hal E. Fulton” hal9000@hypermetrics.com
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Friday, September 20, 2002 3:30 PM
Subject: Re: String interpolation at will?

Hmm, there have been times I wished for a String.interpolate
method… couldn’t be too hard to expose it. Wonder if it’s
worth it?

To reply to myself: I’ve just remembered why
this is nontrivial in pure Ruby. If you write
a String#interpolate, it can’t get to your
local variables, i.e. if you do:

bar = “secret”
foo = ‘code is #{bar}’
str = foo.interpolate

it won’t work because #interpolate can’t see
the bar variable. Hmm.

You can still do it outside of a method, of
course.

I’m playing with a Proc now out of curiosity.

And to answer my own post again, I find that
this works OK.

Tempted to put ANN: on the subject line. :wink:

Code below.

Cheers,
Hal

Let’s make a setter for a class variable

class String
def String.interp=(blk)
@@interp = blk
end
end

Back to top-level scope

String.interp = (Proc.new do |s|
__str = s.dup
__str.gsub!(/“/,‘"’)
eval('”’ + __str + ‘"’)
end)

Now define the methods

class String
def String.interpolate(str)
@@interp.call(str)
end
def interpolate
@@interp.call(self)
end
end

Now try it out

str = <<‘END’
He said, “I am the #{alpha} and
the #{omega}.”
Have a nice day.

END

puts str

alpha = “walrus”
omega = “weather is fine”

str2 = str.interpolate
puts str2

str3 = String.interpolate(str)
puts str3

And the output is:

He said, “I am the #{alpha} and
the #{omega}.”
Have a nice day.

He said, “I am the walrus and
the weather is fine.”
Have a nice day.

He said, “I am the walrus and
the weather is fine.”
Have a nice day.

very nice. but, unless i am missing something, there is just one flaw:
String.interp is always called in global context. you cannot use
String.interpolate inside a method and use local variables there.

have fun
messju

very nice. but, unless i am missing something, there is just one flaw:
String.interp is always called in global context. you cannot use
String.interpolate inside a method and use local variables there.

Perhaps you are right. I don’t have time
to look at it right now.

Can you show me an example of something
that fails?

Hal

···

----- Original Message -----
From: “M Mohr” messju@lammfellpuschen.de
Newsgroups: comp.lang.ruby
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Monday, September 23, 2002 7:16 AM
Subject: Re: String[#.]interpolate (was Re: String interpolation at will?)

Can you show me an example of something
that fails?

pigeon% cat b.rb
#!/usr/bin/ruby
class String
   def String.interp=(blk)
      @@interp = blk
   end
end
  
# Back to top-level scope
String.interp = (Proc.new do |s|
                    __str = s.dup
                    __str.gsub!(/"/,'\"')
                    eval('"' + __str + '"')
                 end)
  
# Now define the methods
class String
   def String.interpolate(str)
      @@interp.call(str)
   end
   def interpolate
      @@interp.call(self)
   end
end

def aa
  
   str = <<'END'
He said, "I am the #{alpha} and
the #{omega}."
Have a nice day.
  
END
   puts str
  
   alpha = "WALRUS"
   omega = "WEATHER IS FINE"

   str2 = str.interpolate
   puts str2

   str3 = String.interpolate(str)
   puts str3
end

alpha = "walrus"
omega = "weather is fine"

aa
pigeon%

pigeon% b.rb
He said, "I am the #{alpha} and
the #{omega}."
Have a nice day.
  
He said, "I am the walrus and
the weather is fine."
Have a nice day.
  
He said, "I am the walrus and
the weather is fine."
Have a nice day.
  
pigeon%

Guy Decoux

Of course, stupid of me. This solution
is useless.

Thanks, Guy.

Hal

···

----- Original Message -----
From: “ts” decoux@moulon.inra.fr
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Cc: ruby-talk@ruby-lang.org
Sent: Monday, September 23, 2002 10:27 AM
Subject: Re: String[#.]interpolate (was Re: String interpolation at will?)

Can you show me an example of something
that fails?