From: Joel VanderWerf Date: 2001-12-31T16:08:37+09:00 Subject: [ruby-talk:29820] Re: Proc.class vs yield Michael Lucas-Smith wrote: > The reason I'm bringing this up is because having a criteria block of > code and a failure block of code si very common in Smalltalk. For example: > > childrenOf: aPersonName in: people > people > detect: [:person | person name = aPersonName] > ifFound: [:person | person children] > ifNone: [OrderedCollection new] Someone just mentioned that you could use Enumerable#detect, but if you really want several blocks, you can do something like this: module Enumerable class SearchSpec attr_reader :match_proc, :found_proc, :none_proc def matching(&b) @match_proc = b end def ifFound(&b) @found_proc = b end def ifNone(&b) @none_proc = b end end def search(&b) search_spec = SearchSpec.new search_spec.instance_eval(&b) found = find(&search_spec.match_proc) if found return search_spec.found_proc[found] else return search_spec.none_proc[] end end end zoe = {:name => "Zoe Blow", :children => [] } moe = {:name => "Moe Blow", :children => [zoe] } joe = {:name => "Joe Blow", :children => [moe] } the_blows = [joe, moe, zoe] def children_of name, people people.search { matching { |person| person[:name] == name } ifFound { |person| person[:children] } ifNone { [] } } end [moe] == children_of("Joe Blow", the_blows) # ==> true [] == children_of("Ned Flanders", the_blows) # ==> true Note that 'self' inside the search { ... } will get bound to the auxilliary object, an instance of SearchSpec, and not to the receiver of children_of. With a little work and cleverness, you could automate the generation of the aux class, so that all you'd have to do to define search is something like: def search(search_spec) found = find(&search_spec.match_proc) if found return search_spec.found_proc[found] else return search_spec.none_proc[] end end method_accepts_multiple_blocks :search, [:matching, :match_proc], [:ifFound, :found_proc].... To define method_accepts_multiple_blocks, you'd need to use alias to rename search and wrap a new "search" around it that constructs the SearchSpec and passes it in. You'd also need to create the SearchSpec class (probably anonymously, though) on the fly, unless it already exists, and give it the three methods and three readers. But nobody's done this, so it's probably not very useful.... -- Joel VanderWerf California PATH, UC Berkeley mailto:vjoel@path.berkeley.edu Ph. (510) 231-9446 http://www.path.berkeley.edu FAX (510) 231-9512