Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of github.com:pry/pry

  • Loading branch information...
commit dc0e15cf47ad75d0ed671955c1c8037c23815ff1 2 parents 39d8672 + b1c0494
@banister banister authored
Showing with 101 additions and 67 deletions.
  1. +101 −67 lib/pry/default_commands/find_method.rb
View
168 lib/pry/default_commands/find_method.rb
@@ -32,94 +32,128 @@ def process
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 == []
- puts text.bold("No Methods Matched")
+
+ matches = if opts.content?
+ content_search(pattern, klass)
+ else
+ name_search(pattern, klass)
+ end
+
+ if matches.empty?
+ output.puts text.bold("No Methods Matched")
else
- puts text.bold("Methods Matched")
- puts "--"
- stagger_output to_put.join("\n")
+ print_matches(matches, pattern)
end
end
private
- def puts(item)
- output.puts item
- end
+ # pretty-print a list of matching methods.
+ #
+ # @param Array[Method]
+ def print_matches(matches, pattern)
+ grouped = matches.group_by(&:owner)
+ order = grouped.keys.sort_by{ |x| x.name || x.to_s }
- 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
- 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
+ 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
- klass.constants.each do |klazz|
+ end
+
+ # 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
- meths += ((res = content_search(pattern, klass.const_get(klazz), current, the_methods)) ? res : [])
- rescue Pry::RescuableException
- 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
- 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
Please sign in to comment.
Something went wrong with that request. Please try again.