Digging & Safe navigation

21 juin 2025
Objectif : éviter du code de contrôle pour récupérer des données sur recherche, map/reduce, nesting

Digging

 Recherche dans un nested Hash qui potentiellement peut ne pas être défini.

Version non robuste

$mydata = {:config => { :environments => { :developement => {:key => "value"}, :production => {:key => "value"}}}}  
p $mydata  
  
  
  def get_config(data: $mydata,environment: :developement)  
    return data[:config][:environments][environment][:key]  
  rescue Exception => e  
    puts e.message  
  end  
  
p get_config   
p get_config environment: :staging  
Remarque : On constate qu'un méthode est comparable à un bloc en certain aspect et donc pas besoin de faire un begin / end pour rescue l'exception

Voir : Bonnes pratiques 

Sortie :

{:config=>{:environments=>{:developement=>{:key=>"value"}, :production=>{:key=>"value"}}}}  
"value"  
undefined method `[]' for nil:NilClass  
nil  

Quand l’environnement est défini tout va bien, mais sinon on lève une exception car on utilise une méthode d'un Array sur un Objet NilClass

Version "Ugly"

def ugly_get_config(data: $mydata,environment: :developement)  
  if data[:config][:environments].include? environment  
    return data[:config][:environments][environment][:key]  
  end  
end  
  
p ugly_get_config   
p ugly_get_config environment: :staging  

Sortie :

"value"  
nil  
Limite: si en plus le champs key n'est pas présent dans la définition d'un environement une lève encore une exception

 Version "Safe"

On utilise #dig, qui propose un parcours deep nesting du hashage et renvoi nil si il ne trouve pas de path

def get_safe_config(data: $mydata, environment: :developement)  
  return data[:config][:environments].dig(environment, :key)  
end  
  
p get_safe_config  
p get_safe_config environment: :staging  

Safe Navigation

 Version non robuste

Soit une recherche sur Array

$list_names = ["romain","pierre","camille"]  
  
def get_pattern(data: $list_names, pattern: /.*/)  
  return data.select {|item| item =~ pattern}.first.capitalize  
end  
  
p get_pattern  
  
begin   
p get_pattern pattern: /hass/  
  
rescue Exception => e  
  puts e.message   
  
end  

Sortie : 

"Romain"  
undefined method `capitalize' for nil:NilClass  

first peut renvoyer un tableau vide, donc first peu renvoyer un object nil.

=> la méthode capitalize n'existe pas sur NilClass.

Version "Ugly"

def ugly_get_pattern(data: $list_names, pattern: /.*/)  res = data.select {|item| item =~ pattern}  
  return res.first.capitalize unless res.empty?   
end  
  
p ugly_get_pattern pattern: /hass/  
p ugly_get_pattern  

Sortie :

nil  
Romain  

Version "Safe"

def pretty_get_pattern(data: $list_names, pattern: /.*/)  return  data.select {|item| item =~ pattern}.first&.capitalize  
end  
  
p pretty_get_pattern pattern: /hass/  
p pretty_get_pattern  
Remarque : on utilise &. qui permet la safe navigation

Sortie :

nil  
Romain  

Romain GEORGES

Open Source evangelist & Ruby enthousiast