From: Michael Judge Date: 2006-12-14T11:41:36+09:00 Subject: Re: map taking an argument (was: Re: join_with) On Dec 13, 2006, at 2:40 PM, dblack@wobblini.net wrote: > Hi -- > > On Thu, 14 Dec 2006, James Edward Gray II wrote: > >> On Dec 13, 2006, at 3:56 PM, Christian Neukirchen wrote: >> >>> "Martin DeMello" writes: >>>>> (1..10).map &lambda {|i| i*2} >>>> => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] >>> David, do you want to allow (1..10).map(:*, 2) ? >> >> Does the version currently in Ruby 1.9 support arguments? > > I don't think so. I'm actually not sure where they'd go, since &:meth > is the block and not an argument. > > David A few days ago, I modified Dr. Nic's MapByMethod gem (locally) to attempt to handle arguments. The results were interesting. Scroll down for some examples. # # --copy into irb-- # module FindByMethod def method_missing method, *args, &block begin method_missing_handler method, *args, &block rescue super end end FIND_BY_REGEX = /^(all|any|collect|detect|find_all|find| first_match|grep|group_by|map|none|partition|reject|select|sort_by)_? (by|where)?_([\w_]+\??)$/ QUERY_ITERATORS = ["all","any","none"] def method_missing_handler method, *args, &block unless method.to_s.match FIND_BY_REGEX raise NoMethodError end iterator = $1 selector = $2 callmethod = $3 iterator += "?" if QUERY_ITERATORS.include? iterator self.send(iterator) do |item| if selector == "where" # Arguments used in boolean comparison if args.length == 1 args.first == item.send(callmethod) else args.include? item.send(callmethod) end else # Arguments fall through item.send(callmethod,*args) end end end end Array.send :include, FindByMethod # # ---stop--- # # # Examples! # [1,2,3].map_by_succ # => [2, 3, 4] # -- equivalent to [1,2,3].map { |x| x.succ } [1,2,nil].select_by_nil? # => [nil] # -- equivalent to [1,2,nil].select { |x| x.nil? } # # Now lets try some arguments. # (Normally they're passed right to the method.) # [2,4,6].map_by_div(2) # => [1, 2, 3] ["1","one"].select_by_match(/\d/) # => ["1"] # # If you've gotten ahead of me, you're probably wondering # how you would pull off a rails-like magic finder: # # users.find_by_name("charlie") # # I struggled with that one for a long time, before settling # on using 'find_where' instead of 'find_by' where you need # it to equal an argument rather than pass through an argument. # [1,2,'a'].select_where_class(Fixnum) # => [1, 2] # -- equivalent to [1,2,'a'].select { |x| x.class == Fixnum } # # You can use most enumerable methods as well. # [1,2,3].partition_where_to_f(3.0) # => [[3], [1, 2]] # # Some special cases though are .any?, .none?, and .all? # #They work, but you need to omit the question mark or ruby # throws up all over her prom dress. # [1,2,3].any_by_nil? # => false # # Keep in mind that it's easy to mix up 'where' and 'by'. # Compare these two identical sounding method calls. # [1,2,'a'].select_where_kind_of?(Fixnum) [1,2,'a'].select_by_kind_of?(Fixnum) # Can you guess which works and which crashes? # # _by_ works as it translates into: # x.kind_of?(Fixnum) # #_where_ raises an exception because it becomes gibberish: # x.kind_of? == Fixnum # # I had to run it to figure out the difference too. There's something # seriously wrong with the words I chose to distinguish between # passing an argument from equaling an argument. # # - Mike