【问题标题】:Problem using OpenStruct with ERB将 OpenStruct 与 ERB 一起使用时出现问题
【发布时间】:2011-03-15 14:56:45
【问题描述】:

编辑:忘记包含我的环境信息... 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 绑定?我通过传入vars_binding 告诉它使用来自OpenStruct 的绑定

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

【问题讨论】:

  • 在 Mac 上的 ruby​​ 1.8.7 和 1.9.1 上为我工作:输出“foo”并返回 nil。
  • @Andrew:好奇你能不能解决这个问题?
  • @Andrew:当我通过 IRB 控制台运行您的确切示例时,我也会收到错误消息。如果这很重要,我使用的是 Windows Vista。

标签: ruby binding erb nameerror


【解决方案1】:

问题在于绑定的执行位置。 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

更多关于这个问题in this answer

【讨论】:

    【解决方案2】:

    解决问题:

    在 Ruby 1.9.2 中遇到具有相似代码的相同类型错误时,我偶然发现了这个问题。

    我是 Ruby 新手,所以我无法解释发生了什么。我继续在网上搜索,发现this blog post 的方法似乎可行。在修改您的示例以合并此方法后,我最终得到以下有效代码:

    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
    

    【讨论】:

    • 我忘了我有这个问题。实际上,我前段时间找到了相同的解决方案。不过,感谢您的回答。给你信用并结束问题:)
    【解决方案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
    

    在 OSX 上低于 1.8.7:

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

    【讨论】:

      【解决方案4】:

      看起来这不适用于更高的 ruby​​ 版本

      使用 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>'
      

      使用 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
      

      所以它给出了错误,但在 1.9.3 和 1.9.3 以下的所有版本中仍然有效。

      【讨论】:

        猜你喜欢
        • 2012-12-29
        • 2011-05-27
        • 1970-01-01
        • 1970-01-01
        • 2023-04-07
        • 2010-10-26
        • 2020-06-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多