web-dev-qa-db-fra.com

Rendre un modèle ERB avec des valeurs d'un hachage

Je dois ignorer quelque chose de très simple ici, mais je n'arrive pas à comprendre comment rendre un modèle ERB simple avec des valeurs d'une table de hachage.

Je suis relativement nouveau pour Ruby, venant de python. J'ai un modèle ERB (pas HTML), dont j'ai besoin rendu avec le contexte qui doit être pris à partir d'une carte de hachage, que je reçois d'une source externe.

Cependant, la documentation d'ERB indique que la méthode ERB.result Prend un binding. J'ai appris qu'ils contiennent des contextes variables dans Ruby (quelque chose comme locals() et globals() en python, je suppose?). Mais, Je ne sais pas comment créer un objet de liaison à partir de ma carte de hachage.

Un peu (un beaucoup , en fait) googler m'a donné ceci: http://refactormycode.com/codes/281-given-a -hash-of-variables-render-an-erb-template , qui utilise une magie de métaprogrammation Ruby qui m'échappe).

Alors, n'y a-t-il pas une solution simple à ce problème? Ou existe-t-il un meilleur moteur de modélisation (non lié au HTML) mieux adapté à cela? (J'ai seulement choisi ERB parce que c'est dans le stdlib).

57
Shrikant Sharat

Je ne sais pas si cela peut être qualifié de "plus élégant" ou non:

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

Ou à partir d'une méthode de classe:

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 a Erb, T pour modèle et sonne comme "tisane". Nommer les choses est difficile.)

56
Dave Newton
require 'erb'
require 'ostruct'

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

par exemple

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

Si vous pouvez utiliser Erubis vous avez déjà cette fonctionnalité:

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 a ERB#result_with_hash qui fournit cette fonctionnalité:

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

La partie délicate ici n'est pas de polluer la liaison avec des variables locales redondantes (comme dans les réponses les mieux notées):

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

Solution simple utilisant Binding :

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

Si vous voulez faire les choses très simplement, vous pouvez toujours utiliser des recherches de hachage explicites dans le modèle ERB. Imaginons que vous utilisiez "binding" pour passer une variable de hachage appelée "hash" dans le modèle, cela ressemblerait à ceci:

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