Blog do TaQ

Hashes Ruby com valores default

Publicado em Developer

Vivendo e aprendendo. Hoje estava lendo um post no site do Eigenclass e não havia me tocado de todas as possibilidades do Hash.new. Olha que barato.

O primeiro comportamento do Hash.new, o mais conhecido, é retornar um valor nil sempre que é requisitada uma chave que não existe na Hash:

[taq@~]irb
irb(main):001:0> h = Hash.new
=> {}
irb(main):002:0> h["a"] = 100
=> 100
irb(main):003:0> h["b"] = 200
=> 200
irb(main):004:0> h["a"]
=> 100
irb(main):005:0> h["b"]
=> 200
irb(main):006:0> h["c"]
=> nil
irb(main):007:0> h
=> {"a"=>100, "b"=>200}

Até aí tudo bem. Mas o Hash.new permite também que alteremos esse valor default:

[taq@~]irb
irb(main):001:0> h = Hash.new("Inexistente")
=> {}
irb(main):002:0> h["a"] = 100
=> 100
irb(main):003:0> h["b"] = 200
=> 200
irb(main):004:0> h["a"]    
=> 100
irb(main):005:0> h["b"]
=> 200
irb(main):006:0> h["c"]
=> "Inexistente"
irb(main):007:0> h
=> {"a"=>100, "b"=>200}

Agora a parte legal é que podemos retornar o valor default utilizando blocos (ah, os blocos!):

[taq@~]irb
irb(main):001:0> h = Hash.new {|h,k| "#{k} foi pescar."}
=> {}
irb(main):002:0> h["a"] = 100
=> 100
irb(main):003:0> h["b"] = 200
=> 200
irb(main):004:0> h["a"]      
=> 100
irb(main):005:0> h["b"]
=> 200
irb(main):006:0> h["c"]
=> "c foi pescar."
irb(main):007:0> h
=> {"a"=>100, "b"=>200}

E uma parte mais legal ainda é que ali no bloco passamos a referência da Hash também, então podemos, se quisermos, incluir um elemento novo nela com a chave especificada e o valor default:

[taq@~]irb
irb(main):001:0> h = Hash.new {|h,k| h[k] = "#{k} foi pescar."}
=> {}
irb(main):002:0> h["a"] = 100
=> 100
irb(main):003:0> h["b"] = 200
=> 200
irb(main):004:0> h["a"]      
=> 100
irb(main):005:0> h["b"]
=> 200
irb(main):006:0> h["c"]
=> "c foi pescar."
irb(main):007:0> h
=> {"a"=>100, "b"=>200, "c"=>"c foi pescar."}

Resumindo um pouco o exemplo do post que mencionei, e fazendo algo mais sensato do que esses valores default doidos, o que o sujeito fez foi criar uma Hash onde quando um IP é requisitado na chave, ele é adicionado na chave e armazenao nome do país no valor, utilizando o GeoIP:

[taq@~]irb
irb(main):001:0> h = Hash.new {|h,k| h[k] = `geoiplookup #{k}`.chomp.gsub(
/^GeoIP Country Edition: /,"") }
=> {}
irb(main):002:0> h["200.211.78.150"]
=> "BR, Brazil"
irb(main):003:0> h["216.236.37.99"]
=> "US, United States"
irb(main):004:0> h["217.12.3.11"]
=> "GB, United Kingdom"
irb(main):005:0> h
=> {"217.12.3.11"=>"GB, United Kingdom", "200.211.78.150"=>"BR, Brazil", 
"216.236.37.99"=>"US, United States"}

Ah, dá para retornar o valor default usando ... Hash.default também. :-) Seguindo o exemplo acima:

irb(main):006:0> h.default
Usage: geoiplookup [-v] <ipaddress|hostname>
=> ""
irb(main):007:0> h.default("212.80.177.133")
=> "ES, Spain"
irb(main):008:0> h
=> {"217.12.3.11"=>"GB, United Kingdom", "200.211.78.150"=>"BR, Brazil", nil=>"", 
"216.236.37.99"=>"US, United States", "212.80.177.133"=>"ES, Spain"}

Legal, hein. :-)


Tags:


Comentários

Sem nenhum comentário.

comments powered by Disqus

Twitter