Case statement pod lupou

Posted by Jan Kubr Tue, 30 Oct 2007 21:40:00 GMT

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

no comments | atom

Comments

Leave a response

Leave a comment