Why does `a.is_a? Array && !a.empty?` raise NoMethodError?

不羁的心 提交于 2020-01-15 04:19:06

问题


I'm a Python developer and I just started learning Rails, so this might be a noobish question. I found some surprising behavior in my code:

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

This results in the following error: undefined method `empty?' for nil:NilClass

It seems like Ruby should not be calling .empty? in the second part of this clause. I confirmed that short-circuit evaluation works in other cases:

# 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__'

Anyone know why this behavior is happening? Seems to only trigger when I use is_a? and not the other operators.


回答1:


This is happening because you are using space and not brackets for the parameters of is_a? function so rails is trying to send the whole thing as a parameter. Try it like this

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

Explanation:

when you write flash[:notice].is_a? Array && !flash[:notice].empty? rails interpret it like flash[:notice].is_a?(Array && !flash[:notice].empty?) so Array is evaluated as true and !flash[:notice].empty? is evaluated which raises the exception.




回答2:


It's because NilClass does not respond to empty:

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

While it responds to is_a?:

nil.respond_to? :is_a?
#=> true

Shows all methods nil respond to:

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__]


If you fix by checking first the existence of the value for the key :notice, as this example shows: https://api.rubyonrails.org/classes/ActionDispatch/Flash.html, a syntax error is raised, which points to the parenthesis missing:
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?
#                              ^~~~~


来源:https://stackoverflow.com/questions/58052202/why-does-a-is-a-array-a-empty-raise-nomethoderror

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!