title: Ruby .erb template from hash, but catch unset variables
body: <p>I'm a bit of a Ruby-newbie, but I'm trying to render Puppet .erb templates using a script and a load of synthesised data (which I'll put in a Yaml file or something). Our puppet templates are mostly along these sorts of lines:</p>
  
  <pre><code># Some config file
  &lt;%= @some_ordinary_variable %&gt;
  &lt;%= some_other_variable %&gt;
  &lt;%= @something_undefined %&gt;
  &lt;%= scope.function_hiera("some_hiera_variable") %&gt;
  </code></pre>
  
  <p>I've got as far as mocking up the hiera lookups, and found <a href="https://stackoverflow.com/questions/3242470/problem-using-openstruct-with-erb/8293786">Problem using OpenStruct with ERB</a> as a way to substitute in the "some_other_variable" (I'm a bit stuck on getting "@some_ordinary_variable" to work, but I think I can figure that one out.</p>
  
  <p>What I'm asking about is how can I use a binding that lets me run a bit of code with each variable lookup? I'm thinking I'd like to run something like:</p>
  
  <pre><code>def variable_lookup(key)
    if @variables.has_key?(key)
      return @variables[key]
    else
      warn "The variable " + key + " is required by the template but not set"
    end
  end
  </code></pre>
  
  <p>I could then merge this with my Hiera mock-up to lookup the Hiera data. The code I have so far is:</p>
  
  <pre><code>require 'rubygems'
  require 'yaml'
  require 'erb'
  require 'ostruct'
  
  class ErbBinding &lt; OpenStruct
    include Enumerable
    attr_accessor :yamlfile, :hiera_config, :erbfile, :yaml
  
    def scope
      self
    end
  
    def function_hiera(key)
      val = @yaml['values'][key]
      if val.is_a?(YAML::Syck::Scalar)
        return val.value
      else
        warn "erby: " + key + " required in template but not set in yaml"
        return nil
      end
    end
  
    def get_binding
      return binding()
    end
  end
  
  variables = {'some_other_variable' =&gt; 'hello world'}
  
  hs = ErbBinding.new(variables)
  template = File.read('./template.erb')
  hs.yaml = YAML.parse( File.read('./data.yaml') )
  
  erb = ERB.new(template)
  
  vars_binding = hs.send(:get_binding)
  puts erb.result(vars_binding)
  </code></pre>
  
  <p>I can't figure out how to set up a binding that runs code, rather than just using the 'variables' hash. Any ideas?</p>