What is wrong with this Ruby CASE statement?
I have the following ruby function, and when I call it `deg_to_dir 270' the case statement never matches, when it should return W. I have been pulling my hair out and short of converting the entire thing to IF statements I don't have a next step.
def deg_to_dir deg
# used logic from http://www.csgnetwork.com/degrees2direct.html
d = deg.to_f
dir = "#{d}°"
case d
when d >= 0 && d <= 11.25,
d > 348.75 && d <= 360
dir = "N"
when d > 11.25 && d <= 33.75
dir = "NNE"
when d > 33.75 && d <= 56.25
dir = "NE"
when d > 56.25 && d <= 78.75
dir = "ENE"
when d > 78.75 && d <= 101.25
dir = "E"
when d > 101.25 && d <= 123.75
dir = "ESE"
when d > 123.75 && d <= 146.25
dir = "SE"
when d > 146.25 && d <= 168.75
dir = "SSE"
when d > 168.75 && d <= 191.25
dir = "S"
when d > 191.25 && d <= 213.75
dir = "SSW"
when d > 213.75 && d <= 236.25
dir = "SW"
when d > 236.25 && d <= 258.75
dir = "WSW"
when d > 258.75 && d <= 281.25
dir = "W"
when d > 281.25 && d <= 303.75
dir = "WNW"
when d > 303.75 &开发者_JAVA百科& d <= 326.25
dir = "NW"
when d > 326.25 && d <= 348.75
dir = "NNW"
end
dir
end
What you're trying to do is an if elsif
pattern. If you're trying to use a case when
pattern should be using ranges:
case d
when (0..11.25)
dir = "N"
when (11.25..33.75)
dir = "NE"
# etc...
end
Every time the parser comes to a when statment it executes case_statement === when_statement
. All of your when
statements evaluate to a boolean, which will never equal a degree.
I'd say the worst part about that case
statement is that it shouldn't be a case
statement at all.
DIRS = %w[N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW]
def deg_to_dir deg
deg = deg.to_f
dir = DIRS[(deg + 11.25).div(22.5)]
"#{deg}° #{dir}"
end
If you do not want to compare a value but instead "simulate" an if-else with case (as in your case) you simply have to write
case
instead of
case d
The problem is that you wrote case d
and a boolean condition in the when
(so it performs a true|false === d
, which never succeeds). It should look like this (notice how to take advantage of case
being an expression in Ruby):
dir = case
when d >= 0 && d <= 11.25,
d > 348.75 && d <= 360
"N"
...
end
Anyway, why don't you refactor this method without conditionals? IMO this is a pretty poor implementation; an array with the abbrevation names (and code that uses it judiciously) is all you should need. Probably a one/two-liner.
Combinating Kyle's and tokland's answers, you will end up in following:
def deg_to_dir deg
case deg.to_f
when (0..11.25)
"N"
when (11.25..33.75)
"NE"
# ... your rest ...
end
end
And no helper variables!
Kyle's answer with the ranges is the right one. The reason is that the case statement compares d with the when statement using ===.
In this case you're doing a compare of
270 === true
which isn't. A float isn't going to equal a boolen, for any values of float and bool.
精彩评论