Переменная экземпляра Ruby в шаблоне Puppet (erb)

Я не понимаю поведение этого кода Ruby, который я написал внутри шаблона Puppet (erb). Это должно быть связано с каким-то свойством переменных экземпляра, которое я игнорирую и не смог выяснить.

На стороне Puppet переменная $local_users может быть объявлена ​​(и инициализирована) или нет в файле site.pp. В коде шаблона, показанном ниже, предложение if проверяет, было ли оно ранее инициализировано.

<% if @local_users -%>
  <%= fail('local_users has to be an array') unless local_users.class == Array -%>
<% else -%>
  <% local_users = [ "root" ] -%>
  <%# some code to add more users to the array -%>
<% end -%>
<% local_users.uniq.each do |user| -%>
  <%= user %>
<% end -%>

Если $local_users не объявлен в файле site.pp (else ветка), этот код работает безупречно. Если он объявлен (если ветвь), то он терпит неудачу при попытке применить манифест Puppet:

Failed to parse template sendmail/local-users.erb: undefined method `uniq' for nil:NilClass at /usr/share/puppet/modules/sendmail/manifests/config.pp:39

(строка 39 — это место, где вызывается шаблон: content => template('sendmail/sendmail.mc.erb'),)

Проблема в том, что в цикле переменная local_users не распознается как массив. Я решил проблему, просто объявив локальную переменную в ветке if:

<% if @local_users -%>
  <%= fail('local_users has to be an array') unless local_users.class == Array -%>
  <% local_users = @local_users -%>
<% else -%>

Но внутри ветки if это массив, так как local.users.class == Array возвращает true (в этот момент я также могу без проблем использовать метод local_users.uniq). Кроме того, я пробовал с if local_users (без @) и внутри ветки if local_users по-прежнему является массивом, но в цикле продолжаются сбои.

Вот мои вопросы:

  1. Как можно объяснить такое поведение? Почему переменная local_users представляет собой массив внутри ветки if, а не в цикле?
  2. Верен ли мой обходной путь или есть лучшие способы сделать это?

person Christian    schedule 22.06.2012    source источник


Ответы (1)


Так как в Ruby nil это объект со своим классом (NilClass) и так как (попробуйте это с irb):

nil.respond_to? :class
# => true

оператор local_users.class == Array возвращает false.

local_user — это переменная, локальная для представления, а @local_user — переменная экземпляра контроллера, стоящего за этим представлением.

Это две разные вещи, поэтому вам нужно присвоить local_user @local_user, чтобы не было nil при вызове local_users.uniq.

Кстати, почему вы работаете с local_users вместо того, чтобы просто использовать @local_users и перенести всю логику на контроллер?

person Andrea Salicetti    schedule 22.06.2012
comment
Упс, вы правы: этот совет имеет смысл только на сильной архитектуре MVC. Все остальное остается. - person Andrea Salicetti; 22.06.2012
comment
Спасибо @андреа. Как сказал @mark, я не думаю, что контроллер - лучший термин в этом случае. По определению переменная экземпляра принадлежит самому объекту, в котором она создана (т.е. себе). В этом случае self — это весь шаблон. В любом случае, позвольте мне отметить странное поведение, о котором я говорил: если я поместил test_class = local_users.uniq в ветку if, это сработает (т. е. local_users.class — это Array)! Это как если бы областью действия локальной переменной была ветвь if... - person Christian; 22.06.2012
comment
Кстати, он отлично работает, если я всегда использую @local_users (внутри ветвей if и else и в цикле). Кажется, это способ следовать. Но опять же, почему local_users является массивом внутри ветки if, а не в цикле? - person Christian; 22.06.2012
comment
Не могли бы вы лучше объяснить мне, что вы имеете в виду, когда говорите: «... но в цикле все время происходит сбой»? - person Andrea Salicetti; 22.06.2012
comment
Да, я имею в виду, что в строке local_users.uniq.each do |user| local_users ноль (как вы указали в своем первом ответе), и поэтому я получаю сообщение об ошибке. Предполагаемое поведение будет заключаться в том, что local_users будет массивом, поскольку он находится внутри ветки if. - person Christian; 22.06.2012