Ok I do have the following code
def update_state_actions
states.each do |state|
@state_turns[state.id] -= 1 if @state_turns[state.id] > 0 && state.auto_removal_timing == 1
end
end
now in the line of...
@state_turns[state.id] -= 1 if @state_turns[state.id] > 0 && state.auto_removal_timing == 1
it says the error
in 'block update_state_actions' : Undefined method '>' for nil:NilClass <NoMethodError>
what is the cause of the error? how come >
is considered as a method but it is a logical operator?
how come > is considered as a method but it is a logical operator?
There is no problem with that. In Ruby, when you write an expression like 1 + 2
, internally it is understood as 1.+( 2 )
: Calling method #+
on the receiver 1
with 2
as a single argument. Another way to understand the same is, that you are sending the message [ :+, 2 ]
to the object 1
.
what is the cause of the error?
Now in your case, @state_turns[ state.id ]
returns nil
for some reason. So the expression @state_turns[state.id] > 0
becomes nil > 0
, which, as I said earlier, is understood as calling #>
method on nil
. But you can check that NilClass
, to which nil
belongs, has no instance method #>
defined on it:
NilClass.instance_methods.include? :> # => false
nil.respond_to? :> # => false
The NoMethodError
exception is therefore a legitimate error. By raising this error, Ruby protects you: It tells you early that your @state_turns[ state.id ]
is not what you assume it to be. That way, you can correct your errors earlier, and be a more efficient programmer. Also, Ruby exceptions can be rescued with begin ... rescue ... end
statement. Ruby exceptions are generally very friendly and useful objects, and you should learn how to define your custom exceptions in your software projects.
To extend this discussion a bit more, let's look at from where your error is coming. When you write an expression like nil > 10
, which is actually nil.>( 10 )
, Ruby starts searching for #>
method in the lookup chain of nil
. You can see the lookup chain by typing:
nil.singleton_class.ancestors #=> [NilClass, Object, Kernel, BasicObject]
The method will be searched in each module of the ancestor chain: First, Ruby will check whether #>
is defined on NilClass
, then on Object
, then Kernel
, and finally, BasicObject
. If #>
is not found in any of them, Ruby will continue by trying method_missing
methods, again in order on all the modules of the lookup chain. If even method_missing
does not handle the :>
message, NoMethodError
exception will be raised. To demonstrate, let's define #method_missing
method in Object
by inserting a custom message, that will appear instead of NoMethodError
:
class Object
def method_missing( name, *args )
puts "There is no method '##{name}' defined on #{self.class}, you dummy!"
end
end
[ 1, 2, 3 ][ 3 ] > 2
#=> There is no method '#>' defined on NilClass, you dummy!
Why doesn't it says like NullPointerException
There is no such exception in Ruby. Check the Ruby's Exception
class.