Проблема использования OpenStruct с ERB
EDIT: забыл включить информацию о моей среде... Win7x64, RubyInstaller Ruby v1.9.1-p378
РЕДАКТИРОВАТЬ 2: только что обновленный до версии 1.1.1, патч 429 и все еще получающий эту же ошибку.
Редактировать 3: работает тот же код в Ruby v1.8.7, patch 249, отлично работает. поэтому он v1.9.1, который сломал его, по-видимому.
Я новичок в использовании ERB, и образцы, которые я мог найти, были... ummm... меньше, чем полезно... играя с ERB около часа, я получил некоторые базовые примеры, работающие (наконец) но я понятия не имею, почему это не работает...
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)
этот код вызывает следующую ошибку:
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 `'
почему он смотрит на привязку main:Object
? Я сказал ему использовать привязку из OpenStruct, перейдя в vars_binding
может кто-то наполнить меня тем, почему он не работает, и помочь мне заставить его работать?
Ответы
Ответ 1
Исправить проблему:
Я наткнулся на этот вопрос, столкнувшись с тем же типом ошибок с аналогичным кодом в Ruby 1.9.2.
Я новичок в Ruby, поэтому не могу объяснить, что происходит. Я продолжал искать в Интернете и нашел этот пост в блоге, в котором есть подход, который, похоже, работает. После изменения вашего примера, чтобы включить этот подход, я получаю следующий, рабочий, код:
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)
Дополнительная информация:
Когда код запускается через IRB, я получаю:
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
Проблема заключается в том, где выполняется привязка. 1.8.7-way obj.send(:binding)
больше не работает (см. issue2161), среда должна быть самим объектом. Поэтому используйте 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
Подробнее об этом выпуске в этом ответе.
Ответ 3
Как выглядит ваша среда? Этот код работал у меня (я просто изменил строку "bar" на "baz", чтобы устранить эту проблему в моем мозгу и добавил ее к шаблону):
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)
Когда я запустил его, я получаю:
defeateds-MacBook-Pro:Desktop defeated$ ruby erb.rb
foo baz
В разделе 1.8.7 на OSX:
defeateds-MacBook-Pro:Desktop defeated$ ruby -v
ruby 1.8.7 (2009-06-08 patchlevel 173) [universal-darwin10.0]
Ответ 4
Похоже, что это не работает с более высокими версиями 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>'
с рубином 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
Таким образом, он дает ошибку, но все еще работает в 1.9.3 и во всех версиях ниже 1.9.3.