Is it possible to filter blocks, online, in an elegant way? for instance if I have the block class Integer def divisors (1..self).each{ |i| yield i if self % i == 0 } end end and I want to pass this block through an 'online' filter. I want to do something elegant like 10.divisors.odd{ |n| puts n } # instead of 10.divisors{ |n| puts n if n.odd? } #, which is pretty much the same as 10.divisors{ |n| yield n if n.odd? }{|n| puts n} I suppose it's not possible at all to treat a block as an object in this manner? If so, suppose I want to use a generic filter that takes a block and a condition as its arguments, and returns the block of each elements for which a condition is fulfilled? # pseudo def filter (block, condition) block do |s| yield s if s.condition end end How would I do anything like this, without using arrays as inbetweens? Am I again trying to treat blocks wrongly as objects, is it at all possible to 'operate' through them in this way? I'm new to ruby so this might be a bit stupid. I was just experimenting and couldn't find an elegent, modular manner of filtering blocks run-time in a 'chain-like' manner, without needlessly compressing them to arrays in between. I got this when googling, btw: www.rubyfilter.com :)

on 2008-12-08 17:14

on 2008-12-08 18:35

Hm, I think the problem is not to filter a block (that's also possible, because in ruby blocks are also objects of the class Proc). You want to filter an Enumeration. Therefore you could use the class Enumerator. require "enumerator" class Integer def odds() if block_given? then 1.upto(self) do |number| yield number if number % 2 == 1 end else Enumerable::Enumerator.new(self, :odds) end end def evens() if block_given? then 1.upto(self) do |number| yield number if number % 2 == 0 end else Enumerable::Enumerator.new(self, :even) end end end 5.odds.each do |number| puts number end # => 1, 3, 5 5.odds.any? do |number| number % 3 == 0 end # => true And of course you can add more "filters" by extending the Enumerator class, or better, a subclass of Enumerator which handles only with Integers. require "enumerator" class Integer def odds() if block_given? then 1.upto(self) do |number| yield number if number % 2 == 1 end else Enumerable::Enumerator::Integer.new(self, :odds) end end def evens() if block_given? then 1.upto(self) do |number| yield number if number % 2 == 0 end else Enumerable::Enumerator::Integer.new(self, :even) end end end module Enumerable class Enumerator class Integer < Enumerator def prime if block_given? then each do |number| # primitive prime algorithm yield(number) unless (2..Math.sqrt(number)).any? do |i| number % i == 0 end end else Enumerable::Enumerator.new(self, :prime) end end def odds if block_given? then each do |number| yield number if number % 2 == 1 end else Enumerable::Enumerator.new(self, :odds) end end def evens if block_given? then each do |number| yield number if number % 2 == 0 end else Enumerable::Enumerator.new(self, :evens) end end end end end 12.odds.prime.each {|x| p x}