/usr/lib/ruby/vendor_ruby/pry/commands/find_method.rb is in pry 0.10.3-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | class Pry
class Command::FindMethod < Pry::ClassCommand
extend Pry::Helpers::BaseHelpers
match 'find-method'
group 'Context'
description 'Recursively search for a method within a Class/Module or the current namespace.'
command_options :shellwords => false
banner <<-'BANNER'
Usage: find-method [-n|-c] METHOD [NAMESPACE]
Recursively search for a method within a Class/Module or the current namespace.
Use the `-n` switch (the default) to search for methods whose name matches the
given regex. Use the `-c` switch to search for methods that contain the given
code.
# Find all methods whose name match /re/ inside
# the Pry namespace. Matches Pry#repl, etc.
find-method re Pry
# Find all methods that contain the code:
# output.puts inside the Pry namepsace.
find-method -c 'output.puts' Pry
BANNER
def options(opt)
opt.on :n, :name, "Search for a method by name"
opt.on :c, :content, "Search for a method based on content in Regex form"
end
def process
return if args.size < 1
klass = search_class
matches = if opts.content?
content_search(klass)
else
name_search(klass)
end
show_search_results(matches)
end
private
# @return [Regexp] The pattern to search for.
def pattern
@pattern ||= ::Regexp.new args[0]
end
# Output the result of the search.
#
# @param [Array] matches
def show_search_results(matches)
if matches.empty?
output.puts text.bold("No Methods Matched")
else
print_matches(matches)
end
end
# The class to search for methods.
# We only search classes, so if the search object is an
# instance, return its class. If no search object is given
# search `target_self`.
def search_class
klass = if args[1]
target.eval(args[1])
else
target_self
end
klass.is_a?(Module) ? klass : klass.class
end
# pretty-print a list of matching methods.
#
# @param [Array<Method>] matches
def print_matches(matches)
grouped = matches.group_by(&:owner)
order = grouped.keys.sort_by{ |x| x.name || x.to_s }
order.each do |klass|
print_matches_for_class(klass, grouped)
end
end
# Print matched methods for a class
def print_matches_for_class(klass, grouped)
output.puts text.bold(klass.name)
grouped[klass].each do |method|
header = method.name_with_owner
output.puts header + additional_info(header, method)
end
end
# Return the matched lines of method source if `-c` is given or ""
# if `-c` was not given
def additional_info(header, method)
if opts.content?
": " << colorize_code(matched_method_lines(header, method))
else
""
end
end
def matched_method_lines(header, method)
method.source.split(/\n/).select {|x| x =~ pattern }.join("\n#{' ' * header.length}")
end
# Run the given block against every constant in the provided namespace.
#
# @param [Module] klass The namespace in which to start the search.
# @param [Hash<Module,Boolean>] done The namespaces we've already visited (private)
# @yieldparam klass Each class/module in the namespace.
#
def recurse_namespace(klass, done={}, &block)
return if !(Module === klass) || done[klass]
done[klass] = true
yield klass
klass.constants.each do |name|
next if klass.autoload?(name)
begin
const = klass.const_get(name)
rescue RescuableException
# 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
end
# Gather all the methods in a namespace that pass the given block.
#
# @param [Module] namespace The namespace in which to search.
# @yieldparam [Method] 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
matches
end
# Search for all methods with a name that matches the given regex
# within a namespace.
#
# @param [Module] namespace The namespace to search
# @return [Array<Method>]
#
def name_search(namespace)
search_all_methods(namespace) do |meth|
meth.name =~ pattern
end
end
# Search for all methods who's implementation matches the given regex
# within a namespace.
#
# @param [Module] namespace The namespace to search
# @return [Array<Method>]
#
def content_search(namespace)
search_all_methods(namespace) do |meth|
begin
meth.source =~ pattern
rescue RescuableException
false
end
end
end
end
Pry::Commands.add_command(Pry::Command::FindMethod)
end
|