pry 0.9.8.4-i386-mswin32 → 0.9.9-i386-mswin32

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/pry_class.rb CHANGED
@@ -46,11 +46,14 @@ class Pry
46
46
  # @return [Fixnum] The number of active Pry sessions.
47
47
  attr_accessor :active_sessions
48
48
 
49
+ # @return [Boolean] Whether Pry sessions are quiet by default.
50
+ attr_accessor :quiet
51
+
49
52
  # plugin forwardables
50
53
  def_delegators :@plugin_manager, :plugins, :load_plugins, :locate_plugins
51
54
 
52
55
  delegate_accessors :@config, :input, :output, :commands, :prompt, :print, :exception_handler,
53
- :hooks, :color, :pager, :editor, :memory_size, :input_stack
56
+ :hooks, :color, :pager, :editor, :memory_size, :input_stack, :extra_sticky_locals
54
57
  end
55
58
 
56
59
  # Load the rc files given in the `Pry::RC_FILES` array.
@@ -261,6 +264,8 @@ class Pry
261
264
 
262
265
  config.memory_size = 100
263
266
 
267
+ config.extra_sticky_locals = {}
268
+
264
269
  config.ls ||= OpenStruct.new({
265
270
  :heading_color => :default,
266
271
 
@@ -279,9 +284,10 @@ class Pry
279
284
  :builtin_global_color => :cyan, # e.g. $stdin, $-w, $PID
280
285
  :pseudo_global_color => :cyan, # e.g. $~, $1..$9, $LAST_MATCH_INFO
281
286
 
282
- :constant_color => :default, # e.g. VERSION, ARGF
287
+ :constant_color => :default, # e.g. VERSION, ARGF
283
288
  :class_constant_color => :blue, # e.g. Object, Kernel
284
289
  :exception_constant_color => :magenta, # e.g. Exception, RuntimeError
290
+ :unloaded_constant_color => :yellow, # Any constant that is still in .autoload? state
285
291
 
286
292
  # What should separate items listed by ls? (TODO: we should allow a columnar layout)
287
293
  :separator => " ",
@@ -345,7 +351,7 @@ class Pry
345
351
  # @param [Object] target The object to get a `Binding` object for.
346
352
  # @return [Binding] The `Binding` object.
347
353
  def self.binding_for(target)
348
- if target.is_a?(Binding)
354
+ if Binding === target
349
355
  target
350
356
  else
351
357
  if TOPLEVEL_BINDING.eval('self') == target
@@ -8,6 +8,8 @@ class Pry
8
8
  attr_accessor :print
9
9
  attr_accessor :exception_handler
10
10
  attr_accessor :input_stack
11
+ attr_accessor :quiet
12
+ alias :quiet? :quiet
11
13
 
12
14
  attr_accessor :custom_completions
13
15
 
@@ -24,6 +26,8 @@ class Pry
24
26
 
25
27
  attr_accessor :backtrace
26
28
 
29
+ attr_accessor :extra_sticky_locals
30
+
27
31
  # Special treatment for hooks as we want to alert people of the
28
32
  # changed API
29
33
  attr_reader :hooks
@@ -48,6 +52,7 @@ class Pry
48
52
  # @option options [Hash] :hooks The defined hook Procs
49
53
  # @option options [Array<Proc>] :prompt The array of Procs to use for the prompts.
50
54
  # @option options [Proc] :print The Proc to use for the 'print'
55
+ # @option options [Boolean] :quiet If true, omit the whereami banner when starting.
51
56
  # component of the REPL. (see print.rb)
52
57
  def initialize(options={})
53
58
  refresh(options)
@@ -63,9 +68,9 @@ class Pry
63
68
  def refresh(options={})
64
69
  defaults = {}
65
70
  attributes = [
66
- :input, :output, :commands, :print,
71
+ :input, :output, :commands, :print, :quiet,
67
72
  :exception_handler, :hooks, :custom_completions,
68
- :prompt, :memory_size, :input_stack
73
+ :prompt, :memory_size, :input_stack, :extra_sticky_locals
69
74
  ]
70
75
 
71
76
  attributes.each do |attribute|
@@ -155,7 +160,7 @@ class Pry
155
160
  :_file_ => proc { last_file },
156
161
  :_dir_ => proc { last_dir },
157
162
  :_ => proc { last_result }
158
- }
163
+ }.merge(extra_sticky_locals)
159
164
  end
160
165
 
161
166
  # Initialize the repl session.
@@ -195,13 +200,19 @@ class Pry
195
200
 
196
201
  repl_prologue(target)
197
202
 
198
- break_data = catch(:breakout) do
199
- loop do
200
- rep(binding_stack.last)
203
+ break_data = nil
204
+ exception = catch(:raise_up) do
205
+ break_data = catch(:breakout) do
206
+ loop do
207
+ rep(binding_stack.last)
208
+ end
201
209
  end
210
+ exception = false
202
211
  end
203
212
 
204
- break_data || nil
213
+ raise exception if exception
214
+
215
+ break_data
205
216
  ensure
206
217
  repl_epilogue(target)
207
218
  end
@@ -229,17 +240,6 @@ class Pry
229
240
  def re(target=TOPLEVEL_BINDING)
230
241
  target = Pry.binding_for(target)
231
242
 
232
- compl = Pry::InputCompleter.build_completion_proc(target,
233
- instance_eval(&custom_completions))
234
-
235
- if defined? Coolline and input.is_a? Coolline
236
- input.completion_proc = proc do |cool|
237
- compl.call cool.completed_word
238
- end
239
- elsif input.respond_to? :completion_proc=
240
- input.completion_proc = compl
241
- end
242
-
243
243
  # It's not actually redundant to inject them continually as we may have
244
244
  # moved into the scope of a new Binding (e.g the user typed `cd`)
245
245
  inject_sticky_locals(target)
@@ -282,7 +282,7 @@ class Pry
282
282
  end
283
283
 
284
284
  begin
285
- break if complete_expression?(eval_string)
285
+ break if Pry::Code.complete_expression?(eval_string)
286
286
  rescue SyntaxError => e
287
287
  output.puts "SyntaxError: #{e.message.sub(/.*syntax error, */m, '')}"
288
288
  eval_string = ""
@@ -334,9 +334,23 @@ class Pry
334
334
  @indent.reset if eval_string.empty?
335
335
 
336
336
  current_prompt = select_prompt(eval_string, target)
337
+ completion_proc = Pry::InputCompleter.build_completion_proc(target,
338
+ instance_eval(&custom_completions))
339
+
340
+
337
341
  indentation = Pry.config.auto_indent ? @indent.indent_level : ''
338
342
 
339
- val = readline("#{current_prompt}#{indentation}")
343
+ begin
344
+ val = readline("#{current_prompt}#{indentation}", completion_proc)
345
+
346
+ # Handle <Ctrl+C> like Bash, empty the current input buffer but do not quit.
347
+ # This is only for ruby-1.9; other versions of ruby do not let you send Interrupt
348
+ # from within Readline.
349
+ rescue Interrupt => e
350
+ output.puts ""
351
+ eval_string.replace("")
352
+ return
353
+ end
340
354
 
341
355
  # invoke handler if we receive EOF character (^D)
342
356
  if !val
@@ -356,8 +370,8 @@ class Pry
356
370
  original_val = "#{indentation}#{val}"
357
371
  indented_val = @indent.indent(val)
358
372
 
359
- if original_val != indented_val && output.tty? && Pry::Helpers::BaseHelpers.use_ansi_codes? && Pry.config.correct_indent
360
- output.print @indent.correct_indentation(current_prompt + indented_val, original_val.length - indented_val.length)
373
+ if output.tty? && Pry::Helpers::BaseHelpers.use_ansi_codes? && Pry.config.correct_indent
374
+ output.print @indent.correct_indentation(current_prompt, indented_val, original_val.length - indented_val.length)
361
375
  output.flush
362
376
  end
363
377
  else
@@ -514,17 +528,42 @@ class Pry
514
528
  self.input = input_stack.pop
515
529
  end
516
530
  retry
531
+
532
+ # Interrupts are handled in r() because they need to tweak eval_string
533
+ # TODO: Refactor this baby.
534
+ rescue Interrupt
535
+ raise
536
+
537
+ # If we get a random error when trying to read a line we don't want to automatically
538
+ # retry, as the user will see a lot of error messages scroll past and be unable to do
539
+ # anything about it.
540
+ rescue RescuableException => e
541
+ puts "Error: #{e.message}"
542
+ puts "FATAL: Pry failed to get user input using `#{input}`."
543
+ puts "To fix this you may be able to pass input and output file descriptors to pry directly. e.g."
544
+ puts " Pry.config.input = STDIN"
545
+ puts " Pry.config.output = STDOUT"
546
+ puts " binding.pry"
547
+ throw(:breakout)
517
548
  end
518
549
  end
519
-
520
550
  private :handle_read_errors
521
551
 
522
552
  # Returns the next line of input to be used by the pry instance.
523
553
  # This method should not need to be invoked directly.
524
554
  # @param [String] current_prompt The prompt to use for input.
525
555
  # @return [String] The next line of input.
526
- def readline(current_prompt="> ")
556
+ def readline(current_prompt="> ", completion_proc=nil)
527
557
  handle_read_errors do
558
+
559
+ if defined? Coolline and input.is_a? Coolline
560
+ input.completion_proc = proc do |cool|
561
+ completion_proc.call cool.completed_word
562
+ end
563
+ elsif input.respond_to? :completion_proc=
564
+ input.completion_proc = completion_proc
565
+ end
566
+
528
567
  if input == Readline
529
568
  input.readline(current_prompt, false) # false since we'll add it manually
530
569
  elsif defined? Coolline and input.is_a? Coolline
@@ -598,50 +637,45 @@ class Pry
598
637
  prompt_stack.size > 1 ? prompt_stack.pop : prompt
599
638
  end
600
639
 
601
- # Determine if a string of code is a complete Ruby expression.
602
- # @param [String] code The code to validate.
603
- # @return [Boolean] Whether or not the code is a complete Ruby expression.
604
- # @raise [SyntaxError] Any SyntaxError that does not represent incompleteness.
605
- # @example
606
- # complete_expression?("class Hello") #=> false
607
- # complete_expression?("class Hello; end") #=> true
608
- def complete_expression?(str)
609
- if defined?(Rubinius::Melbourne19) && RUBY_VERSION =~ /^1\.9/
610
- Rubinius::Melbourne19.parse_string(str, Pry.eval_path)
611
- elsif defined?(Rubinius::Melbourne)
612
- Rubinius::Melbourne.parse_string(str, Pry.eval_path)
613
- else
614
- catch(:valid) do
615
- Helpers::BaseHelpers.silence_warnings do
616
- eval("BEGIN{throw :valid}\n#{str}", binding, Pry.eval_path)
617
- end
618
- end
619
- end
620
-
621
- # Assert that a line which ends with a , is incomplete.
622
- str !~ /[,]\z/
623
- rescue SyntaxError => e
624
- if incomplete_user_input_exception?(e)
625
- false
626
- else
627
- raise e
628
- end
629
- end
630
-
631
- # Check whether the exception indicates that the user should input more.
640
+ # Raise an exception out of Pry.
632
641
  #
633
- # @param [SyntaxError] the exception object that was raised.
634
- # @param [Array<String>] The stack frame of the function that executed eval.
635
- # @return [Boolean]
642
+ # See Kernel#raise for documentation of parameters.
643
+ # See rb_make_exception for the inbuilt implementation.
636
644
  #
637
- def incomplete_user_input_exception?(ex)
638
- case ex.message
639
- when /unexpected (\$end|end-of-file|END_OF_FILE)/, # mri, jruby, ironruby
640
- /unterminated (quoted string|string|regexp) meets end of file/, # "quoted string" is ironruby
641
- /missing 'end' for/, /: expecting '[})\]]'$/, /can't find string ".*" anywhere before EOF/, /expecting keyword_end/ # rbx
642
- true
645
+ # This is necessary so that the raise-up command can tell the
646
+ # difference between an exception the user has decided to raise,
647
+ # and a mistake in specifying that exception.
648
+ #
649
+ # (i.e. raise-up RunThymeError.new should not be the same as
650
+ # raise-up NameError, "unititialized constant RunThymeError")
651
+ #
652
+ def raise_up_common(force, *args)
653
+ exception = if args == []
654
+ last_exception || RuntimeError.new
655
+ elsif args.length == 1 && args.first.is_a?(String)
656
+ RuntimeError.new(args.first)
657
+ elsif args.length > 3
658
+ raise ArgumentError, "wrong number of arguments"
659
+ elsif !args.first.respond_to?(:exception)
660
+ raise TypeError, "exception class/object expected"
661
+ elsif args.length === 1
662
+ args.first.exception
663
+ else
664
+ args.first.exception(args[1])
665
+ end
666
+
667
+ raise TypeError, "exception object expected" unless exception.is_a? Exception
668
+
669
+ exception.set_backtrace(args.length === 3 ? args[2] : caller(1))
670
+
671
+ if force || binding_stack.one?
672
+ binding_stack.clear
673
+ throw :raise_up, exception
643
674
  else
644
- false
675
+ binding_stack.pop
676
+ raise exception
645
677
  end
646
678
  end
679
+ def raise_up(*args); raise_up_common(false, *args); end
680
+ def raise_up!(*args); raise_up_common(true, *args); end
647
681
  end
@@ -1,20 +1,13 @@
1
1
  class Pry
2
2
  module RbxMethod
3
3
  private
4
- def core?
5
- source_file and RbxPath.is_core_path?(source_file)
6
- end
7
4
 
8
5
  def core_code
9
- MethodSource.source_helper(core_path_line)
6
+ MethodSource.source_helper(source_location)
10
7
  end
11
8
 
12
9
  def core_doc
13
- MethodSource.comment_helper(core_path_line)
14
- end
15
-
16
- def core_path_line
17
- [RbxPath.convert_path_to_full(source_file), source_line]
10
+ MethodSource.comment_helper(source_location)
18
11
  end
19
12
  end
20
13
  end
data/lib/pry/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Pry
2
- VERSION = "0.9.8.4"
2
+ VERSION = "0.9.9"
3
3
  end
@@ -1,15 +1,55 @@
1
+ require 'pry/helpers/documentation_helpers'
2
+
1
3
  class Pry
4
+ class << self
5
+ # If the given object is a `Pry::WrappedModule`, return it unaltered. If it's
6
+ # anything else, return it wrapped in a `Pry::WrappedModule` instance.
7
+ def WrappedModule(obj)
8
+ if obj.is_a? Pry::WrappedModule
9
+ obj
10
+ else
11
+ Pry::WrappedModule.new(obj)
12
+ end
13
+ end
14
+ end
15
+
2
16
  class WrappedModule
17
+ include Helpers::DocumentationHelpers
3
18
 
4
19
  attr_reader :wrapped
5
20
  private :wrapped
6
21
 
22
+ # Convert a string to a module.
23
+ #
24
+ # @param [String] mod_name
25
+ # @param [Binding] target The binding where the lookup takes place.
26
+ # @return [Module, nil] The module or `nil` (if conversion failed).
27
+ # @example
28
+ # Pry::WrappedModule.from_str("Pry::Code")
29
+ def self.from_str(mod_name, target=TOPLEVEL_BINDING)
30
+ kind = target.eval("defined?(#{mod_name})")
31
+
32
+ # if we dont limit it to constants then from_str could end up
33
+ # executing methods which is not good, i.e `show-source pry`
34
+ if (kind == "constant" && target.eval(mod_name).is_a?(Module))
35
+ Pry::WrappedModule.new(target.eval(mod_name))
36
+ else
37
+ nil
38
+ end
39
+ rescue RescuableException
40
+ nil
41
+ end
42
+
7
43
  # Create a new WrappedModule
8
44
  # @raise ArgumentError, if the argument is not a Module
9
45
  # @param [Module]
10
46
  def initialize(mod)
11
47
  raise ArgumentError, "Tried to initialize a WrappedModule with a non-module #{mod.inspect}" unless ::Module === mod
12
48
  @wrapped = mod
49
+ @host_file_lines = nil
50
+ @source = nil
51
+ @source_location = nil
52
+ @doc = nil
13
53
  end
14
54
 
15
55
  # The prefix that would appear before methods defined on this class.
@@ -67,7 +107,202 @@ class Pry
67
107
  end
68
108
 
69
109
  def respond_to?(method_name)
70
- super || wrapped.send(method_name, *args, &block)
110
+ super || wrapped.respond_to?(method_name)
111
+ end
112
+
113
+ def yard_docs?
114
+ !!(defined?(YARD) && YARD::Registry.at(name))
115
+ end
116
+
117
+ def process_doc(doc)
118
+ process_comment_markup(strip_leading_hash_and_whitespace_from_ruby_comments(doc),
119
+ :ruby)
120
+ end
121
+
122
+ def doc
123
+ return @doc if @doc
124
+
125
+ file_name, line = source_location
126
+
127
+ if yard_docs?
128
+ from_yard = YARD::Registry.at(name)
129
+ @doc = from_yard.docstring
130
+ elsif source_location.nil?
131
+ raise CommandError, "Can't find module's source location"
132
+ else
133
+ @doc = extract_doc_for_candidate(0)
134
+ end
135
+
136
+ raise CommandError, "Can't find docs for module: #{name}." if !@doc
137
+
138
+ @doc = process_doc(@doc)
139
+ end
140
+
141
+ def doc_for_candidate(idx)
142
+ doc = extract_doc_for_candidate(idx)
143
+ raise CommandError, "Can't find docs for module: #{name}." if !doc
144
+
145
+ process_doc(doc)
146
+ end
147
+
148
+ # Retrieve the source for the module.
149
+ def source
150
+ @source ||= source_for_candidate(0)
71
151
  end
152
+
153
+ def source_for_candidate(idx)
154
+ file, line = module_source_location_for_candidate(idx)
155
+ raise CommandError, "Could not locate source for #{wrapped}!" if file.nil?
156
+
157
+ strip_leading_whitespace(Pry::Code.retrieve_complete_expression_from(lines_for_file(file)[(line - 1)..-1]))
158
+ end
159
+
160
+ def source_file
161
+ if yard_docs?
162
+ from_yard = YARD::Registry.at(name)
163
+ from_yard.file
164
+ else
165
+ source_file_for_candidate(0)
166
+ end
167
+ end
168
+
169
+ def source_line
170
+ source_line_for_candidate(0)
171
+ end
172
+
173
+ def source_file_for_candidate(idx)
174
+ Array(module_source_location_for_candidate(idx)).first
175
+ end
176
+
177
+ def source_line_for_candidate(idx)
178
+ Array(module_source_location_for_candidate(idx)).last
179
+ end
180
+
181
+ # Retrieve the source location of a module. Return value is in same
182
+ # format as Method#source_location. If the source location
183
+ # cannot be found this method returns `nil`.
184
+ #
185
+ # @param [Module] mod The module (or class).
186
+ # @return [Array<String, Fixnum>] The source location of the
187
+ # module (or class).
188
+ def source_location
189
+ @source_location ||= module_source_location_for_candidate(0)
190
+ rescue Pry::RescuableException
191
+ nil
192
+ end
193
+
194
+ # memoized lines for file
195
+ def lines_for_file(file)
196
+ @lines_for_file ||= {}
197
+
198
+ if file == Pry.eval_path
199
+ @lines_for_file[file] ||= Pry.line_buffer.drop(1)
200
+ else
201
+ @lines_for_file[file] ||= File.readlines(file)
202
+ end
203
+ end
204
+
205
+ def module_source_location_for_candidate(idx)
206
+ mod_type_string = wrapped.class.to_s.downcase
207
+ file, line = method_source_location_for_candidate(idx)
208
+
209
+ return nil if !file.is_a?(String)
210
+
211
+ class_regex1 = /#{mod_type_string}\s*(\w*)(::)?#{wrapped.name.split(/::/).last}/
212
+ class_regex2 = /(::)?#{wrapped.name.split(/::/).last}\s*?=\s*?#{wrapped.class}/
213
+
214
+ host_file_lines = lines_for_file(file)
215
+
216
+ search_lines = host_file_lines[0..(line - 2)]
217
+ idx = search_lines.rindex { |v| class_regex1 =~ v || class_regex2 =~ v }
218
+
219
+ source_location = [file, idx + 1]
220
+ rescue Pry::RescuableException
221
+ nil
222
+ end
223
+
224
+ def extract_doc
225
+ extract_doc_for_candidate(0)
226
+ end
227
+
228
+ def extract_doc_for_candidate(idx)
229
+ file_name, line = module_source_location_for_candidate(idx)
230
+
231
+ buffer = ""
232
+ lines_for_file(source_file_for_candidate(idx))[0..(line - 2)].each do |line|
233
+ # Add any line that is a valid ruby comment,
234
+ # but clear as soon as we hit a non comment line.
235
+ if (line =~ /^\s*#/) || (line =~ /^\s*$/)
236
+ buffer << line.lstrip
237
+ else
238
+ buffer.replace("")
239
+ end
240
+ end
241
+
242
+ buffer
243
+ end
244
+
245
+ # FIXME: this method is also found in Pry::Method
246
+ def safe_send(obj, method, *args, &block)
247
+ (Module === obj ? Module : Object).instance_method(method).bind(obj).call(*args, &block)
248
+ end
249
+
250
+ # FIXME: a variant of this method is also found in Pry::Method
251
+ def all_from_common(mod, method_type)
252
+ %w(public protected private).map do |visibility|
253
+ safe_send(mod, :"#{visibility}_#{method_type}s", false).select do |method_name|
254
+ if method_type == :method
255
+ safe_send(mod, method_type, method_name).owner == class << mod; self; end
256
+ else
257
+ safe_send(mod, method_type, method_name).owner == mod
258
+ end
259
+ end.map do |method_name|
260
+ Pry::Method.new(safe_send(mod, method_type, method_name), :visibility => visibility.to_sym)
261
+ end
262
+ end.flatten
263
+ end
264
+
265
+ def all_methods_for(mod)
266
+ all_from_common(mod, :instance_method) + all_from_common(mod, :method)
267
+ end
268
+
269
+ def all_source_locations_by_popularity
270
+ return @all_source_locations_by_popularity if @all_source_locations_by_popularity
271
+
272
+ ims = all_methods_for(wrapped)
273
+
274
+ ims.reject! do |v|
275
+ begin
276
+ v.alias? || v.source_location.nil?
277
+ rescue Pry::RescuableException
278
+ true
279
+ end
280
+ end
281
+
282
+ @all_source_locations_by_popularity = ims.group_by { |v| Array(v.source_location).first }.
283
+ sort_by { |k, v| -v.size }
284
+ end
285
+
286
+ def method_candidates
287
+ @method_candidtates ||= all_source_locations_by_popularity.map do |group|
288
+ sorted_by_lowest_line_number = group.last.sort_by(&:source_line)
289
+ best_candidate_for_group = sorted_by_lowest_line_number.first
290
+ end
291
+ end
292
+
293
+ def number_of_candidates
294
+ method_candidates.count
295
+ end
296
+
297
+ def method_source_location_for_candidate(idx)
298
+ file, line = method_candidates[idx].source_location
299
+
300
+ if file && RbxPath.is_core_path?(file)
301
+ file = RbxPath.convert_path_to_full(file)
302
+ end
303
+
304
+ [file, line]
305
+ end
306
+
72
307
  end
73
308
  end