问题
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?
回答1:
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
回答2:
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.
回答3:
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]
回答4:
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.
来源:https://stackoverflow.com/questions/3242470/problem-using-openstruct-with-erb