# Block composition?

**URL:** <https://www.ruby-forum.com/t/block-composition/117719>\
**Category:** Ruby\
**Created:** [October 19, 2007, 6:21pm UTC](https://www.ruby-forum.com/t/block-composition/117719 "2007-10-19T18:21:28Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![aaaaaa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/c6cbf5/32.png) [@aaaaaa](https://www.ruby-forum.com/u/aaaaaa)\
**Post date:** [October 19, 2007, 6:21pm UTC](https://www.ruby-forum.com/t/block-composition/117719/1 "2007-10-19T18:21:28Z")

</div>

Hi,

I’m implementing a plain simple search functionality over an array of  
objects. One of the attributes that those objects expose is a creation  
date (a Time object). The search functionality should work in 3 ways:

- starting from a date
- up to a date
- within a certain range

In the first implementation I had the same code repeated in different  
search methods:

def search\_from(start)  
@list.select {|s| s.creation \>= start}  
end  
def search\_to(\_end)  
@list.select {|s| s.creation \<= \_end}  
end  
def search(start, \_end)  
@list.select {|s| s.creation \>= start && s.creation \<= \_end}  
end

So I wanted to remove the duplication and I thought about defining  
search\_from and search\_to in terms of search. I tried using some sort  
of block composition by means of lambda functions, but I didn’t really  
like it:

def search\_from(start)  
search(start, nil)  
end  
def search\_to(\_end)  
search(nil, \_end)  
end  
def search(start, \_end)  
upper\_limit = if start.nil?  
lambda {|s| true}  
else  
lambda {|s| s.creation \>= start}  
end  
lower\_limit = if \_end.nil?  
lambda {|s| true}  
else  
lambda {|s| s.creation \<= \_end}  
end  
@list.select {|s| upper\_limit.call(s) && lower\_limit.call(s)}  
end

In the end I’ve decided to override \<=\> on Time so that if you compare  
with nil it returns 0 but:

- it’s really ugly
- as a side effect Time.mktime(2007) == nil evaluates to true (while  
of course Time.mktime(2007).nil? is false)
- your code may break in unexpected ways

Does anybody know a better approach towards block composition?  
Thanks! AA

PS: here is the current code with the ugly, horrible, too bad Time.\<=\>  
override.

class Time  
alias\_method :comp, “\<=\>”.intern  
def \<=\>(other)  
if other.nil?  
0  
else  
comp(other)  
end  
end  
end

class Stuff  
attr\_accessor :name  
attr\_accessor :creation  
def initialize(name, creation)  
@name = name  
@creation = creation  
end  
end

class Repository  
def initialize(list)  
@list = list  
end  
def search\_from(start)  
search(start, nil)  
end  
def search\_to(\_end)  
search(nil, \_end)  
end  
def search(start, \_end)  
@list.select {|s| s.creation \>= start && s.creation \<= \_end}  
end  
end

require ‘test/unit’

class TestRepository \< Test::Unit::TestCase  
def setup  
@jan = Stuff.new(“jan”, Time.mktime(2007, 1))  
@feb = Stuff.new(“feb”, Time.mktime(2007, 2))  
@rep = Repository.new([@jan, @feb])  
end  
def test\_search\_returns\_values\_starting\_from\_creation\_date  
assert\_equal([], @rep.search\_from(Time.mktime(2008)))  
assert\_equal([@feb], @rep.search\_from(Time.mktime(2007, 1, 15)))  
assert\_equal([@jan, @feb], @rep.search\_from(Time.mktime(2006,  
12)))  
end  
def test\_search\_returns\_values\_up\_to\_creation\_date  
assert\_equal([], @rep.search\_to(Time.mktime(2006)))  
assert\_equal([@jan], @rep.search\_to(Time.mktime(2007, 1, 15)))  
assert\_equal([@jan, @feb], @rep.search\_to(Time.mktime(2008)))  
end  
def test\_search\_returns\_values\_within\_a\_range\_of\_creation\_dates  
assert\_equal([], @rep.search(Time.mktime(2005),  
Time.mktime(2006)))  
assert\_equal([@jan], @rep.search(Time.mktime(2006),  
Time.mktime(2007, 1, 15)))  
assert\_equal([@jan, @feb], @rep.search(Time.mktime(2006),  
Time.mktime(2008)))  
end  
end

---

<div class="post-metadata">

**Author:** ![aaaaaa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/c6cbf5/32.png) [@aaaaaa](https://www.ruby-forum.com/u/aaaaaa)\
**Post date:** [October 19, 2007, 7:58pm UTC](https://www.ruby-forum.com/t/block-composition/117719/2 "2007-10-19T19:58:39Z")

</div>

On Oct 19, 2007, at 10:20 AM, aa wrote:

> def search\_from(start)  
> @list.select {|s| s.creation \>= start}  
> end  
> def search\_to(\_end)  
> @list.select {|s| s.creation \<= \_end}  
> end  
> def search(start, \_end)  
> @list.select {|s| s.creation \>= start && s.creation \<= \_end}  
> end

why not something simple like

def search &filter  
@list.select &filter  
end

def search\_from time  
search{|s| s.creation and s.creation \>= time}  
end

def search\_in time\_range  
search{|s| s.creation and time\_range === s.creation}  
end

def search\_until time  
search{|s| s.creation and s.creation \<= time}  
end

??

a @ [http://codeforpeople.com/](http://codeforpeople.com/)

---

<div class="post-metadata">

**Author:** ![aaaaaa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/c6cbf5/32.png) [@aaaaaa](https://www.ruby-forum.com/u/aaaaaa)\
**Post date:** [October 19, 2007, 9:15pm UTC](https://www.ruby-forum.com/t/block-composition/117719/3 "2007-10-19T21:15:58Z")

</div>

On Oct 19, 1:57 pm, “ara.t.howard” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> why not something simple like  
> [good stuff snipped]

Well, because:

- I haven’t thought about using a Time range
- it didn’t occur to me that passing the filter to the iterator was  
the best idea to decouple iteration with selection criteria  
Quite neat!

Nevertheless, I’m still interested to know if anybody has ever  
composed different blocks together within the same iteration (and  
how).

Thanks a lot.  
AA

---

<div class="post-metadata">

**Author:** ![aaaaaa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/c6cbf5/32.png) [@aaaaaa](https://www.ruby-forum.com/u/aaaaaa)\
**Post date:** [October 20, 2007, 1:00am UTC](https://www.ruby-forum.com/t/block-composition/117719/4 "2007-10-20T01:00:05Z")

</div>

On 10/19/07, aa [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Nevertheless, I’m still interested to know if anybody has ever  
> composed different blocks together within the same iteration (and  
> how).
> 
> Thanks a lot.  
> AA
> 
> Do you mean something like this?

def search\_from(start)  
search\_all proc {|s| s.creation \>= start }  
end  
def search\_to(\_end)  
search\_all proc {|s| s.creation \<= \_end }  
end  
def search(start, \_end)  
search\_all proc {|s| s.creation \>= start }, proc { |s| s.creation \<=  
\_end  
}  
end  
def search\_all(\*blocks)  
@list.select {|s|  
blocks.all? { |blk| blk.call(s) }  
}  
end

Unfortunately, you can’t pass more than one block at a time - you have  
to  
convert them to procs.

Regards,  
Sean
