Haml::Engine#渲染:"can't modify frozen NilClass (RuntimeError)"

Haml::Engine#render: "can't modify frozen NilClass (RuntimeError)"

我正在研究 Pickaxe 书(第 281 页)的 Haml 部分,代码为:

require 'haml'
engine = Haml::Engine.new(%{
%body
  #welcome-box
    %p= greeting
  %p
    As of
    = Time.now
    the reasons you gave were:
    %table
      %tr
        %th Reason
        %th Rank
      - for reason in reasons
        %tr
          %td= reason[:reason_name]
          %td= reason[:rank]
})

data = {
  greeting: 'Hello, Dave Thomas',
  reasons: [
    { reason_name: 'flexible',    rank: '87' },
    { reason_name: 'transparent', rank: '76' },
    { reason_name: 'fun',         rank: '94' },
  ]
}

puts engine.render(nil, data)

运行 这会产生错误:

/Users/andrekibbe/.rvm/gems/ruby-2.2.1/gems/haml-4.0.7/lib/haml/engine.rb:136:in `block in render': can't modify frozen NilClass (RuntimeError)
    from /Users/andrekibbe/.rvm/gems/ruby-2.2.1/gems/haml-4.0.7/lib/haml/engine.rb:135:in `instance_eval'
    from /Users/andrekibbe/.rvm/gems/ruby-2.2.1/gems/haml-4.0.7/lib/haml/engine.rb:135:in `ensure in render'
    from /Users/andrekibbe/.rvm/gems/ruby-2.2.1/gems/haml-4.0.7/lib/haml/engine.rb:135:in `render'
    from haml_example.rb:17:in `<main>'

我对 Haml::Engine#render 语法感到困惑,根据 documentation 将块作为其三个参数中的最后一个 — 而在上面的代码中,块是第一个两个参数。为什么块应该设置为 "nil"?

您正在使用 nil 作为 scopeEngine#render 的第一个参数) nil 冻结在 Ruby 2.2.

p nil.frozen? # Prints false in Ruby 2.0
p nil.frozen? # Prints true in Ruby 2.2

无法修改冻结的对象。因此,Ruby 不允许 Haml 在 nil 作用域上执行 instance_eval。这就是我们看到错误的原因。

您的代码在 Ruby 2.0 中运行良好。我的猜测是书上的例子写在Ruby 2.2.

之前

要修复您的代码,请使用以下内容:

puts engine.render(Object.new, data)

PS:错误与render的第三个参数无关。你可以看看code of engine.rb来确认。