57 Stimmen

Ruby-Vorlagen: Wie kann man Variablen in inlined ERB übergeben?

Ich habe eine ERB-Vorlage in den Ruby-Code eingefügt:

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

Ich kann die Variable "current" nicht an die Vorlage übergeben.

Der Fehler ist:

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

Wie kann ich das beheben?

4voto

theIV Punkte 24844

Ich kann nicht genau sagen, warum das passiert, weil ich nicht 100% sicher bin, wie ERB funktioniert, aber ich habe mir die ERB RDocs heißt es, dass Sie eine binding das "ein Binding- oder Proc-Objekt ist, das verwendet wird, um den Kontext der Codeauswertung festzulegen".

Versuchen Sie Ihren obigen Code erneut und ersetzen Sie einfach

result = template.result

mit

result = template.result(binding)

hat es funktioniert.

Ich bin sicher/hoffe, dass sich hier jemand einmischt und genauer erklärt, was hier vor sich geht. Prost.

EDIT: Für weitere Informationen über Binding und das alles ein wenig klarer zu machen (zumindest für mich), sehen Sie sich die Bindung RDoc .

3voto

Die sauberste Lösung wäre vielleicht die Verabschiedung spezifischer current lokale Variable an die erb-Vorlage zu übergeben, anstatt die gesamte binding . Es ist möglich mit ERB#Ergebnis_mit_Hash Methode (eingeführt in Ruby 2.5)

DATA.keys.each do |current|
  result = template.result_with_hash(current: current)
...

1voto

akostadinov Punkte 16114

Wie bereits gesagt, benötigen Sie für die Auswertung von ERB mit einer Reihe von Variablen eine geeignete Bindung. Es gibt einige Lösungen mit der Definition von Klassen und Methoden, aber ich denke, die einfachste und sicherste ist es, eine saubere Bindung zu erzeugen und sie zum Parsen der ERB zu verwenden. Hier ist meine Meinung dazu (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)

Ich denke, mit eval und ohne ** dasselbe kann mit älterem Ruby als 2.1 gemacht werden

0voto

EDIT : Dies ist ein unsauberer Workaround. Bitte lesen Sie meine andere Antwort.

Es ist total seltsam, aber das Hinzufügen von

current = ""

vor der "for-each"-Schleife behebt das Problem.

Gott segne Skriptsprachen und ihre "Sprachfunktionen"...

0 Stimmen

Ich denke, das liegt daran, dass Blockparameter in Ruby 1.8 keine echten gebundenen Variablen sind. Das hat sich in Ruby 1.9 geändert.

1 Stimmen

Die Standardbindung, die ERB zur Auswertung der Variablen verwendet, ist die Bindung der obersten Ebene. Ihre Variable "current" existiert nicht in der Bindung der obersten Ebene, es sei denn, Sie verwenden sie dort zuerst (weisen ihr einen Wert zu).

0voto

Alex Levine Punkte 1261

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X