On Dec 13, 2006, at 2:40 PM, [email protected] wrote:
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