قوالب روبي: كيفية تمرير المتغيرات في ERB المطلقة؟

StackOverflow https://stackoverflow.com/questions/1338960

  •  20-09-2019
  •  | 
  •  

سؤال

لدي قالب ERB ممطر إلى رمز 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

لا أستطيع تمرير المتغير "الحالي" في القالب.

الخطأ هو:

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

كيف يمكنني حل هذه المشكلة؟

هل كانت مفيدة؟

المحلول 3

فهمتك!

أقوم بإنشاء فئة ارتباطات

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

وتمرير مثيل إلى 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

يبدو ملف القالب .يرب مثل هذا:

Key: <%= @key %>

نصائح أخرى

لحل بسيط، استخدم افتتح:

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

الرمز أعلاه بسيط بما فيه الكفاية ولكن لديه (على الأقل) مشكلتين: 1) لأنه يعتمد على OpenStruct, ، الوصول إلى عوائد متغيرة غير موجودة nil بينما كنت تريد أن تفضل أنه فشل صاخبة. 2) binding يسمى داخل كتلة، هذا كل شيء، في إغلاق، لذلك يتضمن جميع المتغيرات المحلية في النطاق (في الواقع، هذه المتغيرات ستظل سمات الهيكل!).

إذن إليك حل آخر، وأكثر سرعة ولكن دون أي من هذه المشاكل:

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

بالطبع، إذا كنت ستستخدم هذا في كثير من الأحيان، تأكد من إنشاء String#erb التمديد الذي يسمح لك بكتابة شيء مثل "x=<%= x %>, y=<%= y %>".erb(x: 1, y: 2).

حل بسيط باستخدام ربط:

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

في التعليمات البرمجية من السؤال الأصلي، فقط استبدال

result = template.result

مع

result = template.result(binding)

سوف يستخدم ذلك سياق كل كتلة بدلا من سياق المستوى الأعلى.

(فقط استخراج التعليق بواسطة Sciurus كإجابة لأنها أقصر وأكثر صحة.)

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

المرجع: http://stoneship.org/essays/erb-and-the-context-object/

لا أستطيع أن أعطيك إجابة جيدة جدا لماذا يحدث هذا لأنني لست متأكدا 100٪ كيف يعمل ERB، ولكن فقط النظر إلى erb rdocs., ، يقول أنك بحاجة إلى binding ما هو "كائن ملزم أو بروك يستخدم لتعيين سياق تقييم التعليمات البرمجية".

تحاول رمزك أعلاه مرة أخرى واستبدالها فقط

result = template.result

مع

result = template.result(binding)

جعلها تعمل.

أنا متأكد من / آمل أن يقفز شخص ما هنا وتقديم شرح أكثر تفصيلا لما يحدث. هتافات.

تحرير: للحصول على بعض المعلومات الأخرى Binding وجعل كل هذا أكثر وضوحا قليلا (على الأقل بالنسبة لي)، تحقق من rdoc ملزمة.

تعديل: هذا هو الحل القذر. يرجى الاطلاع على إجابتي الأخرى.

انها غريبة تماما، ولكن إضافة

current = ""

قبل حلقة "for-every" إصلاح المشكلة.

بارك الله في البرمجة النصية ولغاتهم "ميزات اللغة" ...

كما قال آخرون، لتقييم ERB مع بعض المتغيرات، تحتاج إلى ملزمة مناسبة. هناك بعض الحلول التي تعاني من تحديد الفصول والأساليب لكنني أعتقد أن أبسط وأمنح معظم السيطرة والأكثر أمانا هي إنشاء ملزمة نظيفة واستخدامها لتحليل ERB. إليك تأخذ الأمر (روبي 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)

أعتقد مع eval ودون ** يمكن أن يكون الشيء نفسه يعمل مع روبي قديم من 2.1

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top