I'm implementing HTML templating in a Ruby project (non-rails). To do this I'll be using ERB, but I have some concerns about the binding stuff.
First out, this is the method I got so far:
def self.template(template, data)
template = File.read("#{ENV.root}/app/templates/#{template}.html.erb")
template_binding = binding.clone
data.each do |k, v|
template_binding.local_variable_set(k, v)
end
ERB.new(template).result(template_binding)
end
To call it I'll just do
Email.template('email/hello', {
name: 'Bill',
age: 41
}
There are two issues with the current solution though.
First, I'm cloning the current binding. I want to create a new one. I tried Class.new.binding to create a new, but since binding is a private method it can't be obtained that way.
The reason I want a new one is that I want to avoid the risk of instance variables leaking into or out from the ERB file (cloning only takes care of the latter case).
Second, I want the variables passed to the ERB file to be exposed as instance variables. Here I tried with template_binding.instance_variable_set, passing the plain hash key k which complained that it wasn't a valid instance variable name and "@#{k}", which did not complain but also didn't get available in the ERB code.
The reason I want to use instance variables is that it's a convention that the people relying on this code is familiar with.
I have checked some topics here at Stack Overflow such as Render an ERB template with values from a hash, but the answers provided does not address the problems I'm discussing.
So in short, like the title: How to create new binding and assign instance variables to it for availability in ERB?
1) No need to clone, new binding is created for you each time.
I have tested this in irb:
class A; def bind; binding; end; end
a = A.new
bind_1 = a.bind
bind_2 = a.bind
bind_1.local_variable_set(:x, 2)
=> 2
bind_1.local_variables
=> [:x]
bind_2.local_variables
=> []
2) Open the objects Eigenclass and add attr_accessor to it
class << template_binding # this opens Eigenclass for object template_binding
attr_accessor :x
end
So in ruby you can just open any class and add methods for it. Eigenclass means class of a single object - each object can have custom class definition. Coming from C# I couldn't imagine a situation where this would be used, until now. :)
Do this for each hash
data.each do |k, v|
class << template_binding; attr_accessor k.to_sym; end
template_binding.k = v
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With