On Saturday 24 October 2009, Daniel Moore wrote: > | > |## Enumerable ObjectSpace (#222) > | > |Kaixo Rubyists, > | > |This week's quiz was suggested by Trans[1]. > | > |ObjectSpace has the method #each_object. I've always wanted to alias > |that to #each and make ObjectSpace Enumerable. But there's a catch, > |#each_object takes an argument and Enumerable does not pass arguments > |on to the #each method. So how does one resolve this issue? What's the > |easiest way to make ObjectSpace Enumerable? > | > |One could always take the brute force approach and completely > |re-implement Enumerable module to pass along the arguments. But I'm > |hoping there are much more elegant solutions to be had. > | > |Have fun! > | > | > |[1]: http://rubyworks.github.com Here's my solution. It uses an instance variable to keep trace of the argument given to the enumerable method. In more detail, here's how it worsk: after extending Enumerable, in redefines each method added by it allowing any number of arguments (indeed, all that is needed is to add one argument. I believe it can be done that way but I don't think it's worth the effort). The first argument is then removed from the array and inserted at the end of the array contained in the @__chosen_class instance variable (which is created if it doesn't already exist). Then, super is called, passing it the new argument list (that is, the one with the first argument removed) and the block. The each method is then defined to either accept one argument, so that you can do ObjectSpace.each(Array){...} or to use the last element of @__chosen_class. The reason to store the class in an array is to allow nested calls, that is something like this: ObjectSpace.select(cls1) do |o| ... ObjectSpace.any?(cls2){...} ... end When ObjectSpace.any? is called, it'll push cls2 at the end of @__chosen_class, so that its each will use that class, while each for the outer block will use cls1. I enclosed the call to super in a begin/ensure clause to be sure that the class pushed in the array is removed at the end of the method call. module ObjectSpace methods = Enumerable.instance_methods - self.public_methods extend Enumerable methods.each do |m| instance_eval <<-STR def #{m} *args, &blk @__chosen_class ||= [] @__chosen_class << args.shift begin super *args, &blk ensure @__chosen_class.pop end end STR end def self.each cls = nil each_object(cls || @__chosen_class[-1]){|o| yield o} end end Stefano