使用散列值渲染ERB模板

Shr*_*rat 57 ruby template-engine erb

我必须忽略一些非常简单的东西,但我似乎无法弄清楚如何使用哈希映射的值渲染一个简单的ERB模板.

来自python的我对ruby比较新.我有一个ERB模板(不是HTML),我需要使用从哈希映射中获取的上下文来渲染,我从外部源接收.

但是,ERB的文档说明该ERB.result方法需要一个binding.我才知道,他们是保持着可变背景的红宝石东西(像locals()globals()在python,我相信?).但是,我不知道如何从哈希映射中构建绑定对象.

一点点(很多,实际上)谷歌搜索给了我这个:http://refactormycode.com/codes/281-given-a-hash-of-variables-render-an-erb-template,它使用了一些红宝石元编程魔法逃避我

那么,这个问题不是一个简单的解决方案吗?或者是否有更好的模板引擎(不依赖于HTML)更适合这种情况?(我只选择了ERB,因为它在stdlib中).

Mor*_*rty 74

require 'erb'
require 'ostruct'

def render(template, vars)
  ERB.new(template).result(OpenStruct.new(vars).instance_eval { binding })
end
Run Code Online (Sandbox Code Playgroud)

例如

render("Hey, <%= first_name %> <%= last_name %>", first_name: "James", last_name: "Moriarty")
# => "Hey, James Moriarty" 
Run Code Online (Sandbox Code Playgroud)

  • 起初看起来不错,但不幸的是绑定还从实例化`OpenStruct`的上下文中继承了本地和方法.这使模板访问的方式超出预期,并可能导致错误甚至是安全漏洞,例如https://gist.github.com/aspiers/ad6549058ee423819976 (12认同)
  • +1,这是一种从哈希创建绑定的超级优雅方式. (3认同)

Dav*_*ton 57

我不知道这是否符合"更优雅"的条件:

require 'erb'
require 'ostruct'

class ErbalT < OpenStruct
  def render(template)
    ERB.new(template).result(binding)
  end
end

et = ErbalT.new({ :first => 'Mislav', 'last' => 'Marohnic' })
puts et.render('Name: <%= first %> <%= last %>')
Run Code Online (Sandbox Code Playgroud)

或者从类方法:

class ErbalT < OpenStruct
  def self.render_from_hash(t, h)
    ErbalT.new(h).render(t)
  end

  def render(template)
    ERB.new(template).result(binding)
  end
end

template = 'Name: <%= first %> <%= last %>'
vars = { :first => 'Mislav', 'last' => 'Marohnic' }
puts ErbalT::render_from_hash(template, vars)
Run Code Online (Sandbox Code Playgroud)

(ErbalT有Erb,T模板,听起来像"凉茶".命名很难.)


Phr*_*ogz 32

如果您可以使用Erubis,您已经拥有此功能:

irb(main):001:0> require 'erubis'
#=> true
irb(main):002:0> locals = { first:'Gavin', last:'Kistner' }
#=> {:first=>"Gavin", :last=>"Kistner"}
irb(main):003:0> Erubis::Eruby.new("I am <%=first%> <%=last%>").result(locals)
#=> "I am Gavin Kistner"
Run Code Online (Sandbox Code Playgroud)

  • 这很方便,因为Rails 4现在使用Erubis for ERB作为其渲染引擎. (5认同)

Tom*_*and 31

Ruby 2.5 ERB#result_with_hash提供了这个功能:

$ ruby -rerb -e 'p ERB.new("Hi <%= name %>").result_with_hash(name: "Tom")'
"Hi Tom"
Run Code Online (Sandbox Code Playgroud)

  • 这个答案是最好的答案.最近的红宝石比使用绑定更容易. (4认同)

Lev*_*sky 8

这里棘手的部分是不污染与冗余局部变量的绑定(如在评分最高的答案中):

require 'erb'

class TemplateRenderer
  def self.empty_binding
    binding
  end

  def self.render(template_content, locals = {})
    b = empty_binding
    locals.each { |k, v| b.local_variable_set(k, v) }

    # puts b.local_variable_defined?(:template_content) #=> false

    ERB.new(template_content).result(b)
  end
end

# use it
TemplateRenderer.render('<%= x %> <%= y %>', x: 1, y: 2) #=> "1 2"

# use it 2: read template from file
TemplateRenderer.render(File.read('my_template.erb'), x: 1, y: 2)
Run Code Online (Sandbox Code Playgroud)


asf*_*fer 7

使用绑定的简单解决方案:

b = binding
b.local_variable_set(:a, 'a')
b.local_variable_set(:b, 'b')
ERB.new(template).result(b)
Run Code Online (Sandbox Code Playgroud)