Почему `a.is_a?Array &&! A.empty? `Повысить NoMethodError? - PullRequest
2 голосов
/ 22 сентября 2019

Я разработчик Python, и я только начал изучать Rails, так что это может быть глупым вопросом.Я обнаружил в своем коде неожиданное поведение:

<!-- render flash message array if set -->
<% if flash[:notice].is_a? Array && !flash[:notice].empty? %>

Это приводит к следующей ошибке: undefined method `empty?' for nil:NilClass

Кажется, что Ruby не должен вызывать .empty? во второй частиэтот пункт.Я подтвердил, что оценка короткого замыкания работает в других случаях:

# this is more what I expected
[3] pry(main)> a = nil
=> nil
[5] pry(main)> !a.nil? && a.empty?
=> false
...
[6] pry(main)> a = 1
=> 1
[7] pry(main)> !a.nil? && a.empty?
NoMethodError: undefined method `empty?' for 1:Integer
from (pry):7:in `__pry__'

Кто-нибудь знает, почему это происходит?Кажется, срабатывает только тогда, когда я использую is_a?, а не другие операторы.

Ответы [ 2 ]

8 голосов
/ 22 сентября 2019

Это происходит потому, что вы используете пробел, а не скобки для параметров функции is_a?, поэтому rails пытается отправить все это как параметр.Попробуйте это так

<% if flash[:notice].is_a?(Array) && !flash[:notice].empty? %>

Объяснение:

когда вы пишете flash[:notice].is_a? Array && !flash[:notice].empty? рельсы интерпретируют это как flash[:notice].is_a?(Array && !flash[:notice].empty?), поэтому Array оценивается как true и !flash[:notice].empty?что вызывает исключение.

1 голос
/ 22 сентября 2019

Это потому, что NilClass не отвечает на empty:

nil.class #=> NilClass
nil.respond_to? :empty?
#=> false

Пока отвечает на is_a?:

nil.respond_to? :is_a?
#=> true

Показывает все методы nil отвечает на:

nil.methods
#=> [:&, :inspect, :to_a, :to_s, :===, :to_f, :to_i, :=~, :to_h, :nil?, :to_r, :rationalize, :|, :to_c, :^, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :protected_methods, :instance_variables, :instance_variable_get, :public_methods, :private_methods, :method, :public_method, :public_send, :singleton_method, :define_singleton_method, :extend, :to_enum, :enum_for, :<=>, :!~, :eql?, :respond_to?, :freeze, :object_id, :send, :display, :hash, :class, :singleton_class, :clone, :dup, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :equal?, :!, :==, :instance_exec, :!=, :instance_eval, :__id__, :__send__]


Если исправить, проверив сначала наличие значения для ключа :notice, как показано в этом примере: https://api.rubyonrails.org/classes/ActionDispatch/Flash.html, возникает синтаксическая ошибка, которая указываетв скобках отсутствует:
flash[:notice] && flash[:notice].is_a? Array && flash[:notice].empty?
# syntax error, unexpected tCONSTANT, expecting end-of-input
# ...] && flash[:notice].is_a? Array && flash[:notice].empty?
#                              ^~~~~
...