tags:

views:

88

answers:

2

For a long time I tried desperately to get this to work, I've googled, I've tinkered, and I've asked some local Rubyists (though not pdx.rb, though I really should).

I think I explained this poorly to begin with. Let me try again. We were trying to do something like this at work


case user.roles.included? (... magic ...) 
when ['admin', 'editor'] 
then ...
when ['anonymous'] 
then ...
end

So you can see how it feels like a case, but because it's not using === as El noted it doesn't work. I know I can use ifs but it feels like a place where a case should be used.

Thanks everyone!

+3  A: 
case 
  when x == 16
    puts 'hi'
  when x.is_a?(Object)
    puts 'obj'
end

If I really understood the question, you just need to remove the x variable after the case keyword.

The lambda code didn't work because the lambda simply returns the argument.

names_l.call(names)
# => {:name => 'Terry'}

It's like running the following coe

case {:name => 'Terry'}
  when 'Terry'
    puts "Success!"
end

And {:name => 'Terry'} is not equal to 'Terry'.

Simone Carletti
Hah, well that's half of my question. I had no idea it would be so easy. I'll try to clarify the rest of my issue. Maybe I can find the old code that was causing me problems.
Chuck Vose
Can't find the code, I'm on the wrong machine. But I'll give the situation. We were creating a named scope in rails that needed to act differently based on the roles of the user logged in. So the case needed to take a function and the when needed to be an array. Essentially I was thinking like this (pseudo-code):case user.roles.included? (... magic ...)when ['admin', 'editor']when ['anonymous']endWe ended up using a function but this has still bugged me. How can I get the when part to evaluate in the case? Or is this just faulty logic and has to be done with a function?
Chuck Vose
okay, no code here in comments. Hopefully you get what I'm getting at.
Chuck Vose
Your explanation about lambda is correct, but your case code is throwing missing then errors for me.
EmFi
I tested the statement in irb against Ruby 1.8.6, 1.8.7 and 1.9.1 without getting any error message. :| Then keyword is not required with a line break.
Simone Carletti
Looks like irb was complaining about `x.is_a? Object`. x.is_a?(Object) works though.
EmFi
Fixed the example. :)
Simone Carletti
+3  A: 

When uses the === operator to compare the value given to case against the argument given to when. Also 'then' is unnecessary when appearing on a different line from the when statement The correct code for what you're trying to do is:

case x
when 16
  puts 'hi'
when Object
  puts 'obj'
end

As for the new addition to the question.

case user.roles.included? (... magic ...) 
when ['admin', 'editor'] 
  ... 
when ['anonymous'] 
  ... 
end

Doesn't work because Array's === doesn't map to include. I'm not sure where Array's === operator comes from or even what it does. But you could override it to provide the functionality you want.

Judging by the above code you want the case to trigger if one of the users roles matches the array. This will override Array#=== to do just that.

class Array
  def === other_array
    ! (other_array & self).empty?
  end
end

case user.roles
when ['admin', 'editor'] 
  ... 
when ['anonymous'] 
  ... 
end

Caveat: Depending on where you override Array#=== this can have unforeseen consequences. As it will change all arrays in that scope. Given that === is being inherited from Object where it is an alias for ==, I'm not expecting it to be a big problem.

Places where the new === differs from the old ===:

  • new === will return true if either array is a subset or reordering of the other.
  • old === will only return true if the two arrays are identical (order and contents)

So far as I know, case/when is the only time === could be implicitly called on an array.

EmFi
If you want something more complicated than this, you should use `if` statements.
Ken Bloom
revised original question to be more clear. I think I explained poorly.
Chuck Vose
That Caveat is what was worrisome to me. Maybe I just have to accept that this isn't really something ruby can do? I guess when I think about how this is done in Haskell it's just different because it's basically a glorified if rather than a switch in the way we think of it. But that is cool to know that by overriding === on Array the switch could work the way I wanted!
Chuck Vose
Overriding === is really harmful and you shouldn't do this for such this case.
Simone Carletti
I honestly wouldn't worry too much about it. I just couldn't post the code without the caveat in good conscious. I've updated my answer to explain why it should not be too much of a problem.
EmFi
I think this is probably the best solution I'll find to the problem. Maybe with my new knowledge I can post another question later or post to the pdx.rb mailing list and go over it some more. Thanks for all your help!
Chuck Vose