CyberFerret
CyberFerret

Reputation: 275

Is there a more elegant way to perform a multiple include? selection in ruby?

I came across this issue in a project last night, while writing a helper to pick an icon depending on a file extension, and was wondering if there was a better (more "ruby") way of handling it?

The code currently goes something like:

def choose_icon(myfile)
  icon = "default-icon"
  if ["*.doc","*.docx",".txt","*.dot"].include? File.extname(myfile)
    icon = "doc-icon"
  end
  if ["*.xls","*.xlsx","*.xlt"].include? File.extname(myfile)
    icon = "sheet-icon"
  end
  if ["*.mp3","*.aac","*.aiff","*.wav"].include? File.extname(myfile)
    icon = "audio-icon"
  end
  if ["*.mov","*.m4a","*.wmv"].include? File.extname(myfile)
    icon = "movie-icon"
  end
  icon # return the chosen icon
end

This somehow feels a little clumsy and inelegant to me, and I was struggling to find a better way to do it in Ruby.

(Note: The above example is REALLY simplified and the actual code is far longer and looks far more untidy.)

It would be really cool if the 'case' construct would work like this:

def choose_icon(myfile)
  case File.extname(myfile)
  when ["*.doc","*.docx",".txt","*.dot"].include? 
    "doc-icon"
  when ["*.xls","*.xlsx","*.xlt"].include? 
    "sheet-icon"
  when ["*.mp3","*.aac","*.aiff","*.wav"].include? 
    "audio-icon"
  when ["*.mov","*.m4a","*.wmv"].include? 
    "movie-icon"
  else
    "default-icon"
  end
end

But of course, that doesn't work. It is so much easier to read though, so I was wondering if I had missed some other method of doing a multiple comparison against a collection of options that would restore some elegance and readability to my code?

Upvotes: 0

Views: 81

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110685

You could use a hash:

h = [*(%w| .doc .docx .txt .dot |).product(["doc-icon"]),
     *(%w| .xls .xlsx .xlt      |).product(["sheet-icon"]),
     *(%w| .aac .aiff .wav      |).product(["audio-icon"]),
     *(%w| .mov .m4a  .wmv      |).product(["movie-icon"])].to_h
  #=> {".doc"=>"default-icon", ".docx"=>"default-icon",
  #    ".txt"=>"default-icon", ".dot"=>"default-icon",
  #    ".xls"=>"sheet-icon"  , ".xlsx"=>"sheet-icon",
  #    ".xlt"=>"sheet-icon"  , ".aac"=>"audio-icon",
  #    ".aiff"=>"audio-icon" , ".wav"=>"audio-icon",
  #    ".mov"=>"movie-icon"  , ".m4a"=>"movie-icon",
  #    ".wmv"=>"movie-icon"}
h.default = "default-icon"

h[File.extname("myfile.wav")]
  #=> "audio-icon"
h[File.extname("./mydir/myfile.abc")]
  #=> "default-icon" 

Upvotes: 2

Patrick Oscity
Patrick Oscity

Reputation: 54684

You almost got it right. Just leave off the square brackets and the include? and it will work. I think the asterisks should not be necessary either since File.extname returns the extension with just a dot.

def choose_icon(myfile)
  case File.extname(myfile)
  when '.doc', '.docx', '.txt', '.dot'
    'doc-icon'
  when '.xls', '.xlsx', '.xlt' 
    'sheet-icon'
  when '.mp3', '.aac', '.aiff', '.wav'
    'audio-icon'
  when '.mov', '.m4a', '.wmv'
    'movie-icon'
  else
    'default-icon'
  end
end

Upvotes: 3

Related Questions