15

编辑:忘记包含我的环境信息... Win7x64,RubyInstaller Ruby v1.9.1-p378

编辑 2:刚刚更新到 v1.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: main:Object 的未定义局部变量或方法“bar”
        来自 (erb):1
        来自 C:/Ruby/v1.9.1/lib/ruby/1.9.1/erb.rb:753:in `eval'
        来自 C:/Ruby/v1.9.1/lib/ruby/1.9.1/erb.rb:753:in `result'
        来自 (irb):7
        来自 C:/Ruby/v1.9.1/bin/irb:12:in `'

为什么它在看main:Object绑定?我告诉它通过传入来使用 OpenStruct 中的绑定vars_binding

有人可以告诉我为什么它不起作用,并帮助我让它起作用吗?

4

4 回答 4

19

问题是在哪里执行绑定。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

此答案中有关此问题的更多信息。

于 2011-11-28T09:26:24.180 回答
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

于 2011-02-20T00:10:34.717 回答
2

你的环境是什么样的?这段代码对我有用(我只是将字符串“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

在 OSX 上的 1.8.7 下:

defeateds-MacBook-Pro:Desktop defeated$ ruby -v
ruby 1.8.7 (2009-06-08 patchlevel 173) [universal-darwin10.0]
于 2010-07-14T00:28:24.040 回答
0

看起来这不适用于更高的 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 以下的所有版本。

于 2015-02-17T11:14:59.207 回答