From: Michael Lucas-Smith Date: 2001-12-31T22:42:01+09:00 Subject: [ruby-talk:29849] Re: Proc.class vs yield That's a good solution, thanks. But I have to say I'm slightly confused as to why everybody seems so against having the Ruby language hide the fact that you're either dealing with a block or a proc. Why must there only be one? Why do you have to use the keyword proc to define a new proc from a block? The common case is to pass a block around, but when you need it to act like an object, you have to turn it in to a proc. I'm all for optimisation. So why can't Ruby do it for you - if the method takes >1 parameters and you hand it some blocks, can't it turn them in to procs for you? (taking in to account the & logic to accept the yield block as a proc) Michael Joel VanderWerf wrote: > 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 > >