182 votes

Équivalent de .try () pour un hachage?

Dans Rails, nous pouvons procéder comme suit au cas où une valeur n'existe pas pour éviter une erreur:

 @myvar = @comment.try(:body)
 

Quel est l'équivalent lorsque je creuse dans un hachage et que je ne veux pas d'erreur?

 @myvar = session[:comments][@comment.id]["temp_value"] 
# [:comments] may or may not exist here
 

Dans le cas ci-dessus, session[:comments]try[@comment.id] ne fonctionne pas. Quel serait?

290voto

Andrew Grimm Points 22996

Vous avez oublié de mettre . avant le try :

 @myvar = session[:comments].try(:[], @comment.id)
 

Puisque [] est le nom de la méthode lorsque vous faites [@comment.id] .

25voto

Arsen7 Points 5534

La plus belle solution est une vieille réponse par Mladen Jablanović, car il vous permet de vous plonger dans la table de hachage plus profond que vous pouvez avec l'aide de direct, .try() des appels, si vous voulez le code, toujours agréable à regarder:

class Hash
  def get_deep(*fields)
    fields.inject(self) {|acc,e| acc[e] if acc}
  end
end

Vous devez être prudent avec divers objets (en particulier params), parce que les Chaînes et les Tableaux aussi répondre à :[], mais la valeur retournée peut être pas ce que vous voulez, et le Tableau déclenche l'exception des Chaînes ou des Symboles utilisés comme indices.

C'est la raison pour laquelle, dans le modèle de formulaire de cette méthode (ci-dessous) le (généralement laid) de test pour .is_a?(Hash) est utilisé à la place de (généralement mieux) .respond_to?(:[]):

class Hash
  def get_deep(*fields)
    fields.inject(self) {|acc,e| acc[e] if acc.is_a?(Hash)}
  end
end

a_hash = {:one => {:two => {:three => "asd"}, :arr => [1,2,3]}}

puts a_hash.get_deep(:one, :two               ).inspect # => {:three=>"asd"}
puts a_hash.get_deep(:one, :two, :three       ).inspect # => "asd"
puts a_hash.get_deep(:one, :two, :three, :four).inspect # => nil
puts a_hash.get_deep(:one, :arr            ).inspect    # => [1,2,3]
puts a_hash.get_deep(:one, :arr, :too_deep ).inspect    # => nil

Le dernier exemple devrait soulever une exception: "Symbole d'index de tableau (TypeError)" s'il n'a pas été gardé par ce vilain "is_a?(Hash)".

17voto

Pablo Castellazzi Points 2453

L'utilisation correcte d' essayer avec un hachage est @sesion.try(:[], :comments) .

 @session.try(:[], :comments).try(:[], commend.id).try(:[], 'temp_value')
 

14voto

sawa Points 62592
 @myvar = session.fetch(:comments, {}).fetch(@comment.id, {})["temp_value"]
 

À partir de Ruby 2.0, vous pouvez faire:

 @myvar = session[:comments].to_h[@comment.id].to_h["temp_value"]
 

8voto

Nicolas Goy Points 379

Une autre approche:

 @myvar = session[:comments][@comment.id]["temp_value"] rescue nil
 

Cela peut aussi être considéré comme un peu dangereux car cela peut en cacher trop, personnellement, je l'aime bien.

Si vous voulez plus de contrôle, vous pouvez envisager quelque chose comme:

 def handle # just an example name, use what speaks to you
    raise $! unless $!.kind_of? NoMethodError # Do whatever checks or 
                                              # reporting you want
end
# then you may use
@myvar = session[:comments][@comment.id]["temp_value"] rescue handle
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X