Case statement pod lupou
Jak pozorní budete, když v knížce o Ruby narazíte na příkaz case? Jestli jako já, tak moc ne. Rozhodnutí, jakou větví se provádění programu vydá se řídí operátorem ===, tak co je nutné vědět více, že? Následující určitě někomu přijde jako stará známá věc, ale věřím, že ne všem. Až do nedávna jsem si myslel, že následující case:
case wifes
when 0
puts 'single'
when 1
puts 'married'
else
puts 'mormon'
end
se přeloží do následující operace:
if wifes === 0 puts 'single' elsif wifes === 1 puts 'married' else puts 'mormon' end
Chtěl jsem ale, aby můj test vlezl do všech těchto větví (to je takový dobrý testovací návyk;) a jal jsem se nahradit metodu === na objektu wifes něčím (mockem), co mi vrátí postupně všechny hodnoty. A ono to nefungovalo. Zkoumáním nalezené skutečnosti v irb jsem dospěl k různým zajimavostem, které jsem si předtím dostatečnš neuvědomil:
irb(main):001:0> String === "" => true irb(main):002:0> "" === String => false irb(main):003:0> /h/ === "hey" => true irb(main):004:0> "hey" === /h/ => false
Aneb potřeboval jsem si znova uvědomit, že === není žádný komutativní operátor, ale metoda a ta může (a je) v různých třídách implementována různě. A jak to navazuje na case statement? No ten příkaz se ve skutečnosti vykoná takhle:
if 0 === wifes puts 'single' elsif 1 === wifes puts 'married' else puts 'mormon' end
Metoda === se tedy nevolá na objektu stojícím za klíčovým slovem case, ale na objektech za "whens" v jednotlivých větvích. Zajimavé to pak začíná být především v případech, kdy nejsou všechny objekty instance stejné třídy. Doufám, že to dává smysl. Objasňuje to i tyhle hojně využívané casy:
case extension.downcase
when /jpg$/
puts "picture"
when /mp3$/
puts "song"
end
res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }
case res
when Net::HTTPSuccess, Net::HTTPRedirection
# OK
else
res.error!
end