2017-01-11 12 views
3

我在Ruby项目中实现HTML模板(非rails)。要做到这一点,我会使用ERB,但我对绑定的东西有一些担忧。如何创建新的绑定并为其分配实例变量以实现ERB的可用性?

首先出来,这是我迄今为止方法:

def self.template(template, data) 
    template = File.read("#{ENV.root}/app/templates/#{template}.html.erb") 

    template_binding = binding.clone 

    data.each do |k, v| 
    template_binding.local_variable_set(k, v) 
    end 

    ERB.new(template).result(template_binding) 
end 

要叫它我只是做

Email.template('email/hello', { 
    name: 'Bill', 
    age: 41 
} 

没有与虽然当前的解决方案的两个问题。

首先,我克隆当前绑定。我想创建一个新的。我试过Class.new.binding来创建一个新的,但因为binding是一个私人的方法,它不能获得这种方式。 我想要一个新的原因是,我想避免实例变量的风险漏入或流出ERB文件(克隆只需要在后一种情况下的服务)。

,我想传递给ERB文件中的变量暴露为实例变量。在这里,我试图与template_binding.instance_variable_set,经过简单的哈希键k这抱怨,这不是一个有效的实例变量名和"@#{k}",这并没有抱怨,而且在ERB代码并没有得到使用。 我想使用实例变量的原因是,依赖此代码的人员熟悉这是一种惯例。

我在堆栈溢出如Render an ERB template with values from a hash这里查了一些话题,但提供不解决,我讨论的问题的答案。

因此,在短期,如标题:如何创建新的绑定,并在该局指定实例变量给它的可用性?

回答

2

1)无需复制,新的绑定为您每次创建。

我在IRB测试此:

class A; def bind; binding; end; end 
a = A.new 
bind_1 = a.bind 
bind_2 = a.bind 

bind_1.local_variable_set(:x, 2) 
=> 2 
bind_1.local_variables 
=> [:x] 
bind_2.local_variables 
=> [] 

2)打开对象Eigenclass并添加attr_accessor

class << template_binding # this opens Eigenclass for object template_binding 
    attr_accessor :x 
end 
在红宝石

所以,你可以打开任何类,并添加方法,它。 Eigenclass表示单个对象的类 - 每个对象都可以具有自定义类的定义。来自C#我无法想象这种情况下,将使用,直到现在。 :)

这样做对每个哈希

data.each do |k, v| 
    class << template_binding; attr_accessor k.to_sym; end 
    template_binding.k = v 
end 
+0

感谢马尔科,这真的有用!我猜想使用当前绑定会将当前实例变量暴露给ERB代码,但是使用类似于第一行中创建的虚拟类的东西来检索新绑定可以解决该问题。 – matsve

+1

我不明白你的恐惧 - ERB代码会为你的对象添加新的实例变量?这听起来不可能 - 在IRB中试试你的场景。如果有帮助的话,也是upvote并接受答案;) –

+0

这是我所尝试的恐惧之一,正如你所说的那样,它似乎并没有那样工作。另外,ERB代码可能会得到它不应该使用的实例变量。我希望100%明确将数据传递给ERB。你的回答对我有帮助,所以我投了赞成票并接受了它。非常感谢:) – matsve

相关问题