Question

EDIT: forgot to include my environment info... Win7x64, RubyInstaller Ruby v1.9.1-p378

EDIT 2: just updated to v1.9.1, patch 429, and still getting this same error.

Edit 3: running this same code in Ruby v1.8.7, patch 249, works fine. so it's v1.9.1 that broke it, apparently.

I'm new to using ERB and the samples i could find are... ummm... less than helpful... having played around with ERB for about an hour, I got some basic examples working (finally), but I have no idea why this doesn't work...

require 'ostruct'
require 'erb'

data = {:bar => "bar"}
vars = OpenStruct.new(data)

template = "foo "
erb = ERB.new(template)

vars_binding = vars.send(:binding)
puts erb.result(vars_binding)

this code produces the following error:

irb(main):007:0> puts erb.result(vars_binding)
NameError: undefined local variable or method `bar' for main:Object
        from (erb):1
        from C:/Ruby/v1.9.1/lib/ruby/1.9.1/erb.rb:753:in `eval'
        from C:/Ruby/v1.9.1/lib/ruby/1.9.1/erb.rb:753:in `result'
        from (irb):7
        from C:/Ruby/v1.9.1/bin/irb:12:in `'

why is it looking at the main:Object binding? I told it to use the binding from the OpenStruct by passing in vars_binding

can someone fill me in on why it doesn't work, and help me get it to work?

Was it helpful?

Solution

Fix to Problem:

I stumbled upon this question when encountering the same type of error with similar code in Ruby 1.9.2.

I'm new to Ruby so I can't explain what is happening. I continued to search online and found this blog post that has an approach that seems to work. After modifying your example to incorporate this approach I end up with the following, working, code:

require 'ostruct'
require 'erb'

class ErbBinding < OpenStruct
    def get_binding
        return binding()
    end
end

data = {:bar => "baz"}
vars = ErbBinding.new(data)

template = "foo <%= bar %>"
erb = ERB.new(template)

vars_binding = vars.send(:get_binding)
puts erb.result(vars_binding)

Additional Information:

When the code is run thru the IRB, I get:

require 'ostruct'
=> true
require 'erb'
=> true

class ErbBinding < OpenStruct
    def get_binding
        return binding()
    end
end
=> nil

data = {:bar => "baz"}
=> {:bar=>"baz"}
vars = ErbBinding.new(data)
=> #<ErbBinding bar="baz">

template = "foo <%= bar %>"
=> "foo <%= bar %>"
erb = ERB.new(template)
=> #<ERB:0x2b73370 @safe_level=nil, @src="#coding:IBM437\n_erbout = ''; _erbout.concat \"foo \"; _erbout.concat(( bar ).to_s); _erbout.force_encoding(__ENCODING__)", @enc=#<Encoding:IBM437>, @filename=nil>

vars_binding = vars.send(:get_binding)
=> #<Binding:0x2b6d418>
puts erb.result(vars_binding)
foo baz
=> nil

OTHER TIPS

The problem is where the binding is being executed. The 1.8.7-way obj.send(:binding) does not work anymore (see issue2161), the environment must be the object itself. So use instance_eval:

require 'ostruct'
require 'erb'

namespace = OpenStruct.new(:first => 'Salvador', :last => 'Espriu')
template = 'Name: <%= first %> <%= last %>'
ERB.new(template).result(namespace.instance_eval { binding })
#=> Name: Salvador Espriu

More about this issue in this answer.

What's your environment look like? This code worked for me (I just changed the string "bar" to "baz" to disambiguate in my brain, and added it to the template):

require 'ostruct'
require 'erb'

data = {:bar => "baz"}
vars = OpenStruct.new(data)

template = "foo <%= bar %>"
erb = ERB.new(template)

vars_binding = vars.send(:binding)
puts erb.result(vars_binding)

When I run it, I get:

defeateds-MacBook-Pro:Desktop defeated$ ruby erb.rb 
foo baz

Under 1.8.7 on OSX:

defeateds-MacBook-Pro:Desktop defeated$ ruby -v
ruby 1.8.7 (2009-06-08 patchlevel 173) [universal-darwin10.0]

Looks like this does not work with higher ruby versions

with ruby 2.1.1

[19] pry(main)> name = "samtoddler"
=> "Suresh"
[20] pry(main)> template_string = "My name is <%= name %>"
=> "My name is <%= name %>"
[21] pry(main)> template = ERB.new template_string
=> #<ERB:0x007fadf3491c38
 @enc=#<Encoding:UTF-8>,
 @filename=nil,
 @safe_level=nil,
 @src="#coding:UTF-8\n_erbout = ''; _erbout.concat \"My name is \"; _erbout.concat(( name ).to_s); _erbout.force_encoding(__ENCODING__)">
[22] pry(main)> puts template.result
NameError: undefined local variable or method `name' for main:Object
from (erb):1:in `<main>'

with ruby 1.9.3

[2] pry(main)> name = "samtoddler"
=> "Suresh"
[3] pry(main)> template_string = "My name is <%= name %>"
=> "My name is <%= name %>"
[4] pry(main)> template = ERB.new template_string
=> #<ERB:0x007f9be2a1fdf8
 @enc=#<Encoding:UTF-8>,
 @filename=nil,
 @safe_level=nil,
 @src=
  "#coding:UTF-8\n_erbout = ''; _erbout.concat \"My name is \"; _erbout.concat(( name ).to_s); _erbout.force_encoding(__ENCODING__)">
[5] pry(main)> puts template.result
My name is samtoddler

So it gives error but still works in 1.9.3 and all the versions below 1.9.3.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top