Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
case with predicates
require 'rubygems'
require 'backports' # aliases Proc#=== to Proc#call
rs = (0..10000).to_a.sample(30)
rs.each do |r|
case r
when lambda { |n| n.zero? } then puts "#{r} is zero"
when lambda { |n| (n % 5).zero? } then puts "#{r} is fiven"
when lambda { |n| (n % 4).zero? } then puts "#{r} is fourven"
when lambda { |n| (n % 3).zero? } then puts "#{r} is threeven"
when lambda { |n| n.even? } then puts "#{r} is even"
when lambda { |n| n.odd? } then puts "#{r} is odd"
else
raise 'unpossible'
end
end
@dkubb

This comment has been minimized.

Copy link
Owner Author

@dkubb dkubb commented Aug 7, 2011

This is a ruby 1.8 port of @flazz's code from http://flazz.me/predicates-in-ruby-case-statements (see his fork for original 1.9 specific code)

@avdi

This comment has been minimized.

Copy link

@avdi avdi commented Aug 7, 2011

I did not realize this about 1.9. That is a huge deal despite being such a small change. A lot of code that might otherwise have been considered "hacky" becomes idiomatic.

@radar

This comment has been minimized.

Copy link

@radar radar commented Aug 7, 2011

That is hot. Nice find, Dan.

@dkubb

This comment has been minimized.

Copy link
Owner Author

@dkubb dkubb commented Aug 7, 2011

@avdi me either. I was surprised when I came across this code. Even though the 1.9 only syntax is going to take some getting used to, it looks pretty natural and will certainly clean up some cases, like you say.

@jacortinas

This comment has been minimized.

Copy link

@jacortinas jacortinas commented Aug 7, 2011

That's beautiful, and ridiculously powerful.

@ecin

This comment has been minimized.

Copy link

@ecin ecin commented Aug 7, 2011

<3

@ernie

This comment has been minimized.

Copy link

@ernie ernie commented Aug 7, 2011

Very nice. Had been meaning to test if 1.9 did this with ===. If your subject responds to all predicates, you can also have fun with 1.9's Symbol#to_proc: https://gist.github.com/1130320

@emmanuel

This comment has been minimized.

Copy link

@emmanuel emmanuel commented Aug 8, 2011

Proc#call as #=== is a wonderful addition, but this is a terrible example. I hope I never see someone actually do this.

Why such a harsh reaction? Because you should use case statements' native capabilities if the predicates are defined in the same scope: https://gist.github.com/1132758.

@dkubb

This comment has been minimized.

Copy link
Owner Author

@dkubb dkubb commented Aug 8, 2011

@emmanuel your gist is how I would probably write this in real production code.

I remember times where I've wished to be able to include more complex logic in a case statement, and have it evaluated at runtime, but I'm coming up blank trying to think of a good example. Anyone else have one?

@emmanuel

This comment has been minimized.

Copy link

@emmanuel emmanuel commented Aug 8, 2011

@dkubb

I agree that this opens terrific options for new types of idiomatic Ruby. I would love to see more examples of how people are using this for great justice, but I suspect such examples will be ill-suited to explication in gist form, by virtue of the substance of my complaint.

To be clear, my point is that this specific example should not be emulated. If the predicates are statically defined in the same scope as a case statement, do the simple thing: use the case statement as Matz intended :P

...pardon me while I continue turning into a cantankerous old grump...

@ernie

This comment has been minimized.

Copy link

@ernie ernie commented Aug 8, 2011

I'd still very much like to have &:method work in when arg lists. I spent some time trying to hack parse.y over the weekend, actually, to see if I could make it work in some frankenstein-like manner, but my version of bison seemed not to be playing nicely. :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment