pry 0.9.8.4-i386-mingw32 → 0.9.9-i386-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/CHANGELOG +26 -0
- data/README.markdown +3 -3
- data/lib/pry.rb +9 -1
- data/lib/pry/code.rb +93 -0
- data/lib/pry/command.rb +35 -22
- data/lib/pry/command_set.rb +97 -67
- data/lib/pry/config.rb +63 -10
- data/lib/pry/core_extensions.rb +24 -18
- data/lib/pry/default_commands/context.rb +72 -12
- data/lib/pry/default_commands/easter_eggs.rb +4 -0
- data/lib/pry/default_commands/editing.rb +43 -15
- data/lib/pry/default_commands/find_method.rb +171 -0
- data/lib/pry/default_commands/hist.rb +10 -6
- data/lib/pry/default_commands/introspection.rb +183 -30
- data/lib/pry/default_commands/ls.rb +77 -7
- data/lib/pry/default_commands/misc.rb +1 -0
- data/lib/pry/default_commands/navigating_pry.rb +1 -8
- data/lib/pry/helpers/base_helpers.rb +10 -2
- data/lib/pry/helpers/command_helpers.rb +23 -40
- data/lib/pry/helpers/documentation_helpers.rb +65 -0
- data/lib/pry/indent.rb +17 -4
- data/lib/pry/method.rb +61 -45
- data/lib/pry/pry_class.rb +9 -3
- data/lib/pry/pry_instance.rb +99 -65
- data/lib/pry/rbx_method.rb +2 -9
- data/lib/pry/version.rb +1 -1
- data/lib/pry/wrapped_module.rb +236 -1
- data/pry.gemspec +5 -5
- data/test/helper.rb +22 -0
- data/test/test_command.rb +29 -0
- data/test/test_command_integration.rb +193 -10
- data/test/test_command_set.rb +82 -17
- data/test/test_default_commands/test_cd.rb +16 -0
- data/test/test_default_commands/test_context.rb +61 -0
- data/test/test_default_commands/test_documentation.rb +163 -43
- data/test/test_default_commands/test_find_method.rb +42 -0
- data/test/test_default_commands/test_input.rb +32 -0
- data/test/test_default_commands/test_introspection.rb +50 -197
- data/test/test_default_commands/test_ls.rb +22 -0
- data/test/test_default_commands/test_show_source.rb +306 -0
- data/test/test_pry.rb +3 -3
- data/test/test_pry_defaults.rb +21 -0
- data/test/test_sticky_locals.rb +81 -1
- data/test/test_syntax_checking.rb +7 -6
- metadata +24 -16
data/lib/pry/config.rb
CHANGED
@@ -4,44 +4,82 @@ class Pry
|
|
4
4
|
class Config < OpenStruct
|
5
5
|
|
6
6
|
# Get/Set the object to use for input by default by all Pry instances.
|
7
|
+
# Pry.config.input is an option determining the input object - the object from
|
8
|
+
# which Pry retrieves its lines of input. Pry accepts any object that implements the readline method.
|
9
|
+
# This includes IO objects, StringIO, Readline, File and custom objects.
|
7
10
|
# @return [#readline] The object to use for input by default by all
|
8
11
|
# Pry instances.
|
12
|
+
# @example
|
13
|
+
# Pry.config.input = StringIO.new("@x = 10\nexit")
|
9
14
|
attr_accessor :input
|
10
15
|
|
11
16
|
# Get/Set the object to use for output by default by all Pry instances.
|
17
|
+
# Pry.config.output is an option determining the output object - the object to which
|
18
|
+
# Pry writes its output. Pry accepts any object that implements the puts method. This
|
19
|
+
# includes IO objects, StringIO, File and custom objects.
|
12
20
|
# @return [#puts] The object to use for output by default by all
|
13
21
|
# Pry instances.
|
22
|
+
# @example
|
23
|
+
# Pry.config.output = StringIO.new
|
14
24
|
attr_accessor :output
|
15
25
|
|
16
26
|
# Get/Set the object to use for commands by default by all Pry instances.
|
17
27
|
# @return [Pry::CommandBase] The object to use for commands by default by all
|
18
28
|
# Pry instances.
|
29
|
+
# @example
|
30
|
+
# Pry.config.commands = Pry::CommandSet.new do
|
31
|
+
# import_from Pry::Commands, "ls"
|
32
|
+
#
|
33
|
+
# command "greet" do |name|
|
34
|
+
# output.puts "hello #{name}"
|
35
|
+
# end
|
36
|
+
# end
|
19
37
|
attr_accessor :commands
|
20
38
|
|
21
39
|
# Get/Set the Proc to use for printing by default by all Pry
|
22
40
|
# instances.
|
41
|
+
# Two parameters are passed to the print Proc: these are (1) the
|
42
|
+
# output object for the current session and (2) the expression value to print. It is important
|
43
|
+
# that you write to the output object instead of just stdout so that all Pry output can be redirected if necessary.
|
23
44
|
# This is the 'print' component of the REPL.
|
24
45
|
# @return [Proc] The Proc to use for printing by default by all
|
25
46
|
# Pry instances.
|
47
|
+
# @example
|
48
|
+
# Pry.config.print = proc { |output, value| output.puts "=> #{value.inspect}" }
|
26
49
|
attr_accessor :print
|
27
50
|
|
51
|
+
# Pry.config.exception_handler is an option determining the exception handler object - the
|
52
|
+
# Proc responsible for dealing with exceptions raised by user input to the REPL.
|
53
|
+
# Three parameters are passed to the exception handler Proc: these
|
54
|
+
# are (1) the output object for the current session, (2) the
|
55
|
+
# exception object that was raised inside the Pry session, and (3)
|
56
|
+
# a reference to the associated Pry instance.
|
28
57
|
# @return [Proc] The Proc to use for printing exceptions by default by all
|
29
58
|
# Pry instances.
|
59
|
+
# @example
|
60
|
+
# Pry.config.exception_handler = proc do |output, exception, _|
|
61
|
+
# output.puts "#{exception.class}: #{exception.message}"
|
62
|
+
# output.puts "from #{exception.backtrace.first}"
|
63
|
+
# end
|
30
64
|
attr_accessor :exception_handler
|
31
65
|
|
32
66
|
# @return [Array] The classes of exception that will not be caught by Pry.
|
67
|
+
# @example
|
68
|
+
# Pry.config.exception_whitelist = [SystemExit, SignalException]
|
33
69
|
attr_accessor :exception_whitelist
|
34
70
|
|
35
71
|
# @return [Fixnum] The number of lines of context to show before and after
|
36
72
|
# exceptions, etc.
|
73
|
+
# @example
|
74
|
+
# Pry.config.default_window_size = 10
|
37
75
|
attr_accessor :default_window_size
|
38
76
|
|
39
|
-
# Get/Set the
|
77
|
+
# Get/Set the `Pry::Hooks` instance that defines Pry hooks used by default by all Pry
|
40
78
|
# instances.
|
41
|
-
# @return [
|
79
|
+
# @return [Pry::Hooks] The hooks used by default by all Pry instances.
|
42
80
|
# @example
|
43
|
-
# Pry.hooks :before_session
|
44
|
-
#
|
81
|
+
# Pry.config.hooks = Pry::Hooks.new.add_hook(:before_session,
|
82
|
+
# :default) { |output, target, _pry_| output.puts "Good morning!" }
|
45
83
|
attr_reader :hooks
|
46
84
|
|
47
85
|
# FIXME:
|
@@ -63,23 +101,32 @@ class Pry
|
|
63
101
|
# Pry.config.input_stack = [StringIO.new("puts 'hello world'\nexit")]
|
64
102
|
attr_accessor :input_stack
|
65
103
|
|
66
|
-
# Get the array of Procs to be used for the prompts by default by
|
104
|
+
# Get the array of Procs (or single Proc) to be used for the prompts by default by
|
67
105
|
# all Pry instances.
|
68
|
-
#
|
106
|
+
# Three parameters are passed into the prompt procs, (1) the
|
107
|
+
# object that is the target of the session, (2) the current
|
108
|
+
# nesting level, and (3) a reference to the associated Pry instance. These objects can be used in the prompt, if desired.
|
109
|
+
# @return [Array<Proc>, Proc] The array of Procs to be used for the
|
69
110
|
# prompts by default by all Pry instances.
|
111
|
+
# @example
|
112
|
+
# Pry.config.prompt = proc { |obj, nest_level, _pry_| "#{obj}:#{nest_level}> " }
|
70
113
|
attr_accessor :prompt
|
71
114
|
|
72
|
-
# The default editor to use. Defaults to $EDITOR or
|
73
|
-
#
|
115
|
+
# The default editor to use. Defaults to $VISUAL, $EDITOR, or a sensible fallback
|
116
|
+
# for the platform.
|
74
117
|
# If `editor` is a String then that string is used as the shell
|
75
118
|
# command to invoke the editor. If `editor` is callable (e.g a
|
76
|
-
# Proc) then `file` and `
|
119
|
+
# Proc) then `file`, `line`, and `reloading` are passed in as parameters and the
|
77
120
|
# return value of that callable invocation is used as the exact
|
78
|
-
# shell command to invoke the editor.
|
121
|
+
# shell command to invoke the editor. `reloading` indicates whether Pry will be
|
122
|
+
# reloading code after the shell command returns. Any or all of these parameters
|
123
|
+
# can be omitted from the callable's signature.
|
79
124
|
# @example String
|
80
125
|
# Pry.config.editor = "emacsclient"
|
81
126
|
# @example Callable
|
82
127
|
# Pry.config.editor = proc { |file, line| "emacsclient #{file} +#{line}" }
|
128
|
+
# @example Callable waiting only if reloading
|
129
|
+
# Pry.config.editor = proc { |file, line, reloading| "subl #{'--wait' if reloading} #{file}:#{line}" }
|
83
130
|
# @return [String, #call]
|
84
131
|
attr_accessor :editor
|
85
132
|
|
@@ -171,6 +218,12 @@ class Pry
|
|
171
218
|
# Pry.config.gist.inspecter = proc &:inspect
|
172
219
|
# @return [OpenStruct]
|
173
220
|
attr_accessor :gist
|
221
|
+
|
222
|
+
# @return [Hash] Additional sticky locals (to the standard ones) to use in Pry sessions.
|
223
|
+
# @example Inject `random_number` sticky local into Pry session
|
224
|
+
# Pry.config.extra_sticky_locals = { :random_number => proc {
|
225
|
+
# rand(10) } }
|
226
|
+
attr_accessor :extra_sticky_locals
|
174
227
|
end
|
175
228
|
end
|
176
229
|
|
data/lib/pry/core_extensions.rb
CHANGED
@@ -1,23 +1,29 @@
|
|
1
1
|
class Object
|
2
|
-
# Start a Pry REPL.
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# @param [Object, Binding] target The receiver of the Pry session.
|
13
|
-
# @example First form
|
2
|
+
# Start a Pry REPL. This method only differs from Pry.start in that it
|
3
|
+
# assumes that the target is `self`. It also accepts and passses the same
|
4
|
+
# exact options hash that Pry.start accepts. POSSIBLE DEPRICATION WARNING:
|
5
|
+
# In the future the backwards compatibility with pry(binding) could be
|
6
|
+
# removed so please properly use Object.pry or if you use pry(binding)
|
7
|
+
# switch Pry.start(binding).
|
8
|
+
|
9
|
+
# @param [Binding] the binding or options hash if no binding needed.
|
10
|
+
# @param [Hash] the options hash.
|
11
|
+
# @example First
|
14
12
|
# "dummy".pry
|
15
|
-
# @example Second
|
16
|
-
# pry
|
17
|
-
# @example
|
18
|
-
#
|
19
|
-
|
20
|
-
|
13
|
+
# @example Second
|
14
|
+
# binding.pry
|
15
|
+
# @example An example with options
|
16
|
+
# def my_method
|
17
|
+
# binding.pry :quiet => true
|
18
|
+
# end
|
19
|
+
# my_method()
|
20
|
+
|
21
|
+
def pry(*args)
|
22
|
+
if args.first.is_a?(Hash) || args.length == 0
|
23
|
+
args.unshift(self)
|
24
|
+
end
|
25
|
+
|
26
|
+
Pry.start(*args)
|
21
27
|
end
|
22
28
|
|
23
29
|
# Return a binding object for the receiver.
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "pry/default_commands/ls"
|
2
2
|
require "pry/default_commands/cd"
|
3
|
+
require "pry/default_commands/find_method"
|
3
4
|
|
4
5
|
class Pry
|
5
6
|
module DefaultCommands
|
@@ -7,24 +8,62 @@ class Pry
|
|
7
8
|
Context = Pry::CommandSet.new do
|
8
9
|
import Ls
|
9
10
|
import Cd
|
11
|
+
import FindMethod
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
create_command "whereami" do
|
14
|
+
description "Show code surrounding the current context."
|
15
|
+
banner <<-BANNER
|
16
|
+
Usage: whereami [OPTIONS]
|
17
|
+
BANNER
|
14
18
|
|
15
|
-
|
16
|
-
|
19
|
+
def setup
|
20
|
+
@method = Pry::Method.from_binding(target)
|
17
21
|
end
|
18
22
|
|
19
|
-
|
23
|
+
def process
|
24
|
+
if show_method?
|
25
|
+
file = @method.source_file
|
26
|
+
start = @method.source_range.begin
|
27
|
+
finish = @method.source_range.end
|
28
|
+
marker = target.eval("__LINE__")
|
29
|
+
else
|
30
|
+
file = target.eval("__FILE__")
|
31
|
+
start = target.eval("__LINE__")
|
32
|
+
finish = (args.first && args.first.to_i) || 5
|
33
|
+
marker = start
|
34
|
+
end
|
35
|
+
|
36
|
+
if invalid_file?(file)
|
37
|
+
raise Pry::CommandError,
|
38
|
+
"Cannot find local context. Did you use binding.pry?"
|
39
|
+
end
|
20
40
|
|
21
|
-
|
22
|
-
|
23
|
-
|
41
|
+
# TODO: refactor.
|
42
|
+
if show_method?
|
43
|
+
code = Pry::Code.from_file(file).between(start, finish)
|
44
|
+
else
|
45
|
+
code = Pry::Code.from_file(file).around(start, finish)
|
46
|
+
end
|
47
|
+
|
48
|
+
desc = (@method && @method.name_with_owner) || ""
|
49
|
+
|
50
|
+
if !code.empty?
|
51
|
+
output.puts "\n#{text.bold('From:')} #{file} @ line #{start} #{desc}:\n\n"
|
52
|
+
output.puts code.with_line_numbers.with_marker(marker)
|
53
|
+
output.puts
|
54
|
+
end
|
55
|
+
end
|
24
56
|
|
25
|
-
|
26
|
-
|
27
|
-
|
57
|
+
private
|
58
|
+
|
59
|
+
def show_method?
|
60
|
+
args.empty? && @method && !@method.instance_of?(Pry::Method::Disowned) && @method.source_range.count < 20
|
61
|
+
end
|
62
|
+
|
63
|
+
def invalid_file?(file)
|
64
|
+
file != Pry.eval_path &&
|
65
|
+
(file =~ /(\(.*\))|<.*>/ || file == "" || file == "-e")
|
66
|
+
end
|
28
67
|
end
|
29
68
|
|
30
69
|
create_command "pry-backtrace", "Show the backtrace for the Pry session." do
|
@@ -87,6 +126,27 @@ class Pry
|
|
87
126
|
end
|
88
127
|
end
|
89
128
|
|
129
|
+
# N.B. using a regular expresion here so that "raise-up 'foo'" does the right thing.
|
130
|
+
create_command /raise-up(!?\b.*)/, :listing => 'raise-up' do
|
131
|
+
description "Raise an exception out of the current pry instance."
|
132
|
+
banner <<-BANNER
|
133
|
+
Raise up, like exit, allows you to quit pry. Instead of returning a value however, it raises an exception.
|
134
|
+
If you don't provide the exception to be raised, it will use the most recent exception (in pry _ex_).
|
135
|
+
|
136
|
+
e.g. `raise-up "get-me-out-of-here"` is equivalent to:
|
137
|
+
`raise "get-me-out-of-here"
|
138
|
+
raise-up`
|
139
|
+
|
140
|
+
When called as raise-up! (with an exclamation mark), this command raises the exception through
|
141
|
+
any nested prys you have created by "cd"ing into objects.
|
142
|
+
BANNER
|
143
|
+
|
144
|
+
def process
|
145
|
+
return stagger_output help if captures[0] =~ /(-h|--help)\b/
|
146
|
+
# Handle 'raise-up', 'raise-up "foo"', 'raise-up RuntimeError, 'farble' in a rubyesque manner
|
147
|
+
target.eval("_pry_.raise_up#{captures[0]}")
|
148
|
+
end
|
149
|
+
end
|
90
150
|
end
|
91
151
|
end
|
92
152
|
end
|
@@ -88,8 +88,9 @@ class Pry
|
|
88
88
|
temp_file do |f|
|
89
89
|
f.puts(content)
|
90
90
|
f.flush
|
91
|
-
|
92
|
-
|
91
|
+
reload = !opts.present?(:'no-reload') && !Pry.config.disable_auto_reload
|
92
|
+
invoke_editor(f.path, line, reload)
|
93
|
+
if reload
|
93
94
|
silence_warnings do
|
94
95
|
eval_string.replace(File.read(f.path))
|
95
96
|
end
|
@@ -138,10 +139,11 @@ class Pry
|
|
138
139
|
|
139
140
|
line = opts[:l].to_i if opts.present?(:line)
|
140
141
|
|
141
|
-
|
142
|
+
reload = opts.present?(:reload) || ((opts.present?(:ex) || file_name.end_with?(".rb")) && !opts.present?(:'no-reload')) && !Pry.config.disable_auto_reload
|
143
|
+
invoke_editor(file_name, line, reload)
|
142
144
|
set_file_and_dir_locals(file_name)
|
143
145
|
|
144
|
-
if
|
146
|
+
if reload
|
145
147
|
silence_warnings do
|
146
148
|
TOPLEVEL_BINDING.eval(File.read(file_name), file_name)
|
147
149
|
end
|
@@ -202,17 +204,12 @@ class Pry
|
|
202
204
|
def process_patch
|
203
205
|
lines = @method.source.lines.to_a
|
204
206
|
|
205
|
-
|
206
|
-
lines[0] =~ /^def (?:.*?\.)?#{original_name}(?=[\(\s;]|$)/)
|
207
|
-
lines[0] = "def #{original_name}#{$'}"
|
208
|
-
else
|
209
|
-
raise CommandError, "Pry can only patch methods created with the `def` keyword."
|
210
|
-
end
|
207
|
+
lines[0] = definition_line_for_owner(lines[0])
|
211
208
|
|
212
209
|
temp_file do |f|
|
213
210
|
f.puts lines.join
|
214
211
|
f.flush
|
215
|
-
invoke_editor(f.path, 0)
|
212
|
+
invoke_editor(f.path, 0, true)
|
216
213
|
|
217
214
|
if @method.alias?
|
218
215
|
with_method_transaction(original_name, @method.owner) do
|
@@ -228,9 +225,10 @@ class Pry
|
|
228
225
|
def process_file
|
229
226
|
file, line = extract_file_and_line
|
230
227
|
|
231
|
-
|
228
|
+
reload = !opts.present?(:'no-reload') && !Pry.config.disable_auto_reload
|
229
|
+
invoke_editor(file, opts["no-jump"] ? 0 : line, reload)
|
232
230
|
silence_warnings do
|
233
|
-
load file
|
231
|
+
load file if reload
|
234
232
|
end
|
235
233
|
end
|
236
234
|
|
@@ -257,6 +255,34 @@ class Pry
|
|
257
255
|
ensure
|
258
256
|
target.eval("undef #{temp_name}") rescue nil
|
259
257
|
end
|
258
|
+
|
259
|
+
# The original name of the method, if it's not present raise an error telling
|
260
|
+
# the user why we don't work.
|
261
|
+
#
|
262
|
+
def original_name
|
263
|
+
@method.original_name or raise CommandError, "Pry can only patch methods created with the `def` keyword."
|
264
|
+
end
|
265
|
+
|
266
|
+
# Update the definition line so that it can be eval'd directly on the Method's
|
267
|
+
# owner instead of from the original context.
|
268
|
+
#
|
269
|
+
# In particular this takes `def self.foo` and turns it into `def foo` so that we
|
270
|
+
# don't end up creating the method on the singleton class of the singleton class
|
271
|
+
# by accident.
|
272
|
+
#
|
273
|
+
# This is necessarily done by String manipulation because we can't find out what
|
274
|
+
# syntax is needed for the argument list by ruby-level introspection.
|
275
|
+
#
|
276
|
+
# @param String The original definition line. e.g. def self.foo(bar, baz=1)
|
277
|
+
# @return String The new definition line. e.g. def foo(bar, baz=1)
|
278
|
+
#
|
279
|
+
def definition_line_for_owner(line)
|
280
|
+
if line =~ /^def (?:.*?\.)?#{Regexp.escape(original_name)}(?=[\(\s;]|$)/
|
281
|
+
"def #{original_name}#{$'}"
|
282
|
+
else
|
283
|
+
raise CommandError, "Could not find original `def #{original_name}` line to patch."
|
284
|
+
end
|
285
|
+
end
|
260
286
|
end
|
261
287
|
|
262
288
|
create_command(/amend-line(?: (-?\d+)(?:\.\.(-?\d+))?)?/) do
|
@@ -301,6 +327,8 @@ class Pry
|
|
301
327
|
end
|
302
328
|
|
303
329
|
create_command "play" do
|
330
|
+
include Helpers::DocumentationHelpers
|
331
|
+
|
304
332
|
description "Play back a string variable or a method or a file as input."
|
305
333
|
|
306
334
|
banner <<-BANNER
|
@@ -343,7 +371,7 @@ class Pry
|
|
343
371
|
self.content << File.read(File.expand_path(file))
|
344
372
|
end
|
345
373
|
opt.on :l, :lines, "Only play a subset of lines.", :optional => true, :as => Range, :default => 1..-1
|
346
|
-
opt.on :i, :in, "Play entries from Pry's input expression history. Takes an index or range.", :optional => true,
|
374
|
+
opt.on :i, :in, "Play entries from Pry's input expression history. Takes an index or range. Note this can only replay pure Ruby code, not Pry commands.", :optional => true,
|
347
375
|
:as => Range, :default => -5..-1 do |range|
|
348
376
|
input_expressions = _pry_.input_array[range] || []
|
349
377
|
Array(input_expressions).each { |v| self.content << v }
|
@@ -353,7 +381,7 @@ class Pry
|
|
353
381
|
|
354
382
|
def process
|
355
383
|
perform_play
|
356
|
-
run "show-input" unless
|
384
|
+
run "show-input" unless Pry::Code.complete_expression?(eval_string)
|
357
385
|
end
|
358
386
|
|
359
387
|
def process_non_opt
|
@@ -0,0 +1,171 @@
|
|
1
|
+
class Pry
|
2
|
+
module DefaultCommands
|
3
|
+
FindMethod = Pry::CommandSet.new do
|
4
|
+
|
5
|
+
create_command "find-method" do
|
6
|
+
extend Helpers::BaseHelpers
|
7
|
+
|
8
|
+
group "Context"
|
9
|
+
|
10
|
+
options :requires_gem => "ruby18_source_location" if mri_18?
|
11
|
+
|
12
|
+
description "Recursively search for a method within a Class/Module or the current namespace. find-method [-n | -c] METHOD [NAMESPACE]"
|
13
|
+
|
14
|
+
banner <<-BANNER
|
15
|
+
Usage: find-method [-n | -c] METHOD [NAMESPACE]
|
16
|
+
|
17
|
+
Recursively search for a method within a Class/Module or the current namespace.
|
18
|
+
Use the `-n` switch (the default) to search for methods whose name matches the given regex.
|
19
|
+
Use the `-c` switch to search for methods that contain the given code.
|
20
|
+
|
21
|
+
e.g find re Pry # find all methods whose name match /re/ inside the Pry namespace. Matches Pry#repl, etc.
|
22
|
+
e.g find -c 'output.puts' Pry # find all methods that contain the code: output.puts inside the Pry namepsace.
|
23
|
+
BANNER
|
24
|
+
|
25
|
+
def setup
|
26
|
+
require 'ruby18_source_location' if mri_18?
|
27
|
+
end
|
28
|
+
|
29
|
+
def options(opti)
|
30
|
+
opti.on :n, :name, "Search for a method by name"
|
31
|
+
opti.on :c, :content, "Search for a method based on content in Regex form"
|
32
|
+
end
|
33
|
+
|
34
|
+
def process
|
35
|
+
return if args.size < 1
|
36
|
+
pattern = ::Regexp.new args[0]
|
37
|
+
if args[1]
|
38
|
+
klass = target.eval(args[1])
|
39
|
+
if !klass.is_a?(Module)
|
40
|
+
klass = klass.class
|
41
|
+
end
|
42
|
+
else
|
43
|
+
klass = (target_self.is_a?(Module)) ? target_self : target_self.class
|
44
|
+
end
|
45
|
+
|
46
|
+
matches = if opts.content?
|
47
|
+
content_search(pattern, klass)
|
48
|
+
else
|
49
|
+
name_search(pattern, klass)
|
50
|
+
end
|
51
|
+
|
52
|
+
if matches.empty?
|
53
|
+
output.puts text.bold("No Methods Matched")
|
54
|
+
else
|
55
|
+
print_matches(matches, pattern)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# pretty-print a list of matching methods.
|
63
|
+
#
|
64
|
+
# @param Array[Method]
|
65
|
+
def print_matches(matches, pattern)
|
66
|
+
grouped = matches.group_by(&:owner)
|
67
|
+
order = grouped.keys.sort_by{ |x| x.name || x.to_s }
|
68
|
+
|
69
|
+
order.each do |klass|
|
70
|
+
output.puts text.bold(klass.name)
|
71
|
+
grouped[klass].each do |method|
|
72
|
+
header = method.name_with_owner
|
73
|
+
|
74
|
+
extra = if opts.content?
|
75
|
+
header += ": "
|
76
|
+
colorize_code((method.source.split(/\n/).select {|x| x =~ pattern }).join("\n#{' ' * header.length}"))
|
77
|
+
else
|
78
|
+
""
|
79
|
+
end
|
80
|
+
|
81
|
+
output.puts header + extra
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Run the given block against every constant in the provided namespace.
|
87
|
+
#
|
88
|
+
# @param Module The namespace in which to start the search.
|
89
|
+
# @param Hash[Module,Boolean] The namespaces we've already visited (private)
|
90
|
+
# @yieldparam klazz Each class/module in the namespace.
|
91
|
+
#
|
92
|
+
def recurse_namespace(klass, done={}, &block)
|
93
|
+
if done[klass] || !(Module === klass)
|
94
|
+
return
|
95
|
+
end
|
96
|
+
|
97
|
+
done[klass] = true
|
98
|
+
|
99
|
+
yield klass
|
100
|
+
|
101
|
+
klass.constants.each do |name|
|
102
|
+
next if klass.autoload?(name)
|
103
|
+
begin
|
104
|
+
const = klass.const_get(name)
|
105
|
+
rescue RescuableException => e
|
106
|
+
# constant loading is an inexact science at the best of times,
|
107
|
+
# this often happens when a constant was .autoload? but someone
|
108
|
+
# tried to load it. It's now not .autoload? but will still raise
|
109
|
+
# a NameError when you access it.
|
110
|
+
else
|
111
|
+
recurse_namespace(const, done, &block)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Gather all the methods in a namespace that pass the given block.
|
117
|
+
#
|
118
|
+
# @param Module The namespace in which to search.
|
119
|
+
# @yieldparam Method The method to test
|
120
|
+
# @yieldreturn Boolean
|
121
|
+
# @return Array[Method]
|
122
|
+
#
|
123
|
+
def search_all_methods(namespace)
|
124
|
+
done = Hash.new{ |h,k| h[k] = {} }
|
125
|
+
matches = []
|
126
|
+
|
127
|
+
recurse_namespace(namespace) do |klass|
|
128
|
+
(Pry::Method.all_from_class(klass) + Pry::Method.all_from_obj(klass)).each do |method|
|
129
|
+
next if done[method.owner][method.name]
|
130
|
+
done[method.owner][method.name] = true
|
131
|
+
|
132
|
+
matches << method if yield method
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
matches
|
137
|
+
end
|
138
|
+
|
139
|
+
# Search for all methods with a name that matches the given regex
|
140
|
+
# within a namespace.
|
141
|
+
#
|
142
|
+
# @param Regex The regex to search for
|
143
|
+
# @param Module The namespace to search
|
144
|
+
# @return Array[Method]
|
145
|
+
#
|
146
|
+
def name_search(regex, namespace)
|
147
|
+
search_all_methods(namespace) do |meth|
|
148
|
+
meth.name =~ regex
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Search for all methods who's implementation matches the given regex
|
153
|
+
# within a namespace.
|
154
|
+
#
|
155
|
+
# @param Regex The regex to search for
|
156
|
+
# @param Module The namespace to search
|
157
|
+
# @return Array[Method]
|
158
|
+
#
|
159
|
+
def content_search(regex, namespace)
|
160
|
+
search_all_methods(namespace) do |meth|
|
161
|
+
begin
|
162
|
+
meth.source =~ regex
|
163
|
+
rescue RescuableException => e
|
164
|
+
false
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|