web-dev-qa-db-fra.com

Méthode non définie '>' pour nil: NilClass <NoMethodError>

Ok j'ai le code suivant

 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

maintenant dans la lignée de ...

 @state_turns[state.id] -= 1 if @state_turns[state.id] > 0 && state.auto_removal_timing == 1

il dit l'erreur 

in 'block update_state_actions' : Undefined method '>' for nil:NilClass <NoMethodError>

quelle est la cause de l'erreur? Comment se fait-il que > soit considéré comme une méthode mais qu’il s’agit d’un opérateur logique?

16
Mp de la Vega

comment est-il considéré comme une méthode mais comme un opérateur logique?

Il n'y a pas de problème avec ça. En Ruby, lorsque vous écrivez une expression telle que 1 + 2, elle est comprise en interne comme étant 1.+( 2 ): Appelant la méthode #+ sur le destinataire 1 avec 2 comme argument unique. Une autre façon de comprendre la même chose est que vous envoyez le message [ :+, 2 ] à l'objet 1.

quelle est la cause de l'erreur? 

Maintenant, dans votre cas, @state_turns[ state.id ] renvoie nil pour une raison quelconque. Donc, l'expression @state_turns[state.id] > 0 devient nil > 0, ce qui, comme je l'ai dit précédemment, est compris comme l'appel de la méthode #> sur nil. Mais vous pouvez vérifier que NilClass, auquel appartient nil, n'a pas de méthode d'instance #> définie:

NilClass.instance_methods.include? :> # => false
nil.respond_to? :> # => false

L'exception NoMethodError est donc une erreur légitime. En soulevant cette erreur, Ruby vous protège: Il vous avertit que votre @state_turns[ state.id ] n’est pas ce que vous supposez. De cette façon, vous pourrez corriger vos erreurs plus tôt et devenir un programmeur plus efficace. De plus, les exceptions Ruby peuvent être sauvées avec l'instruction begin ... rescue ... end. Les exceptions Ruby sont généralement des objets très conviviaux et utiles, et vous devez apprendre à définir vos exceptions personnalisées dans vos projets logiciels.

Pour prolonger un peu plus la discussion, voyons d'où vient votre erreur. Lorsque vous écrivez une expression telle que nil > 10, qui est en fait nil.>( 10 ), Ruby commence à rechercher la méthode #> dans la chaîne de recherche de nil. Vous pouvez voir la chaîne de recherche en tapant:

    nil.singleton_class.ancestors #=> [NilClass, Object, Kernel, BasicObject]

La méthode sera recherchée dans chaque module de la chaîne d'ancêtre: Ruby vérifiera d'abord si #> est défini sur NilClass, puis sur Object, puis Kernel et enfin BasicObject. Si #> n'est trouvé dans aucun d'entre eux, Ruby continuera en essayant les méthodes method_missing, toujours dans l'ordre dans tous les modules de la chaîne de recherche. Si même method_missing ne gère pas le message :>, une exception NoMethodError sera déclenchée. Pour démontrer, définissons la méthode #method_missing dans Object en insérant un message personnalisé, qui apparaîtra à la place de 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!

Pourquoi ne dit-il pas comme NullPointerException

Il n'y a pas une telle exception en Ruby. Vérifiez la classe Exception de Ruby.

51
Arup Rakshit

Il doit être converti en variable entière pour effectuer l'opération: 

  • @state_turns [state.id] .to_i> 0 
  • state_a = state.auto_removal_timing.to_i + 1
0
Osmar Valero