From: Robert Dober Date: 2007-06-11T04:51:11+09:00 Subject: Re: fun with "case" On 6/10/07, Marc Heiler wrote: > If its fun, its nice :-) > In ruby i also enjoy when its short and terse (if i manage to understand > it) though :-) Ok it is all Robert's fault, his idea is really nice, I will explain Define a method on integers that will implement a === which will be called for the arg in case arg he just defines a proc on which he aliased :call to :=== (that is the genius part of this, and having the idea of course) irb(main):001:0> class Integer irb(main):002:1> def elements irb(main):003:2> cond = lambda {|enum| self == enum.size} irb(main):004:2> class < alias :=== :call irb(main):006:3> end irb(main):007:2> cond irb(main):008:2> end irb(main):009:1> end => nil irb(main):010:0> case [1,2,3] irb(main):011:1> when 3.elements Ruby will call 3.element === [1,2,3] as you know But 3.elements is a proc with === aliased to :call, thus Ruby calls this_proc.call([1,2,3]) in which [1,2,3].size will be compared to self whihc of course is 3. As I am very lazy I want to have a shortcut for "def elements..." I just put a method in class Module which will define such methods. ... define_method name do | *args | ** is like "def #{name} *args" cond = lambda{ |x| ** literal code inside def trans ? self.send(trans, *args) == x.send( arg_mth ) : ## forget trans self == x.send( arg_mth ) ## this part only is corresponding to Robert's code, arg_mth is :size in our case ## that becomes equivalent ( but way slower ) to ** self == x.size } class << cond alias_method :===, :call end cond ** all above is just stolen from the original idea end if you call that with :name=>"elements" and on => "size" it will just do exactly what Robert did, forget the arguments extension, that was just to fool around even more. This is a little bit like macros in Lisp - just better, because I can figure it out ;). Cheers Robert -- You see things; and you say Why? But I dream things that never were; and I say Why not? -- George Bernard Shaw