Ruby templates: How to pass variables into inlined ERB? Ruby templates: How to pass variables into inlined ERB? ruby ruby

Ruby templates: How to pass variables into inlined ERB?


For a simple solution, use OpenStruct:

require 'erb'require 'ostruct'namespace = OpenStruct.new(name: 'Joan', last: 'Maragall')template = 'Name: <%= name %> <%= last %>'result = ERB.new(template).result(namespace.instance_eval { binding })#=> Name: Joan Maragall

The code above is simple enough but has (at least) two problems: 1) Since it relies on OpenStruct, an access to a non-existing variable returns nil while you'd probably prefer that it failed noisily. 2) binding is called within a block, that's it, in a closure, so it includes all the local variables in the scope (in fact, these variables will shadow the attributes of the struct!).

So here is another solution, more verbose but without any of these problems:

class Namespace  def initialize(hash)    hash.each do |key, value|      singleton_class.send(:define_method, key) { value }    end   end  def get_binding    binding  endendtemplate = 'Name: <%= name %> <%= last %>'ns = Namespace.new(name: 'Joan', last: 'Maragall')ERB.new(template).result(ns.get_binding)#=> Name: Joan Maragall

Of course, if you are going to use this often, make sure you create a String#erb extension that allows you to write something like "x=<%= x %>, y=<%= y %>".erb(x: 1, y: 2).


Simple solution using Binding:

b = bindingb.local_variable_set(:a, 'a')b.local_variable_set(:b, 'b')ERB.new(template).result(b)


Got it!

I create a bindings class

class BindMe    def initialize(key,val)        @key=key        @val=val    end    def get_binding        return binding()    endend

and pass an instance to ERB

dataHash.keys.each do |current|    key = current.to_s    val = dataHash[key]    # here, I pass the bindings instance to ERB    bindMe = BindMe.new(key,val)    result = template.result(bindMe.get_binding)    # unnecessary code goes hereend

The .erb template file looks like this:

Key: <%= @key %>