0

我使用template.erb作为我的模板示例,其中包含:<%= @text %>.

我希望能够渲染范围为block.

我已经这样做了,它有效:

proc = Proc.new do
  @text = "Hello, World"
  Tilt.new('template.erb').render self
end
proc.call # => "Hello, World"

但我想在块之外渲染模板,如下所示:

proc = Proc.new do
  @text = "Hello, World"
end
tilt = Tilt.new('template.erb')
# I tried these alternatives:
tilt.render proc         # => ""
tilt.render proc.binding # => ""
tilt.render &proc        # => ""

但是,当我像这样使用标准 ERB 库时,我成功了:

proc = Proc.new do
  @text = "Hello, World"
  @num = 100
end
ERB.new('<%= @text %> | <%= @num %>').result proc.binding # => "Hello, World | 100"

不过,我仍然想使用 Tilt,因为我想支持其他模板引擎。

4

1 回答 1

0

但是,当我像这样使用标准 ERB 库时,我成功了:

proc = Proc.new do
  @text = "Hello, World"
  @num = 100
end

ERB.new('<%= @text %> | <%= @num %>').result proc.binding # => "Hello, World | 100"

require 'erb'如果我在代码的开头插入该行,并且如果我将“p”附加到最后一行,我得到的输出是:

" | "

我在红宝石中进行了测试:1.8.7、1.9.3、2.0、2.1。

@text 和 @num 为 nil 的原因是它们不是 proc 绑定的一部分。首先,块中的代码,就像 def 中的代码一样,在调用块之前甚至不会执行,因此如果 proc 从未执行,则 proc 是空的还是其中有 @ 变量都没有区别。

其次,您的 proc 可以看到的唯一绑定(即周围范围内的变量及其值)是 self=main。当@ 变量出现时,@ 变量会将其自身附加到 self 的任何对象。结果,当您的 proc 执行时,@ 变量将飞走并附加到 main,这意味着它们与您的 proc 完全没有关联。

第三,您甚至不能在绑定中更改 self 的值:

class Dog
  def bark(proc_obj)
    #self is a dog instance in here
    proc_obj.call 
    p @text
  end
end


my_proc = Proc.new{@text = "hello"}
Dog.new.bark my_proc

puts @text

--output:--
nil 
hello

当 proc 执行时,周围范围内有一个名为 self 的变量,它的值是 dog 实例——但 proc 中的 @ 变量将自身附加到 self=main(最后一个 puts 语句显示)而不是 self=dog_instance . 对我来说,这表明 self 就像一个局部变量,并且 proc 关闭了顶层范围内名为 self 的局部变量。然后,在 def 中,ruby 创建了另一个名为 self 的局部变量,ruby 将其设置为等于调用 def 的 dog 实例。结果,顶层self和def中的self是两个不同的变量,因此def中self的值对proc看到的self值没有影响。

最后,如果您查看 ruby​​ 2.1 的文档,Binding 类现在有一个从绑定中检索变量的方法,它被称为local_variable_get(). 注意名称local。没有命名方法instance_variable_get(),因为据我所知,实例变量不是绑定的一部分——相反,它们飞走并将自己附加到某个对象上,即在创建 proc 时 self 等于什么——而不是什么self 等于 proc 执行的时间。

于 2014-05-27T23:30:38.820 回答