mirror of
https://github.com/pry/pry.git
synced 2022-11-09 12:35:05 -05:00
Refactor, optimize and slightly correct find-method.
This increases the speed for name_search considerably (~50%), and makes the code a bit more readable. It also Fixes # 527, by deduping methods by the pair of [owner, name] not just name. TODO: Test
This commit is contained in:
parent
9c1ec53861
commit
c6676b7e04
1 changed files with 103 additions and 65 deletions
|
@ -32,94 +32,132 @@ class Pry
|
|||
else
|
||||
klass = (target_self.is_a?(Module)) ? target_self : target_self.class
|
||||
end
|
||||
if opts.name?
|
||||
to_put = name_search(pattern, klass)
|
||||
elsif opts.content?
|
||||
to_put = content_search(pattern, klass)
|
||||
else
|
||||
to_put = name_search(pattern, klass)
|
||||
end
|
||||
1
|
||||
if to_put.flatten == []
|
||||
|
||||
matches = if opts.content?
|
||||
content_search(pattern, klass)
|
||||
else
|
||||
name_search(pattern, klass)
|
||||
end
|
||||
|
||||
if matches.empty?
|
||||
puts text.bold("No Methods Matched")
|
||||
else
|
||||
puts text.bold("Methods Matched")
|
||||
puts "--"
|
||||
stagger_output to_put.join("\n")
|
||||
print_matches(matches)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# pretty-print a list of matching methods.
|
||||
#
|
||||
# @param Array[Method]
|
||||
def print_matches(matches)
|
||||
grouped = matches.group_by(&:owner)
|
||||
order = grouped.keys.sort_by{ |x| x.name || x.to_s }
|
||||
|
||||
order.each do |klass|
|
||||
output.puts text.bold(klass.name)
|
||||
grouped[klass].each do |method|
|
||||
header = method.name_with_owner
|
||||
|
||||
extra = if opts.content?
|
||||
header += ": "
|
||||
colorize_code((method.source.split(/\n/).select {|x| x =~ pattern }).join("\n#{' ' * header.length}"))
|
||||
else
|
||||
""
|
||||
end
|
||||
|
||||
output.puts header + extra
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def puts(item)
|
||||
output.puts item
|
||||
end
|
||||
|
||||
def content_search(pattern, klass, current=[], the_methods=[])
|
||||
return unless(klass.is_a? Module)
|
||||
return if current.include? klass
|
||||
current << klass
|
||||
meths = []
|
||||
(Pry::Method.all_from_class(klass) + Pry::Method.all_from_obj(klass)).uniq.each do |meth|
|
||||
next if the_methods.include? meth.name
|
||||
the_methods << meth.name
|
||||
# Run the given block against every constant in the provided namespace.
|
||||
#
|
||||
# @param Module The namespace in which to start the search.
|
||||
# @param Hash[Module,Boolean] The namespaces we've already visited (private)
|
||||
# @yieldparam klazz Each class/module in the namespace.
|
||||
#
|
||||
def recurse_namespace(klass, done={}, &block)
|
||||
if done[klass] || !(Module === klass)
|
||||
return
|
||||
end
|
||||
|
||||
done[klass] = true
|
||||
|
||||
yield klass
|
||||
|
||||
klass.constants.each do |name|
|
||||
next if klass.autoload?(name)
|
||||
begin
|
||||
if meth.source =~ pattern && !meth.alias?
|
||||
header = "#{klass}##{meth.name}: "
|
||||
meths << header + colorize_code((meth.source.split(/\n/).select {|x| x =~ pattern }).join("\n#{' ' * header.length}"))
|
||||
end
|
||||
rescue Pry::RescuableException
|
||||
next
|
||||
rescue Pry::CommandError
|
||||
next
|
||||
const = klass.const_get(name)
|
||||
rescue RescuableException => e
|
||||
# constant loading is an inexact science at the best of times,
|
||||
# this often happens when a constant was .autoload? but someone
|
||||
# tried to load it. It's now not .autoload? but will still raise
|
||||
# a NameError when you access it.
|
||||
else
|
||||
recurse_namespace(const, done, &block)
|
||||
end
|
||||
end
|
||||
klass.constants.each do |klazz|
|
||||
begin
|
||||
meths += ((res = content_search(pattern, klass.const_get(klazz), current, the_methods)) ? res : [])
|
||||
rescue Pry::RescuableException
|
||||
next
|
||||
end
|
||||
end
|
||||
return meths.uniq.flatten
|
||||
end
|
||||
|
||||
def name_search(regex, klass, current=[], the_methods=[])
|
||||
return unless(klass.is_a? Module)
|
||||
return if current.include? klass
|
||||
current << klass
|
||||
header = text.bold("#{klass.name}:")
|
||||
meths = []
|
||||
(Pry::Method.all_from_class(klass) + Pry::Method.all_from_obj(klass)).uniq.each do |x|
|
||||
next if the_methods.include? x.name
|
||||
the_methods << x.name
|
||||
if x.name =~ regex
|
||||
meths << " #{x.name}"
|
||||
begin
|
||||
if x.alias?
|
||||
meths[-1] += "#A|#{x.original_name}" if x.original_name
|
||||
end
|
||||
rescue Pry::RescuableException
|
||||
end
|
||||
# Gather all the methods in a namespace that pass the given block.
|
||||
#
|
||||
# @param Module The namespace in which to search.
|
||||
# @yieldparam Method The method to test
|
||||
# @yieldreturn Boolean
|
||||
# @return Array[Method]
|
||||
#
|
||||
def search_all_methods(namespace)
|
||||
done = Hash.new{ |h,k| h[k] = {} }
|
||||
matches = []
|
||||
|
||||
recurse_namespace(namespace) do |klass|
|
||||
(Pry::Method.all_from_class(klass) + Pry::Method.all_from_obj(klass)).each do |method|
|
||||
next if done[method.owner][method.name]
|
||||
done[method.owner][method.name] = true
|
||||
|
||||
matches << method if yield method
|
||||
end
|
||||
end
|
||||
max = meths.map(&:length).max
|
||||
meths.map! do |x|
|
||||
if x =~ /#{"#A"}/
|
||||
x = x.sub!("#A|", ((' ' * ((max - x.length) + 3)) + text.bold("(Alias of "))) + text.bold(")")
|
||||
end
|
||||
x
|
||||
|
||||
matches
|
||||
end
|
||||
|
||||
# Search for all methods with a name that matches the given regex
|
||||
# within a namespace.
|
||||
#
|
||||
# @param Regex The regex to search for
|
||||
# @param Module The namespace to search
|
||||
# @return Array[Method]
|
||||
#
|
||||
def name_search(regex, namespace)
|
||||
search_all_methods(namespace) do |meth|
|
||||
meth.name =~ regex
|
||||
end
|
||||
meths.unshift header if meths.size > 0
|
||||
klass.constants.each do |x|
|
||||
end
|
||||
|
||||
# Search for all methods who's implementation matches the given regex
|
||||
# within a namespace.
|
||||
#
|
||||
# @param Regex The regex to search for
|
||||
# @param Module The namespace to search
|
||||
# @return Array[Method]
|
||||
#
|
||||
def content_search(regex, namespace)
|
||||
search_all_methods(namespace) do |meth|
|
||||
begin
|
||||
meths << ((res = name_search(regex, klass.const_get(x), current, the_methods)) ? res : [])
|
||||
rescue Pry::RescuableException
|
||||
next
|
||||
meth.source =~ regex
|
||||
rescue RescuableException => e
|
||||
false
|
||||
end
|
||||
end
|
||||
return meths.uniq.flatten
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue