Yakut şablonlar: Nasıl inlined ERB içine değişkenleri geçmek?

oy
51

Ben Ruby koduna inlined bir ERB şablon var:

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

Ben şablonuna değişkeni akımını geçemez.

hatadır:

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

Bunu nasıl düzeltebilirim?

Oluştur 27/08/2009 saat 06:08
kaynak kullanıcı
Diğer dillerde...                            


9 cevaplar

oy
57

Basit bir çözüm için kullanmak 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

Yukarıdaki kod yeteri kadar basit ama vardır (en azından) iki sorun: o kurması gerektiğinden 1) OpenStruct, var olmayan değişken getirilere bir erişim nilbunu gürültüyle başarısız olduğunu muhtemelen tercih ediyorum iken. 2) binding, bir blok içinde denilen o (aslında, bu değişkenler yapının özelliklerini gölge olacak kapsamında tüm yerel değişkenleri içeren böylece, bir mahfaza içinde, bu kadar olur!).

Yani burada daha ayrıntılı ancak bu sorunların hiçbiri olmadan başka bir çözüm vardır:

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

Sık sık bu kullanacağız Tabii ki, eğer, bir oluşturmak emin olun String#erbgibi bir şey yazmak için izin verir uzantısı "x=<%= x %>, y=<%= y %>".erb(x: 1, y: 2).

Cevap 28/03/2011 saat 17:27
kaynak kullanıcı

oy
20

Kullanarak basit çözüm Cilt :

b = binding
b.local_variable_set(:a, 'a')
b.local_variable_set(:b, 'b')
ERB.new(template).result(b)
Cevap 18/01/2015 saat 02:53
kaynak kullanıcı

oy
10

Anladım!

Bir bağlamaları sınıf oluşturmak

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

ve ERB için bir örneği geçmesi

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

.erb şablon dosyası şuna benzer:

Key: <%= @key %>
Cevap 27/08/2009 saat 14:35
kaynak kullanıcı

oy
5

Orijinal sorudan kodunda, sadece yerine

result = template.result

ile

result = template.result(binding)

Yani üst düzey bağlamında yerine her bloğun içeriği kullanacaktır.

(Sadece en kısa ve en doğru biri olduğu için cevap olarak @sciurus tarafından yorumunu çıkarılan.)

Cevap 06/01/2016 saat 18:32
kaynak kullanıcı

oy
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/

Cevap 08/01/2014 saat 01:25
kaynak kullanıcı

oy
4

Ben% 100 ERB nasıl çalıştığını emin, ama sadece bakarak değilim çünkü bu oluyor neden olarak size çok iyi bir cevap veremem ERB RDocs , ihtiyacınız olduğunu söyleyen bir bindingolan a Binding or Proc object which is used to set the context of code evaluation.tekrar yukarıdaki kodu çalışılıyor ve sadece değiştirilmesi result = template.resultile result = template.result(binding)çalışması yaptı.

G / umut birisi burada atlamak ve neler olup bittiğini daha ayrıntılı bir açıklama sağlayacaktır eminim. Şerefe.

DÜZENLEME: Biraz daha ilgili bilgi için Bindingve bu biraz daha net (en azından benim için), kontrol tüm yapım Cilt RDoc .

Cevap 27/08/2009 saat 06:14
kaynak kullanıcı

oy
0

Başkaları değişkenlerden bazıları seti ile ERB değerlendirmek, dediği gibi, uygun bir bağlama gerekir. Orada tanımlayan sınıflar ve yöntemleri ile bazı çözümler vardır ama en basit ve kontrol vererek düşünmek ve en güvenli temiz bir bağlayıcı oluşturmak ve ERB ayrıştırmak için kullanmaktır. İşte o (yakut 2.2.x) almak benim:

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)

Birlikte düşünmek evalve olmayan **2.1 daha eski yakut ile çalışan yapılan edilebilir aynı

Cevap 28/12/2015 saat 21:45
kaynak kullanıcı

Cevap 06/04/2015 saat 20:59
kaynak kullanıcı

oy
0

DÜZENLEME : Bu kirli bir çözümdür. Benim diğer cevaba bakınız.

Tamamen Tuhaf ama ekleyerek

current = ""

"Için-her bir" döngü düzeltmeleri sorunu önce.

Allah betik dilleri ve onların "dil özelliklerini" korusun ...

Cevap 27/08/2009 saat 10:37
kaynak kullanıcı

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