#
# MethodFinder
#
# Author : David Tran
# Date : 2006-05-20
# Last updated : 2006-05-22
#
# Resources :
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/32844
# http://www.nobugs.org/developer/ruby/method_finder.html
# http://redhanded.hobix.com/inspect/stickItInYourIrbrcMethodfinder.html
# http://atrustheotaku.livejournal.com/339449.html
#
class Object
def what?(*args, &block)
MethodFinder.new(self, *args, &block)
end
def _clone_
self.clone
rescue
self
end
end
class MethodFinder
@@black_list = %w[ what? _clone_ exec exit exit! fork sleep syscall system ]
def initialize(obj, *args, &block)
@obj = obj
@args = args
@block = block
end
def self.write(*args)
end
# Find all methods on obj which, when called with *args, &block return result
def self.find(obj, result, *args, &block)
stdout, stderr = $stdout, $stderr
$stdout = $stderr = self
methods = obj.methods.select do |name|
arity = obj.method(name).arity
!@@black_list.include?(name) and
(arity == args.size) || (arity < 0 && (arity+1).abs <= args.size) and
begin obj._clone_.send(name, *args, &block) == result; rescue Object; end
end
$stdout, $stderr = stdout, stderr
methods
end
# As find method but also Pretty-prints the results
def self.show(obj, result, *args, &block)
args_string = args.empty? ? '' : "(" + args.map {|a| a.inspect}.join(", ") + ")"
block_string = block.nil? ? '' : " {...}"
find(obj, result, *args, &block).each do |name|
puts "#{obj.inspect}.#{name}#{args_string}#{block_string} == #{result.inspect}"
end
end
def ==(result)
# MethodFinder.find(@obj, result, *@args, &@block)
MethodFinder.show(@obj, result, *@args, &@block)
end
end
__END__
Some examples:
-1.what? == 1
-1.-@ == 1
-1.abs == 1
-1.denominator == 1
=> ["-@", "abs", "denominator"]
'abc'.what? == 3
"abc".length == 3
"abc".size == 3
=> ["length", "size"]
'a'.what? == 'A'
"a".upcase == "A"
"a".upcase! == "A"
"a".capitalize == "A"
"a".capitalize! == "A"
"a".swapcase == "A"
"a".swapcase! == "A"
=> ["upcase", "upcase!", "capitalize", "capitalize!", "swapcase", "swapcase!"]
[1,2].what? {|s,e| s+e} == 3
[1, 2].instance_eval {...} == 3
[1, 2].inject {...} == 3
=> ["instance_eval", "inject"]
[1,2].what?(0) {|s,e| s+e} == 3
[1, 2].inject(0) {...} == 3
=> ["inject"]
MethodFinder.show(%w[xxx z yy], %w[z yy xxx]) {|e| e.size}
["xxx", "z", "yy"].sort_by {...} == ["z", "yy", "xxx"]
=> ["sort_by"]
#####
updated: 2006-05-22
bug: arity checking
arities = [args.size, -args.size - 1, -1]
arities.include?(obj.method(name).arity)
is not good.
Example:
def m(a, b=1);end
it has arity == -2, so if args.size == 2, [2, -2 - 1, -1].inlcude? check will fail.
==> new checking rule:
((arity >= 0 && arity == args.size) || (arity < 0 && (arity+1).abs <= args.size))
this can simplify to:
(arity == args.size) || (arity < 0 && (arity+1).abs <= args.size)