web-dev-qa-db-ja.com

ハッシュからの値でERBテンプレートをレンダリングします

ここでは非常に単純なものを見落とす必要がありますが、ハッシュマップの値を使用して単純なERBテンプレートをレンダリングする方法を理解できないようです。

私は、Pythonから来たRubyには比較的新しいです。 ERBテンプレート(HTMLではない)があります。これは、外部ソースから受け取るハッシュマップから取得されるコンテキストでレンダリングする必要があります。

ただし、ERBのドキュメントには、_ERB.result_メソッドがbindingを取ると記載されています。 Ruby(Pythonのlocals()globals()のようなもの、私は推測しますか?)で変数コンテキストを保持するものであることを学びました。ハッシュマップからバインドオブジェクトを構築する方法がわかりません。

少し(alot、実際)グーグルは私にこれを与えました: http://refactormycode.com/codes/281-given-a -hash-of-variables-render-an-erb-template 、Ruby私を逃れるメタプログラミングマジックを使用します。

だから、この問題の簡単な解決策はありませんか?または、これに適したより良いテンプレートエンジン(HTMLに関連付けられていない)がありますか(stdlibにあるため、ERBのみを選択しました)。

57
Shrikant Sharat

これが「よりエレガント」であるかどうかはわかりません。

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 %>')

またはクラスメソッドから:

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)

(ErbalTにはテンプレート用のErb、Tがあり、「ハーブティー」のように聞こえます。名前を付けるのは難しいです。)

56
Dave Newton
require 'erb'
require 'ostruct'

def erb(template, vars)
  ERB.new(template).result(OpenStruct.new(vars).instance_eval { binding })
end

例えば

1.9.2p290 :008 > erb("Hey, <%= first_name %> <%= last_name %>", :first_name => "James", :last_name => "Moriarty")
 => "Hey, James Moriarty" 
74
Moriarty

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"
32
Phrogz

Ruby 2.5にはERB#result_with_hashこの機能を提供します:

$ Ruby -rerb -e 'p ERB.new("Hi <%= name %>").result_with_hash(name: "Tom")'
"Hi Tom"
27
Tom Copeland

ここで注意が必要なのは、冗長なローカル変数によるバインディングを汚染しないことです(一流の回答のように)。

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)
8
Lev Lukomsky

Binding を使用した簡単なソリューション:

b = binding
b.local_variable_set(:a, 'a')
b.local_variable_set(:b, 'b')
ERB.new(template).result(b)
6
asfer

非常にシンプルにしたい場合は、ERBテンプレート内で常に明示的なハッシュルックアップを使用できます。 「バインディング」を使用して「ハッシュ」というハッシュ変数をテンプレートに渡すと、次のようになります。

<%= hash["key"] %>
4
Alex D