insert into erb binding

J

Jeremy Wells

I have a class that takes a template, parses it through ERB, then takes
the output for some custom manipulation. When the class is created as an
object a binding is passed to it to be passed to the template. Is it
possible to get the class to insert a variable into the binding? Example:

Template:
<xml><%=@variable1%> <%=variable2%></xml>

class:
class Renderer
def initialize(template_file, apply_binding)
@file = template_file
@binding = apply_binding
end

def render
@variable2 = "There"

template = ERB.new(File.read(@file))
template_results = template.result(@binding)

# Perform on template results
end
end

Program:
@variable1 = "Hello"
renderer = Renderer.new('template.xml', binding)
renderer.render

current output: <xml>Hello</xml>
desired output: <xml>Hello There</xml>

So I want the renderer class to add @variable2 to the binding before
calling the template.
 
J

Jan Svitok

I have a class that takes a template, parses it through ERB, then takes
the output for some custom manipulation. When the class is created as an
object a binding is passed to it to be passed to the template. Is it
possible to get the class to insert a variable into the binding? Example:

Template:
<xml><%=@variable1%> <%=variable2%></xml>

class:
class Renderer
def initialize(template_file, apply_binding)
@file = template_file
@binding = apply_binding
end

def render
@variable2 = "There"

template = ERB.new(File.read(@file))
template_results = template.result(@binding)

# Perform on template results
end
end

Program:
@variable1 = "Hello"
renderer = Renderer.new('template.xml', binding)
renderer.render

current output: <xml>Hello</xml>
desired output: <xml>Hello There</xml>

So I want the renderer class to add @variable2 to the binding before
calling the template.

IIRC this is (more or less) from Rails code:

def evaluate_locals(local_assigns = {})
b = binding
local_assigns.each { |key, value| eval "#{key} =
local_assigns[\"#{key}\"]", b }
b
end

The trick is to use eval with binding as an additional argument.
 
J

Jeremy Wells

surely this won't work as the binding in my case is coming from an
external source, so the ruby in the eval won't have access to the
variable in the render method?

Jan said:
I have a class that takes a template, parses it through ERB, then takes
the output for some custom manipulation. When the class is created as an
object a binding is passed to it to be passed to the template. Is it
possible to get the class to insert a variable into the binding?
Example:

Template:
<xml><%=@variable1%> <%=variable2%></xml>

class:
class Renderer
def initialize(template_file, apply_binding)
@file = template_file
@binding = apply_binding
end

def render
@variable2 = "There"

template = ERB.new(File.read(@file))
template_results = template.result(@binding)

# Perform on template results
end
end

Program:
@variable1 = "Hello"
renderer = Renderer.new('template.xml', binding)
renderer.render

current output: <xml>Hello</xml>
desired output: <xml>Hello There</xml>

So I want the renderer class to add @variable2 to the binding before
calling the template.

IIRC this is (more or less) from Rails code:

def evaluate_locals(local_assigns = {})
b = binding
local_assigns.each { |key, value| eval "#{key} =
local_assigns[\"#{key}\"]", b }
b
end

The trick is to use eval with binding as an additional argument.

--


*Jeremy Wells*
Serval Systems Ltd.

www.servalsystems.co.uk <http://www.servalsystems.co.uk>
Tel: 01342 331940
Fax: 01342 331950
 
J

Jan Svitok

surely this won't work as the binding in my case is coming from an
external source, so the ruby in the eval won't have access to the
variable in the render method?

So once more: The trick is to use eval with binding as an additional argument.
That means when eval gets a binding as the second argument, it will operate
in that context. In this case, if you eval("@var = 123",
some_binding), the variable @var will be set in that binding.

Beware that you are modifying the original binding, so you might
corrupt the original caller.
Maybe @binding = apply_binding.dup will be neccessary.

(I added @ in the template - it was missing)

require 'erb'

# TEMPLATE = "<xml><%=@variable1%> <%=variable2%></xml>"
TEMPLATE = "<xml><%=@variable1%> <%=@variable2%></xml>"

class Renderer
def initialize(template_file, apply_binding)
@file = template_file
@binding = apply_binding
end

def render
# @variable2 = "There"
eval("@variable2 = \"There\"", @binding)

# template = ERB.new(File.read(@file))
template = ERB.new(TEMPLATE)

template_results = template.result(@binding)

# Perform on template results

template_results
end
end

require 'test/unit'

class TestERB < Test::Unit::TestCase
def test_variable
@variable1 = "Hello"

renderer = Renderer.new('template.xml', binding)
assert_equal "<xml>Hello There</xml>", renderer.render
end

end
 
J

Jeremy Wells

Ah ok, I get it but here is the problem, which I didn't specify...
@variable2 doesn't hold static data, it holds an object, which is
created in the render method like so:

def render
@variable2 = Object.new
eval("@variable2 = ????", @binding)

That's what I meant by the variable not being in the binding, thus not
accessible to eval.

Jan said:
So once more: The trick is to use eval with binding as an additional
argument.
That means when eval gets a binding as the second argument, it will
operate
in that context. In this case, if you eval("@var = 123",
some_binding), the variable @var will be set in that binding.

Beware that you are modifying the original binding, so you might
corrupt the original caller.
Maybe @binding = apply_binding.dup will be neccessary.

(I added @ in the template - it was missing)

require 'erb'

# TEMPLATE = "<xml><%=@variable1%> <%=variable2%></xml>"
TEMPLATE = "<xml><%=@variable1%> <%=@variable2%></xml>"

class Renderer
def initialize(template_file, apply_binding)
@file = template_file
@binding = apply_binding
end

def render
# @variable2 = "There"
eval("@variable2 = \"There\"", @binding)

# template = ERB.new(File.read(@file))
template = ERB.new(TEMPLATE)

template_results = template.result(@binding)

# Perform on template results

template_results
end
end

require 'test/unit'

class TestERB < Test::Unit::TestCase
def test_variable
@variable1 = "Hello"

renderer = Renderer.new('template.xml', binding)
assert_equal "<xml>Hello There</xml>", renderer.render
end

end

--


*Jeremy Wells*
Serval Systems Ltd.

www.servalsystems.co.uk <http://www.servalsystems.co.uk>
Tel: 01342 331940
Fax: 01342 331950
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top