String interpolation / hash of local variables

Hello all-

I’m trying to do something likes

Demonstration Ruby/logic


template = <<-HTML

%{example}
...
%{foobar}
HTML

for i in special_list
example = …
foobar = …
arr.push template % return_magical_hash_with_local_variables()

in Python there is a locals() function that returns a dictionary/hash of
local variables.

In Ruby I’ve found local_variables() but that does not provide the
values. It should for just the example above! Or perhaps I can be
enlightened by someone here?

The other, dirtier idea is something like this:


template = %q{

#{example}
...
#{foobar}
}

for i in special_list
example = …
foobar = …
arr.push eval("“template”")

I believe one should avoid calling eval as much as possible. I tried the
“Facets” package,
“String.interpolate{template}” calls eval, it just masks the fact.

This could be avoided if there were a function that return a dictionary
or hash of local variables.

Correction made, second block of demo code read #{foobar} not %{foobar}.

Any assistance appreciated

G.

Hi,

I find this just dangerous and ugly, and I can’t think of a reason why
anyone would want to use this. At best it’s a demonstration how to
create security problems and confuse readers with unnecessary magic.

The practical solution for this is to simply save the values in a hash
– or even better, use a template engine.

Please, this is not C.

On Tue, Jul 24, 2012 at 10:08 PM, Gerbeck Shark
[email protected]wrote:

%{foobar}
%{foobar}
"String.interpolate{template}" calls eval, it just masks the fact.

This could be avoided if there were a function that return a dictionary
or hash of local variables.


Posted via http://www.ruby-forum.com/.

There is a templating library in the stdlib called erb (
http://rdoc.info/stdlib/erb/ERB)

require ‘erb’

template = <<-HTML

<%= example %>
<%= foobar %>
HTML

===== simple example with toplevel locals =====

example = ‘EXAMPLE’
foobar = ‘FOOBAR’
ERB.new(template).result binding # => "

EXAMPLE
\n

FOOBAR
\n"

===== more realistic example with methods on an object =====

you can technically do ivars in these, too, which

is what most web frameworks use, but that sucks IMO

class MyTemplateRenderer
attr_accessor :example, :foobar

def initialize(example, foobar)
self.example, self.foobar = example, foobar
end

def render(template)
ERB.new(template).result binding
end
end

renderer = MyTemplateRenderer.new ‘ExAmPlE’, ‘FoObAr’
renderer.render template # => "

ExAmPlE
\n

FoObAr
\n"

Try this:

z = 1
y = 2
hash = Hash.new
local_variables.each do |var|
hash[var] = eval var
end
puts h

That should give you a hash of the local variables.

On Wed, Jul 25, 2012 at 3:14 PM, Sam D. [email protected]
wrote:

1.9.3p125 :004 > magical_hash_with_local_**variables[:example] = “magical”
=> “magical”
1.9.3p125 :005 > magical_hash_with_local_**variables[:foobar] = “hash”
=> “hash”
1.9.3p125 :006 > arr.push template % magical_hash_with_local_**variables
=> [“

magical
\n
**hash
”]

No eval. No external dependencies. In your loop you just populate your
magical hash anew.

Nice! didn’t know you could do that.

On 07/25/2012 03:08 PM, Gerbeck Shark wrote:

%{foobar}
%{foobar}
"String.interpolate{template}" calls eval, it just masks the fact.

This could be avoided if there were a function that return a dictionary
or hash of local variables.

What about simply

irb
1.9.3p125 :001 > template =

%{example}
\n
%{foobar}

=> “
%{example}
\n
%{foobar}

1.9.3p125 :002 > arr = []
=> []
1.9.3p125 :003 > magical_hash_with_local_variables = {}
=> {}
1.9.3p125 :004 > magical_hash_with_local_variables[:example] = “magical”
=> “magical”
1.9.3p125 :005 > magical_hash_with_local_variables[:foobar] = “hash”
=> “hash”
1.9.3p125 :006 > arr.push template % magical_hash_with_local_variables
=> [“
magical
\n
hash
”]

No eval. No external dependencies. In your loop you just populate your
magical hash anew.

Sam