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

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}