With Erubis, it is trivial to use a context object that makes variables accessible as instance variables in templates. It is not obvious, but you can do exactly the same with ERB as well, with a bit of work. Imagine being able to do this:
assigns = { :adjective => 'awesome' }
puts 'This is <%= @adjective %>!'.eruby(assigns)
The first step is to create a class which will contain the instance variables that should be accessible inside the template. The class whose source is shown below builds its instance variables based off a hash argument.
class ERBContext
def initialize(hash)
hash.each_pair do |key, value|
instance_variable_set('@' + key.to_s, value)
end
end
end
The next part involves the magic of Binding. A binding basically lets you evalutate code (using eval() or something) at some point in your program, and pretend the code was evaluated at the point where you got the binding.
In our ERB code, we’d like to evaluate the ERB template at some point in the program, but still pretend we’re evaluating the template inside the context object, so that we have access to its instance variables. To do so, add a method that returns a binding for that class:
class ERBContext
def get_binding
binding
end
end
And we can finally use the context object:
assigns = { :adjective => 'awesome' }
ERB.new('This is <%= @adjective %>!')
erb_context = ERBContext.new(assigns)
erb_binding = erb_context.get_binding
puts erb.result(erb_binding)
That is not very pretty, and it takes a lot of code to evaluate a single template, so let’s put this in a new String method, like this:
class String
def eruby(assigns={})
ERB.new(self).result(ERBContext.new(assigns).get_binding)
end
end
So now we can indeed do (as mentioned above):
assigns = { :adjective => 'awesome' }
puts 'This is <%= @adjective %>!'.eruby(assigns)
For completeness, here’s the full source code for this example:
require 'erb'
class ERBContext
def initialize(hash)
hash.each_pair do |key, value|
instance_variable_set('@' + key.to_s, value)
end
end
def get_binding
binding
end
end
class String
def eruby(assigns={})
ERB.new(self).result(ERBContext.new(assigns).get_binding)
end
end
Enjoy!