Ruby šablon: Jak předat proměnné do inline ERB?

hlasů
51

Mám šablonu ERB inline do Ruby kód:

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

Nemohu předat proměnnou „aktuální“ do šablony.

Chyba je:

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

Jak mohu tento problém vyřešit?

Položena 27/08/2009 v 06:08
zdroj uživatelem
V jiných jazycích...                            


9 odpovědí

hlasů
57

Pro jednoduché řešení, použijte 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

Výše uvedený kód je natolik jednoduchý, ale má (alespoň) dva problémy: 1) Vzhledem k tomu, že se opírá o OpenStruct, přístup do neexistující proměnná vrátí nil, zatímco vy byste asi raději, že to propadlo hlučně. 2) bindingje volána v rámci bloku, to je v uzávěru, takže zahrnuje všechny lokální proměnné v rozsahu (ve skutečnosti, budou tyto proměnné stín atributy struct!).

Takže tady je další řešení, více upovídaný, ale aniž by některý z těchto problémů:

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

Samozřejmě, pokud budete používat to často, ujistěte se, že vytvořit String#erbrozšíření, které vám umožní napsat něco podobného "x=<%= x %>, y=<%= y %>".erb(x: 1, y: 2).

Odpovězeno 28/03/2011 v 17:27
zdroj uživatelem

hlasů
20

Jednoduché řešení pomocí Binding :

b = binding
b.local_variable_set(:a, 'a')
b.local_variable_set(:b, 'b')
ERB.new(template).result(b)
Odpovězeno 18/01/2015 v 02:53
zdroj uživatelem

hlasů
10

Mám to!

I vytvořit třídu vázání

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

a předat instance pro 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

Soubor .erb šablony vypadá takto:

Key: <%= @key %>
Odpovězeno 27/08/2009 v 14:35
zdroj uživatelem

hlasů
5

V kódu z původní otázce, stačí vyměnit

result = template.result

s

result = template.result(binding)

Že bude používat kontext každého bloku spíše než kontextu nejvyšší úrovně.

(Just vytáhl k předložení připomínek @sciurus jako odpověď, protože je to nejkratší a nejsprávnější jeden.)

Odpovězeno 06/01/2016 v 18:32
zdroj uživatelem

hlasů
5
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/

Odpovězeno 08/01/2014 v 01:25
zdroj uživatelem

hlasů
4

Nemohu vám dát dobrou odpověď na to, proč se to děje, protože nejsem 100% jistý, jak ERB funguje, ale jen při pohledu na ERB RDocs , říká, že budete potřebovat binding, který je a Binding or Proc object which is used to set the context of code evaluation.Snaha svůj výše uvedený kód znovu a jen nahradí result = template.resultse result = template.result(binding)dělal to fungovat.

Jsem si jistý / naději, že někdo bude skákat sem a poskytují podrobnější vysvětlení toho, co se děje. Na zdraví.

EDIT: Pro některé další informace o Bindinga dělat všechny tyto trochu jasnější (alespoň pro mě), podívejte se na Závazné RDoc .

Odpovězeno 27/08/2009 v 06:14
zdroj uživatelem

hlasů
0

Stejně jako jiní říkali, vyhodnotit ERB s nějakým souborem proměnných, budete potřebovat správné vazby. Existují nějaké řešení s definujících tříd a metod, ale myslím, že nejjednodušší a dává maximální kontrolu a nejbezpečnější je generovat čistý vázání a použít jej analyzovat ERB. Tady je můj pohled na něj (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)

Myslím, že se evali bez **totéž lze provést pracovat se staršími rubínem než 2,1

Odpovězeno 28/12/2015 v 21:45
zdroj uživatelem

Odpovězeno 06/04/2015 v 20:59
zdroj uživatelem

hlasů
0

EDIT : To je špinavá řešení. Viz moje jinou odpověď.

Je to zcela zvláštní, ale přidávání

current = ""

před „pro-každý“ smyčka řeší problém.

Bůh žehnej skriptovacích jazyků a jejich „jazykové vlastnosti“ ...

Odpovězeno 27/08/2009 v 10:37
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more