Potresti essere pigro e avvolgerlo in un lambda
:
my_hash = YAML.load_file('yml')
my_lamb = lambda { |key| my_hash[key.to_s] }
my_lamb[:a] == my_hash['a'] #=> true
Ma questo funzionerebbe solo per la lettura dell'hash, non per la scrittura.
Per farlo, potresti usare Hash#merge
my_hash = Hash.new { |h,k| h[k] = h[k.to_s] }.merge(YAML.load_file('yml'))
Il blocco init convertirà le chiavi una volta su richiesta, sebbene se si aggiorna il valore per la versione stringa della chiave dopo aver effettuato l'accesso alla versione simbolo, la versione simbolo non verrà aggiornata.
irb> x = { 'a' => 1, 'b' => 2 }
#=> {"a"=>1, "b"=>2}
irb> y = Hash.new { |h,k| h[k] = h[k.to_s] }.merge(x)
#=> {"a"=>1, "b"=>2}
irb> y[:a] # the key :a doesn't exist for y, so the init block is called
#=> 1
irb> y
#=> {"a"=>1, :a=>1, "b"=>2}
irb> y[:a] # the key :a now exists for y, so the init block is isn't called
#=> 1
irb> y['a'] = 3
#=> 3
irb> y
#=> {"a"=>3, :a=>1, "b"=>2}
Potresti anche avere il blocco init che non aggiorna l'hash, il che ti proteggerebbe da quel tipo di errore, ma saresti comunque vulnerabile al contrario - l'aggiornamento della versione del simbolo non aggiornerebbe la versione della stringa:
irb> q = { 'c' => 4, 'd' => 5 }
#=> {"c"=>4, "d"=>5}
irb> r = Hash.new { |h,k| h[k.to_s] }.merge(q)
#=> {"c"=>4, "d"=>5}
irb> r[:c] # init block is called
#=> 4
irb> r
#=> {"c"=>4, "d"=>5}
irb> r[:c] # init block is called again, since this key still isn't in r
#=> 4
irb> r[:c] = 7
#=> 7
irb> r
#=> {:c=>7, "c"=>4, "d"=>5}
Quindi la cosa da fare attenzione con questi è il passaggio tra le due forme chiave. Stick con uno.