First of all, this is no attempt to rival with James' nice Ruby Quiz ;-)
I came up with a nice new(?) use for method_missing today. Now it is your job to figure out what you can do with it. (My hope is that someone will find nice uses for this, that I didn't think of)
So here is the code:
class Array def method_missing(meth, *args, &block) rmeth = (meth.to_s =~ /\A_x_(.*)/ ? $1.to_sym : meth) if block if empty? [] else mm_block_rec(rmeth, 0, res=[], [], *args, &block) res end else res=[] each_with_index { |el, i| res << el.send(rmeth, *(args.collect { |el| (Array === el) ? el[i] : el })) } res end end
private
def mm_block_rec(rmeth, i, res, bargs, *args, &block) myargs=args.collect { |el| (Array === el) ? el[i] : el } res[i] = self[i].send(rmeth, *myargs) { |*ba| bargs[i]=(ba.size==1 ? ba.first : ba) if i==size-1 block.call(*bargs) else mm_block_rec(rmeth, i+1, res, bargs, *args, &block) end } end end
And some questions:
What does it do?
What can it be used for?
Has this been done before? (I couldn't find anything.)
Dominik Bathon wrote: > First of all, this is no attempt to rival with James' nice Ruby Quiz ;-)
> I came up with a nice new(?) use for method_missing today. > Now it is your job to figure out what you can do with it. > (My hope is that someone will find nice uses for this, that I didn't > think of)
Interesting.
> And some questions:
> What does it do?
> What can it be used for?
> Has this been done before? (I couldn't find anything.)
Reminds me of some code I wrote a few years ago when I was poking into method-oriented programming.
Rather than have receiver.message( args )
I wanted to reverse things and do message( args )->[ list_of_receivers ]
I hacked on Symbol and the result was that I could loop over a set of objects, or use a proc to conditionally send the message to objects in ObjectSpace (i.e., "I know what I want to do, I just don't know who to do it to"). The results were then collected and returned as an array.
The call looked something like
:message.>>( obj_set_or_criteria_proc ) { args }
I never found a really practical application for this. Conceivably, one could close all open file handles, or shut down lingering socket connections, or save user sessions if the session was x minutes old, or whatever.
It was mostly a "Gee, I wonder if ..." sort of thing, and the best scenario I could think of was if I had an app that might need a global shutdown, so one might want to dispatch a common set of messages across a range of unknown objects before ending.
I never released the code, being unhappy with the syntax. But I still like the idea of casting a message out into object space and reeling back the results.
BTW, I tried out your code, with a trivial example:
p %w{ This is some text }.size
Ah, but, of course, method_missing never gets called, so I did not get what I wanted.
This works, though:
p %w{ This is some text }.upcase
So there is the issue of trying to distribute a method across the list when that method is also implemented by Array
> Dominik Bathon wrote: > > First of all, this is no attempt to rival with James' nice Ruby Quiz ;-)
> > I came up with a nice new(?) use for method_missing today. > > Now it is your job to figure out what you can do with it. > > (My hope is that someone will find nice uses for this, that I didn't > > think of)
> Interesting.
> > And some questions:
> > What does it do?
> > What can it be used for?
> > Has this been done before? (I couldn't find anything.)
> Reminds me of some code I wrote a few years ago when I was poking into > method-oriented programming.
> Rather than have > receiver.message( args )
> I wanted to reverse things and do > message( args )->[ list_of_receivers ]
> I hacked on Symbol and the result was that I could loop over a set of > objects, or use a proc to conditionally send the message to objects in > ObjectSpace (i.e., "I know what I want to do, I just don't know who to > do it to"). The results were then collected and returned as an array.
> I never found a really practical application for this. Conceivably, one > could close all open file handles, or shut down lingering socket > connections, or save user sessions if the session was x minutes old, or > whatever.
> It was mostly a "Gee, I wonder if ..." sort of thing, and the best > scenario I could think of was if I had an app that might need a global > shutdown, so one might want to dispatch a common set of messages across > a range of unknown objects before ending.
> I never released the code, being unhappy with the syntax. But I still > like the idea of casting a message out into object space and reeling > back the results.
> BTW, I tried out your code, with a trivial example:
> p %w{ This is some text }.size
> Ah, but, of course, method_missing never gets called, so I did not get > what I wanted.
> This works, though:
> p %w{ This is some text }.upcase
> So there is the issue of trying to distribute a method across the list > when that method is also implemented by Array
Obviously no one really likes to decipher undocumented code... (I should have known after the "Code Cleaning"-Quiz ;-) Well, so let me tell you what it does:
As James Britt already figured out, it lets you call one method on all elements of an Array. If no block is given this works like collect. Instead of
[-1, -2, -3].collect { |x| x.abs } => [1, 2, 3]
you can just write
[-1, -2, -3].abs => [1, 2, 3]
Since #abs is not part of the Array interface, method_missing is triggered. But it does more than collect, it even works on nested Arrays:
If you try a method that is part of Array's interface, method_missing obviously won't be called:
%w[abc de fghi].size => 3
But there is a trick (maybe hack):
%w[abc de fghi]._x_size => [3, 2, 4]
The optional "_x_" is automatically stripped. But this also has a downside, it doesn't work with nested arrays, but on the other hand you can choose an explicit depth:
Or maybe use _i_ for the multidimensional iteration and _x_ for the rest...
I also thougt about adding it to Enumerable, but I think it doesn't make to much sense for other Enumerables (like Ranges) and if you really need it you can always use #to_a.
I realize there are lots of inconsistences in this concept, but I really like it generally. So, what do you think?
> [snip] > I realize there are lots of inconsistences in this concept, but I really > like it generally. So, what do you think?
I like that second version better, because its clearer. It makes clear in which order you are iterating. I'd even prefer something including 0 and 2 (upto, each, for) to make clear what the boundaries are.