Skip to content

Instantly share code, notes, and snippets.

@koppen
Created May 15, 2015 11:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save koppen/bbe92e5a0b41ffa232e0 to your computer and use it in GitHub Desktop.
Save koppen/bbe92e5a0b41ffa232e0 to your computer and use it in GitHub Desktop.
Find methods that return a value given a receiver and arguments
#!/usr/bin/env ruby
wanted = if ARGV.any?
[
ARGV.map { |argument| eval(argument) }
]
else
# 1: The receiver
# 2: Expected result
# 3+: Arguments
[
[1, 2, 1],
[2, 4, 2],
]
end
def find_methods(wanted)
def result(receiver, method_name, arguments)
if arguments.any?
receiver.send(method_name, *arguments)
else
receiver.send(method_name)
end
rescue ArgumentError => e
false
rescue LocalJumpError => e
false # This methods needs a block
rescue NameError, RuntimeError, TypeError => e
false # Shit happens
end
def match?(method_name, receiver, arguments, wanted_result)
begin
receiver = receiver.dup if receiver.respond_to?(:dup)
rescue TypeError
# Some objects, like Fixnum, respond_to :dup, but can't actually be duped
end
result(receiver, method_name, arguments) == wanted_result
end
def methods_matching_result(receiver, arguments, wanted_result)
methods_with_arity(receiver, arguments.size).select { |method_name|
match?(method_name, receiver, arguments, wanted_result)
}
end
def methods_with_arity(receiver, number_of_arguments)
receiver.methods.select do |method_name|
arity = receiver.method(method_name).arity
if arity == -1
# This is a method written in C, taking a variable number of methods,
# and we can't know the exact number
else
arity == number_of_arguments || arity == -1 - number_of_arguments
end
end
end
wanted.map do |w|
w = w.dup
receiver = w.shift
wanted_result = w.shift
arguments = w
methods_matching_result(receiver, arguments, wanted_result).map { |method_name|
call = "#{receiver.inspect}.#{method_name}"
arglist = if arguments.any?
"(#{arguments.map(&:inspect).join(',')})"
else
""
end
"#{call}#{arglist} #=> #{wanted_result.inspect}"
}
end
end
puts find_methods(wanted)
$ ./find_method.rb "foo" "FOO"
"foo".upcase #=> "FOO"
"foo".swapcase #=> "FOO"
"foo".upcase! #=> "FOO"
"foo".swapcase! #=> "FOO"
$ ./find_method.rb 1 2
1.succ #=> 2
1.next #=> 2
$ ./find_method.rb 1 2 2
1.*(2) #=> 2
1.lcm(2) #=> 2
$ ./find_method.rb \[1,2\] \[2,1\]
[1, 2].reverse #=> [2, 1]
[1, 2].reverse! #=> [2, 1]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment