Main Page | Report this Page
Computers Forum Index  »  Computer Languages (Ruby)  »  [QUIZ] Enumerable ObjectSpace (#222)...
Page 1 of 1    

[QUIZ] Enumerable ObjectSpace (#222)...

Author Message
Daniel Moore...
Posted: Sat Oct 24, 2009 9:44 pm
Guest
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this
quiz until 48 hours have elapsed from the time this message was
sent.

2. Support Ruby Quiz by submitting ideas and responses
as often as you can.

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby Talk follow the discussion. Please reply to
the original quiz message, if you can.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RSS Feed: http://rubyquiz.strd6.com/quizzes.rss

Suggestions?: http://rubyquiz.strd6.com/suggestions

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

## 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

--
-Daniel
http://rubyquiz.strd6.com
 
James Coglan...
Posted: Tue Oct 27, 2009 3:23 am
Guest
[Note: parts of this message were removed to make it a legal post.]

Quote:
## 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.



There is probably something better to be had using reflection and method
generation, but here's one stab:

class << ObjectSpace
def method_missing(sym, *args, &block)
mod = args.first.is_a?(Module) ? args.shift : nil
enum = enum_for(*[:each_object, mod].compact)
enum.__send__(sym, *args, &block)
end
end

# e.g. puts ObjectSpace.map(Class) { |c| c.name }

--
James Coglan
http://jcoglan.com
 
Intransition...
Posted: Mon Nov 02, 2009 1:24 am
Guest
On Oct 28, 4:13 am, Benoit Daloze <erego... at (no spam) gmail.com> wrote:

Quote:
Something I don't understand is why it seem impossible to modify each if
Enumerable is included

Not sure what you mean. Could you explain further?
 
Intransition...
Posted: Mon Nov 02, 2009 1:51 am
Guest
I was impressed with these solutions. The use of an instance variable
to store the argument I found particularly clever.

I had worked on something like this a long time ago. At the time I
completely reimplemented Enumerable by hand to accept #each arguments
(it was the first time I ever used TDD, btw). I later realized
afterward a bit of meta-programming could make all of it a whole lot
easier, so I created what is now enumargs.rb (gem install enumargs).
It is similar to Benoit's solution.

require 'enumerator'

# This is a simple reimplementation of the core Enumerable module
# to allow the methods to take and pass-on arbitrary arguments to
the
# underlying #each call. This library uses Enumerator and scans
# Enumerable so it can alwasy stay in sync.
#
# NOTE Any Enumerable method with a negative arity cannot pass
arguments
# due to ambiguity in the argument count. So the methods #inject and
#zip
# do NOT work this way, but simply work as they do in Enumerable.
# However the method #find, and it's alias #detect, have been made
to work
# by removing its rarely used optional parameter and providing
instead an optional
# keyword parameter (:ifnone => ...). Please keep these difference
in mind.
#
# require 'enumargs'
#
# class T
# include Enumerable::Arguments
# def initialize(arr)
# at (no spam) arr = arr
# end
# def each(n)
# arr.each{ |e| yield(e+n) }
# end
# end
#
# t = T.new([1,2,3])
# t.collect(4)
# #=> [5,6,7]
#
module Enumerable
module Arguments

def self.wrap_enumerable_method( methodname )

m = methodname
meth = Enumerable.instance_method(m)
arity = meth.arity

case arity <=> 0
when 0
class_eval %{
def #{m}( *args, &yld )
enum_for(:each, *args).#{m}( &yld )
end
}
when 1
class_eval %{
def #{m}( *args, &yld )
args, each_args = args[0...#{arity}], args[#{arity}..-1]
enum_for(:each, *each_args).#{m}( *args, &yld )
end
}
else
class_eval %{
def #{m}( *args, &yld )
enum_for(:each).#{m}( *args, &yld )
end
}
end
end

Enumerable.instance_methods(false).each do |m|
wrap_enumerable_method( m )
end

# Make exception for #find (a negative arity method) to accept
# keyword argument.
#
# ObjectSpace.find(Class, :ifnone=>lambda{1}) { |e| ... }
# ObjectSpace.find(Class, :ifnone=>lambda{1}) { |e| ... }
#
def find(*args, &yld) # future use **keys ?
if Hash === args.last and args.last.key?(:ifnone)
ifnone = args.last.delete(:ifnone)
args.pop if args.last.empty?
enum_for(:each, *args).find( ifnone, &yld )
else
enum_for(:each, *args).find( &yld )
end
end
alias_method :detect, :find

end
end

With that, the solution to #222 is simply:

class << ObjectSpace
include Enumerable::Arguments
alias each each_object
end

Eg.

ObjectSpace.select(Class){ |c| c < Exception }

Thanks.
 
 
Page 1 of 1    
All times are GMT
The time now is Thu Dec 10, 2009 4:07 pm