From: Rick DeNatale Date: 2011-01-13T21:25:42+09:00 Subject: Re: Case statements - Just beautification On Thu, Jan 13, 2011 at 5:35 AM, flebber wrote: > On Jan 13, 6:41 pm, Tim Roberts wrote: >> flebber wrote: >> >I just want to clarify case statements the name after the word case is >> >this just for beautification and to help with code readability? What >> >purpose does it serve. >> >> >So in my code its "winunit" and matz's code its "birthyear". >> >> ># Method 1 - Confident - assign range >> ># number -> number >> >def pricerange(x) >> >puts "Enter the quoted price: " >> >x = gets.chomp >> >winalloc = case winunit >> >  when x == (1.50...2.50) then ... >> >  when x == (2.50...3.80) then ... >> >  when x == (3.80...5.50) then ... >> >  else something >> >end >> >> Perhaps its purpose would be clearer if you wrote it like Matz's code: >> >> x = gets.chomp >> winalloc = case x >>   when (1.50...2.50) then ... >>   when (2.50...3.80) then ... >>   when (3.80...5.50) then ... >>   else something >> end >> -- >> Tim Roberts, t...@probo.com >> Providenza & Boekelheide, Inc. > > I tough my code looked like Matz's Really? It doesn't look much like it to me. The series of when statements following a case statement without an expression work pretty much like an if elsif...else sequence. WIth an expression in the case statement like case foo when bar baz when bop boo else shazbot end is equivalent to: if bar === foo baz elsif bop === foo boo else shazbot end Case is kind of like a macro, so I'll talk about case statements expanding, but what's really happening is that the Ruby parser and interpreter evaluate the code 'as if' it had been written as an if;elsif...;else sequence. Note that the logical expressions in the if and elsif clauses are === messages sent the the when value with the case value as the argument. That's why === (with 3 equal signs) is called the case comparison operator. Object defines === to be the same as == but certain classes redefine it. In particular Range overrides it to be the same as Range#include? > Matz's code > # Case expression tests ranges with === > generation = case birthyear >             when 1946..1963: "Baby Boomer" >             when 1964..1976: "Generation X" >             when 1978..2000: "Generation Y" >             else nil >             end This 'expands' to generation = if (1946..1963) === birthyear "Baby Boomer" elsif (1964..1976) === birthyear "Generation X" elsif 1(978..2000) === birthyear "Generation Y" else nil end So the value of the case is determined by the first range which includes birthyear. Your code (I'm changing the ...s so we can distinguish the different 'legs'): > My Code - (...) are placeholders > x = gets.chomp > winalloc = case winunit >          when x == 1.50...2.50: something1 >          when x == 2.50...3.80: something2 >          when x == 3.80...5.50: something3 >          else something_else 'expands' to: winalloc = if (x == 1.50...2.50) === winunit something1 elsif (x == 2.50...3.80) === winunit something2 elsif (x == 3.80...5.50) === winunit something3 else something_else end We can see by the code above the case that x is a string (the result of gets chomp), so all those x == expressions will evaluate to false since x is a string and not a Range. So if we substitute: winalloc = if false === winunit something1 elsif false === winunit sometthing2 elsif false === winunit something3 else something_else end which can be simplified to: winalloc = if false === winunit something1 else something_else end which should be obvious I hope. Note that false, being the sole instance of FalseClass uses Object#=== so false === winunit will only be true if the variable winunit references the unique false object. So since we don't know what winunit actually is from the snippet you've given, the result will either be something1 iff winunit == false, and something_else otherwise. If this is the first appearance of winunit it will be nil, so the case expression will always return something_else. Note that since x is a string (the result of gets chomp) it won't be a member of any of those ranges. I'm guessing that maybe winunit is meant to be the integer value of that string. If so maybe you want something like this: x = gets.chomp winunit = x.to_i winalloc = case winunit when 1.50...2.50: ... when 2.50...3.80: ... when 3.80...5.50: ... else something Which should look a lot more like the code in Matz and Flanigan. HTH -- Rick DeNatale Blog: http://talklikeaduck.denhaven2.com/ Github: http://github.com/rubyredrick Twitter: @RickDeNatale WWR: http://www.workingwithrails.com/person/9021-rick-denatale LinkedIn: http://www.linkedin.com/in/rickdenatale