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" <martindemello / gmail.com> 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