Проблема с использованием OpenStruct с ERB

EDIT: забыл включить информацию о своей среде... Win7x64, RubyInstaller Ruby v1.9.1-p378

РЕДАКТИРОВАТЬ 2: только что обновился до версии 1.9.1, исправление 429, и по-прежнему возникает та же ошибка.

Изменить 3: запуск того же кода в Ruby v1.8.7, патч 249, работает нормально. так что это v1.9.1 сломала его, по-видимому.

Я новичок в использовании ERB, и образцы, которые я смог найти,... эммм... менее чем полезны... поигравшись с 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

может ли кто-нибудь объяснить мне, почему это не работает, и помочь мне заставить его работать?


person Derick Bailey    schedule 14.07.2010    source источник
comment
У меня работает на ruby ​​1.8.7 и 1.9.1 на Mac: выводит foo и возвращает nil.   -  person Andrew Vit    schedule 14.07.2010
comment
@Andrew: Любопытно, смогли ли вы это исправить?   -  person Matt    schedule 20.02.2011
comment
@Andrew: Когда я запускаю именно ваш пример через консоль IRB, я также получаю сообщение об ошибке. У меня Windows Vista, если это имеет значение.   -  person Matt    schedule 20.02.2011


Ответы (4)


Исправление проблемы:

Я наткнулся на этот вопрос, когда столкнулся с ошибкой того же типа с аналогичным кодом в 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

person Matt    schedule 20.02.2011
comment
я забыл, что у меня был этот вопрос открытым. Я нашел это же решение некоторое время назад, на самом деле. спасибо за ответ, однако. отдаю должное и закрываю вопрос :) - person Derick Bailey; 22.02.2011

Проблема в том, где выполняется привязка. Версия 1.8.7 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

Подробнее об этой проблеме в этом ответе.

person tokland    schedule 28.11.2011

Как выглядит ваше окружение? Этот код работал для меня (я просто изменил строку «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]
person defeated    schedule 14.07.2010

Похоже, это не работает с более высокими версиями 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.

person samtoddler    schedule 17.02.2015