Визуализация шаблона наклона с использованием блока в качестве области видимости

Я использую template.erb в качестве примера шаблона, который содержит: <%= @text %>.

Я хотел бы иметь возможность отображать шаблон наклона с областью действия block.

Я сделал это, что работает:

proc = Proc.new do
  @text = "Hello, World"
  Tilt.new('template.erb').render self
end
proc.call # => "Hello, World"

Но я хотел бы отобразить шаблон вне блока, например:

proc = Proc.new do
  @text = "Hello, World"
end
tilt = Tilt.new('template.erb')
# I tried these alternatives:
tilt.render proc         # => ""
tilt.render proc.binding # => ""
tilt.render &proc        # => ""

Однако мне это удалось, когда я использовал стандартную библиотеку ERB следующим образом:

proc = Proc.new do
  @text = "Hello, World"
  @num = 100
end
ERB.new('<%= @text %> | <%= @num %>').result proc.binding # => "Hello, World | 100"

Тем не менее, я все еще хотел бы использовать Tilt, потому что я хочу поддерживать другие механизмы шаблонов.


person August    schedule 25.05.2014    source источник
comment
@zishe Нет, он ожидает масштаба, и это поднимает TypeError: can't define singleton   -  person August    schedule 26.05.2014


Ответы (1)


Однако мне это удалось, когда я использовал стандартную библиотеку ERB следующим образом:

proc = Proc.new do
  @text = "Hello, World"
  @num = 100
end

ERB.new('<%= @text %> | <%= @num %>').result proc.binding # => "Hello, World | 100"

Если я вставлю строку require 'erb' в начало вашего кода и добавлю 'p' к вашей последней строке, я получу следующий вывод:

" | "

Я проверил это на рубинах: 1.8.7, 1.9.3, 2.0, 2.1.

Причина, по которой @text и @num равны нулю, заключается в том, что они не являются частью привязки proc. Во-первых, код в блоке, как и код в def, даже не выполняется до тех пор, пока блок не будет вызван, поэтому не имеет значения, является ли процедура пустой или имеет в ней переменные @, если процедура никогда не выполняется.

Во-вторых, единственные привязки (т. е. переменные и их значения в окружающей области видимости), которые могут быть видны вашей процедуре, — это self=main. И переменная @ присоединяется к любому объекту, который является self, когда переменная @ появляется. В результате, когда ваш proc все-таки выполнится, переменные @ улетят и прикрепятся к main, что означает, что они вообще не будут иметь никакой связи с вашим proc.

В-третьих, вы даже не можете изменить значение для себя в привязке:

class Dog
  def bark(proc_obj)
    #self is a dog instance in here
    proc_obj.call 
    p @text
  end
end


my_proc = Proc.new{@text = "hello"}
Dog.new.bark my_proc

puts @text

--output:--
nil 
hello

Когда процедура выполняется, в окружающей области видимости есть переменная с именем self, и ее значением является экземпляр собаки, однако переменная @ в процедуре присоединяется к self=main (последний оператор puts показывает это), а не к self=dog_instance . Для меня это указывает на то, что self действует как локальная переменная, и процесс закрывается по локальной переменной с именем self в области верхнего уровня. Затем в def ruby ​​создает еще одну локальную переменную с именем self, которую ruby ​​устанавливает равной экземпляру собаки, вызвавшему def. В результате self верхнего уровня и self в def являются двумя разными переменными, и поэтому значение self в def не влияет на значение, которое proc видит для себя.

Наконец, если вы посмотрите документацию для ruby ​​2.1, класс Binding теперь имеет метод для извлечения переменных из привязки, и он называется local_variable_get(). Обратите внимание на имя local. Не существует метода с именем instance_variable_get(), потому что, насколько я могу судить, переменные экземпляра не являются частью привязки — вместо этого они улетают и прикрепляются к какому-то объекту, т. е. тому, чему я был равен во время создания процедуры — не чему равен self при выполнении proc.

person 7stud    schedule 27.05.2014
comment
Спасибо, я никогда не переставал думать, что могу получить доступ к переменным @ с помощью старого доброго self - person August; 28.05.2014