for code ruby templates syntax erb

code - erb ruby syntax



Plantillas de Ruby: ¿Cómo pasar variables a ERB en línea? (9)

¡Lo tengo!

Creo una clase de enlaces

class BindMe def initialize(key,val) @key=key @val=val end def get_binding return binding() end end

y pasar una instancia a ERB

dataHash.keys.each do |current| key = current.to_s val = dataHash[key] # here, I pass the bindings instance to ERB bindMe = BindMe.new(key,val) result = template.result(bindMe.get_binding) # unnecessary code goes here end

El archivo de plantilla .erb se ve así:

Key: <%= @key %>

Tengo una plantilla de ERB incorporada en el código de Ruby:

require ''erb'' DATA = { :a => "HELLO", :b => "WORLD", } template = ERB.new <<-EOF current key is: <%= current %> current value is: <%= DATA[current] %> EOF DATA.keys.each do |current| result = template.result outputFile = File.new(current.to_s,File::CREAT|File::TRUNC|File::RDWR) outputFile.write(result) outputFile.close end

No puedo pasar la variable "actual" en la plantilla.

El error es:

(erb):1: undefined local variable or method `current'' for main:Object (NameError)

¿Cómo puedo solucionar esto?


Como otros dijeron, para evaluar ERB con un conjunto de variables, necesita un enlace adecuado. Hay algunas soluciones para definir clases y métodos, pero creo que lo más simple y que da más control y lo más seguro es generar un enlace limpio y usarlo para analizar el ERB. Aquí está mi opinión (ruby 2.2.x):

module B def self.clean_binding binding end def self.binding_from_hash(**vars) b = self.clean_binding vars.each do |k, v| b.local_variable_set k.to_sym, v end return b end end my_nice_binding = B.binding_from_hash(a: 5, **other_opts) result = ERB.new(template).result(my_nice_binding)

Creo que con eval y sin ** mismo se puede hacer trabajando con ruby ​​más antiguo que 2.1


En el código de la pregunta original, simplemente reemplace

result = template.result

con

result = template.result(binding)

Eso usará el contexto de cada bloque en lugar del contexto de nivel superior.

(Acabo de extraer el comentario de @sciurus como respuesta porque es el más corto y el más correcto).



No puedo darle una muy buena respuesta sobre por qué sucede esto porque no estoy 100% seguro de cómo funciona ERB, pero solo mirando los RDocs de ERB , dice que necesita un binding que sea a Binding or Proc object which is used to set the context of code evaluation. Probar el código anterior de nuevo y simplemente reemplazar result = template.result con result = template.result(binding) hizo funcionar.

Estoy seguro / espero que alguien salte aquí y brinde una explicación más detallada de lo que está sucediendo. Aclamaciones.

EDIT: para obtener más información sobre Binding y hacer todo esto un poco más claro (al menos para mí), consulte el Binding RDoc .


Para una solución simple, use OpenStruct :

require ''erb'' require ''ostruct'' namespace = OpenStruct.new(name: ''Joan'', last: ''Maragall'') template = ''Name: <%= name %> <%= last %>'' result = ERB.new(template).result(namespace.instance_eval { binding }) #=> Name: Joan Maragall

El código anterior es bastante simple pero tiene (al menos) dos problemas: 1) Dado que se basa en OpenStruct , el acceso a una variable no existente devuelve OpenStruct , mientras que probablemente prefiera que haya fallado ruidosamente. 2) el binding se llama dentro de un bloque, eso es todo, en un cierre, por lo que incluye todas las variables locales en el alcance (de hecho, estas variables sombrearán los atributos de la estructura!).

Aquí hay otra solución, más detallada, pero sin ninguno de estos problemas:

class Namespace def initialize(hash) hash.each do |key, value| singleton_class.send(:define_method, key) { value } end end def get_binding binding end end template = ''Name: <%= name %> <%= last %>'' ns = Namespace.new(name: ''Joan'', last: ''Maragall'') ERB.new(template).result(ns.get_binding) #=> Name: Joan Maragall

Por supuesto, si vas a usar esto a menudo, asegúrate de crear una extensión String#erb que te permita escribir algo como "x=<%= x %>, y=<%= y %>".erb(x: 1, y: 2) .


Solución simple usando Binding :

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


EDITAR : Esta es una solución sucia. Por favor mira mi otra respuesta.

Es totalmente extraño, pero agregar

current = ""

antes de que el ciclo "for-each" solucione el problema.

Dios bendiga los lenguajes de scripting y sus "características del lenguaje" ...


require ''erb'' class ERBContext def initialize(hash) hash.each_pair do |key, value| instance_variable_set(''@'' + key.to_s, value) end end def get_binding binding end end class String def erb(assigns={}) ERB.new(self).result(ERBContext.new(assigns).get_binding) end end

REF: http://stoneship.org/essays/erb-and-the-context-object/