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.
Files changed (46) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG +26 -0
  3. data/README.markdown +3 -3
  4. data/lib/pry.rb +9 -1
  5. data/lib/pry/code.rb +93 -0
  6. data/lib/pry/command.rb +35 -22
  7. data/lib/pry/command_set.rb +97 -67
  8. data/lib/pry/config.rb +63 -10
  9. data/lib/pry/core_extensions.rb +24 -18
  10. data/lib/pry/default_commands/context.rb +72 -12
  11. data/lib/pry/default_commands/easter_eggs.rb +4 -0
  12. data/lib/pry/default_commands/editing.rb +43 -15
  13. data/lib/pry/default_commands/find_method.rb +171 -0
  14. data/lib/pry/default_commands/hist.rb +10 -6
  15. data/lib/pry/default_commands/introspection.rb +183 -30
  16. data/lib/pry/default_commands/ls.rb +77 -7
  17. data/lib/pry/default_commands/misc.rb +1 -0
  18. data/lib/pry/default_commands/navigating_pry.rb +1 -8
  19. data/lib/pry/helpers/base_helpers.rb +10 -2
  20. data/lib/pry/helpers/command_helpers.rb +23 -40
  21. data/lib/pry/helpers/documentation_helpers.rb +65 -0
  22. data/lib/pry/indent.rb +17 -4
  23. data/lib/pry/method.rb +61 -45
  24. data/lib/pry/pry_class.rb +9 -3
  25. data/lib/pry/pry_instance.rb +99 -65
  26. data/lib/pry/rbx_method.rb +2 -9
  27. data/lib/pry/version.rb +1 -1
  28. data/lib/pry/wrapped_module.rb +236 -1
  29. data/pry.gemspec +5 -5
  30. data/test/helper.rb +22 -0
  31. data/test/test_command.rb +29 -0
  32. data/test/test_command_integration.rb +193 -10
  33. data/test/test_command_set.rb +82 -17
  34. data/test/test_default_commands/test_cd.rb +16 -0
  35. data/test/test_default_commands/test_context.rb +61 -0
  36. data/test/test_default_commands/test_documentation.rb +163 -43
  37. data/test/test_default_commands/test_find_method.rb +42 -0
  38. data/test/test_default_commands/test_input.rb +32 -0
  39. data/test/test_default_commands/test_introspection.rb +50 -197
  40. data/test/test_default_commands/test_ls.rb +22 -0
  41. data/test/test_default_commands/test_show_source.rb +306 -0
  42. data/test/test_pry.rb +3 -3
  43. data/test/test_pry_defaults.rb +21 -0
  44. data/test/test_sticky_locals.rb +81 -1
  45. data/test/test_syntax_checking.rb +7 -6
  46. 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 Hash that defines Pry hooks used by default by all Pry
77
+ # Get/Set the `Pry::Hooks` instance that defines Pry hooks used by default by all Pry
40
78
  # instances.
41
- # @return [Hash] The hooks used by default by all Pry instances.
79
+ # @return [Pry::Hooks] The hooks used by default by all Pry instances.
42
80
  # @example
43
- # Pry.hooks :before_session => proc { puts "hello" },
44
- # :after_session => proc { puts "goodbye" }
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
- # @return [Array<Proc>] The array of Procs to be used for the
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 nano if
73
- # $EDITOR is not defined.
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 `line` are passed in as parameters and the
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
 
@@ -1,23 +1,29 @@
1
1
  class Object
2
- # Start a Pry REPL.
3
- # This method differs from `Pry.start` in that it does not
4
- # support an options hash. Also, when no parameter is provided, the Pry
5
- # session will start on the implied receiver rather than on
6
- # top-level (as in the case of `Pry.start`).
7
- # It has two forms of invocation. In the first form no parameter
8
- # should be provided and it will start a pry session on the
9
- # receiver. In the second form it should be invoked without an
10
- # explicit receiver and one parameter; this will start a Pry
11
- # session on the parameter.
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 form
16
- # pry "dummy"
17
- # @example Start a Pry session on current self (whatever that is)
18
- # pry
19
- def pry(target=self)
20
- Pry.start(target)
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
- command "whereami", "Show the code context for the session. (whereami <n> shows <n> extra lines of code around the invocation line. Default: 5)" do |num|
12
- file, line_num = file_and_line_from_binding(target)
13
- i_num = num ? num.to_i : 5
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
- if file != Pry.eval_path && (file =~ /(\(.*\))|<.*>/ || file == "" || file == "-e")
16
- raise CommandError, "Cannot find local context. Did you use binding.pry?"
19
+ def setup
20
+ @method = Pry::Method.from_binding(target)
17
21
  end
18
22
 
19
- set_file_and_dir_locals(file)
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
- method = Pry::Method.from_binding(target)
22
- method_description = method ? " in #{method.name_with_owner}" : ""
23
- output.puts "\n#{text.bold('From:')} #{file} @ line #{line_num}#{method_description}:\n\n"
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
- code = Pry::Code.from_file(file).around(line_num, i_num)
26
- output.puts code.with_line_numbers.with_marker(line_num)
27
- output.puts
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
@@ -3,6 +3,10 @@ class Pry
3
3
 
4
4
  EasterEggs = Pry::CommandSet.new do
5
5
 
6
+ command "nyan-cat", "", :requires_gem => ["nyancat"] do
7
+ run ".nyancat"
8
+ end
9
+
6
10
  command(/!s\/(.*?)\/(.*?)/, "") do |source, dest|
7
11
  eval_string.gsub!(/#{source}/) { dest }
8
12
  run "show-input"
@@ -88,8 +88,9 @@ class Pry
88
88
  temp_file do |f|
89
89
  f.puts(content)
90
90
  f.flush
91
- invoke_editor(f.path, line)
92
- if !opts.present?(:'no-reload') && !Pry.config.disable_auto_reload
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
- invoke_editor(file_name, line)
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 opts.present?(:reload) || ((opts.present?(:ex) || file_name.end_with?(".rb")) && !opts.present?(:'no-reload')) && !Pry.config.disable_auto_reload
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
- if ((original_name = @method.original_name) &&
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
- invoke_editor(file, opts["no-jump"] ? 0 : line)
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 unless opts.present?(:'no-reload') || Pry.config.disable_auto_reload
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 _pry_.complete_expression?(eval_string)
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