pry 0.10.0.pre2-universal-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 (131) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +702 -0
  3. data/LICENSE +25 -0
  4. data/README.md +406 -0
  5. data/bin/pry +16 -0
  6. data/lib/pry.rb +161 -0
  7. data/lib/pry/cli.rb +220 -0
  8. data/lib/pry/code.rb +346 -0
  9. data/lib/pry/code/code_file.rb +103 -0
  10. data/lib/pry/code/code_range.rb +71 -0
  11. data/lib/pry/code/loc.rb +92 -0
  12. data/lib/pry/code_object.rb +172 -0
  13. data/lib/pry/color_printer.rb +55 -0
  14. data/lib/pry/command.rb +692 -0
  15. data/lib/pry/command_set.rb +443 -0
  16. data/lib/pry/commands.rb +6 -0
  17. data/lib/pry/commands/amend_line.rb +99 -0
  18. data/lib/pry/commands/bang.rb +20 -0
  19. data/lib/pry/commands/bang_pry.rb +17 -0
  20. data/lib/pry/commands/cat.rb +62 -0
  21. data/lib/pry/commands/cat/abstract_formatter.rb +27 -0
  22. data/lib/pry/commands/cat/exception_formatter.rb +77 -0
  23. data/lib/pry/commands/cat/file_formatter.rb +67 -0
  24. data/lib/pry/commands/cat/input_expression_formatter.rb +43 -0
  25. data/lib/pry/commands/cd.rb +41 -0
  26. data/lib/pry/commands/change_inspector.rb +27 -0
  27. data/lib/pry/commands/change_prompt.rb +26 -0
  28. data/lib/pry/commands/code_collector.rb +165 -0
  29. data/lib/pry/commands/disable_pry.rb +27 -0
  30. data/lib/pry/commands/disabled_commands.rb +2 -0
  31. data/lib/pry/commands/easter_eggs.rb +112 -0
  32. data/lib/pry/commands/edit.rb +195 -0
  33. data/lib/pry/commands/edit/exception_patcher.rb +25 -0
  34. data/lib/pry/commands/edit/file_and_line_locator.rb +36 -0
  35. data/lib/pry/commands/exit.rb +42 -0
  36. data/lib/pry/commands/exit_all.rb +29 -0
  37. data/lib/pry/commands/exit_program.rb +23 -0
  38. data/lib/pry/commands/find_method.rb +193 -0
  39. data/lib/pry/commands/fix_indent.rb +19 -0
  40. data/lib/pry/commands/gem_cd.rb +26 -0
  41. data/lib/pry/commands/gem_install.rb +32 -0
  42. data/lib/pry/commands/gem_list.rb +33 -0
  43. data/lib/pry/commands/gem_open.rb +29 -0
  44. data/lib/pry/commands/gist.rb +101 -0
  45. data/lib/pry/commands/help.rb +164 -0
  46. data/lib/pry/commands/hist.rb +180 -0
  47. data/lib/pry/commands/import_set.rb +22 -0
  48. data/lib/pry/commands/install_command.rb +53 -0
  49. data/lib/pry/commands/jump_to.rb +29 -0
  50. data/lib/pry/commands/list_inspectors.rb +35 -0
  51. data/lib/pry/commands/list_prompts.rb +35 -0
  52. data/lib/pry/commands/ls.rb +114 -0
  53. data/lib/pry/commands/ls/constants.rb +47 -0
  54. data/lib/pry/commands/ls/formatter.rb +49 -0
  55. data/lib/pry/commands/ls/globals.rb +48 -0
  56. data/lib/pry/commands/ls/grep.rb +21 -0
  57. data/lib/pry/commands/ls/instance_vars.rb +39 -0
  58. data/lib/pry/commands/ls/interrogatable.rb +18 -0
  59. data/lib/pry/commands/ls/jruby_hacks.rb +49 -0
  60. data/lib/pry/commands/ls/local_names.rb +35 -0
  61. data/lib/pry/commands/ls/local_vars.rb +39 -0
  62. data/lib/pry/commands/ls/ls_entity.rb +70 -0
  63. data/lib/pry/commands/ls/methods.rb +57 -0
  64. data/lib/pry/commands/ls/methods_helper.rb +46 -0
  65. data/lib/pry/commands/ls/self_methods.rb +32 -0
  66. data/lib/pry/commands/nesting.rb +25 -0
  67. data/lib/pry/commands/play.rb +103 -0
  68. data/lib/pry/commands/pry_backtrace.rb +25 -0
  69. data/lib/pry/commands/pry_version.rb +17 -0
  70. data/lib/pry/commands/raise_up.rb +32 -0
  71. data/lib/pry/commands/reload_code.rb +62 -0
  72. data/lib/pry/commands/reset.rb +18 -0
  73. data/lib/pry/commands/ri.rb +60 -0
  74. data/lib/pry/commands/save_file.rb +61 -0
  75. data/lib/pry/commands/shell_command.rb +48 -0
  76. data/lib/pry/commands/shell_mode.rb +25 -0
  77. data/lib/pry/commands/show_doc.rb +83 -0
  78. data/lib/pry/commands/show_info.rb +195 -0
  79. data/lib/pry/commands/show_input.rb +17 -0
  80. data/lib/pry/commands/show_source.rb +50 -0
  81. data/lib/pry/commands/simple_prompt.rb +22 -0
  82. data/lib/pry/commands/stat.rb +40 -0
  83. data/lib/pry/commands/switch_to.rb +23 -0
  84. data/lib/pry/commands/toggle_color.rb +24 -0
  85. data/lib/pry/commands/watch_expression.rb +105 -0
  86. data/lib/pry/commands/watch_expression/expression.rb +38 -0
  87. data/lib/pry/commands/whereami.rb +190 -0
  88. data/lib/pry/commands/wtf.rb +57 -0
  89. data/lib/pry/config.rb +24 -0
  90. data/lib/pry/config/behavior.rb +139 -0
  91. data/lib/pry/config/convenience.rb +26 -0
  92. data/lib/pry/config/default.rb +165 -0
  93. data/lib/pry/core_extensions.rb +131 -0
  94. data/lib/pry/editor.rb +133 -0
  95. data/lib/pry/exceptions.rb +77 -0
  96. data/lib/pry/helpers.rb +5 -0
  97. data/lib/pry/helpers/base_helpers.rb +113 -0
  98. data/lib/pry/helpers/command_helpers.rb +156 -0
  99. data/lib/pry/helpers/documentation_helpers.rb +75 -0
  100. data/lib/pry/helpers/options_helpers.rb +27 -0
  101. data/lib/pry/helpers/table.rb +109 -0
  102. data/lib/pry/helpers/text.rb +107 -0
  103. data/lib/pry/history.rb +125 -0
  104. data/lib/pry/history_array.rb +121 -0
  105. data/lib/pry/hooks.rb +230 -0
  106. data/lib/pry/indent.rb +406 -0
  107. data/lib/pry/input_completer.rb +242 -0
  108. data/lib/pry/input_lock.rb +132 -0
  109. data/lib/pry/inspector.rb +27 -0
  110. data/lib/pry/last_exception.rb +61 -0
  111. data/lib/pry/method.rb +546 -0
  112. data/lib/pry/method/disowned.rb +53 -0
  113. data/lib/pry/method/patcher.rb +125 -0
  114. data/lib/pry/method/weird_method_locator.rb +186 -0
  115. data/lib/pry/module_candidate.rb +136 -0
  116. data/lib/pry/object_path.rb +82 -0
  117. data/lib/pry/output.rb +50 -0
  118. data/lib/pry/pager.rb +234 -0
  119. data/lib/pry/plugins.rb +103 -0
  120. data/lib/pry/prompt.rb +26 -0
  121. data/lib/pry/pry_class.rb +375 -0
  122. data/lib/pry/pry_instance.rb +654 -0
  123. data/lib/pry/rbx_path.rb +22 -0
  124. data/lib/pry/repl.rb +202 -0
  125. data/lib/pry/repl_file_loader.rb +74 -0
  126. data/lib/pry/rubygem.rb +82 -0
  127. data/lib/pry/terminal.rb +79 -0
  128. data/lib/pry/test/helper.rb +170 -0
  129. data/lib/pry/version.rb +3 -0
  130. data/lib/pry/wrapped_module.rb +373 -0
  131. metadata +248 -0
@@ -0,0 +1,170 @@
1
+ require 'pry'
2
+
3
+ # in case the tests call reset_defaults, ensure we reset them to
4
+ # amended (test friendly) values
5
+ class << Pry
6
+ alias_method :orig_reset_defaults, :reset_defaults
7
+ def reset_defaults
8
+ orig_reset_defaults
9
+
10
+ Pry.config.color = false
11
+ Pry.config.pager = false
12
+ Pry.config.should_load_rc = false
13
+ Pry.config.should_load_local_rc= false
14
+ Pry.config.should_load_plugins = false
15
+ Pry.config.history.should_load = false
16
+ Pry.config.history.should_save = false
17
+ Pry.config.correct_indent = false
18
+ Pry.config.hooks = Pry::Hooks.new
19
+ Pry.config.collision_warning = false
20
+ end
21
+ end
22
+ Pry.reset_defaults
23
+
24
+ # A global space for storing temporary state during tests.
25
+
26
+ module PryTestHelpers
27
+
28
+ module_function
29
+
30
+ # inject a variable into a binding
31
+ def inject_var(name, value, b)
32
+ Pry.current[:pry_local] = value
33
+ b.eval("#{name} = ::Pry.current[:pry_local]")
34
+ ensure
35
+ Pry.current[:pry_local] = nil
36
+ end
37
+
38
+ def constant_scope(*names)
39
+ names.each do |name|
40
+ Object.remove_const name if Object.const_defined?(name)
41
+ end
42
+
43
+ yield
44
+ ensure
45
+ names.each do |name|
46
+ Object.remove_const name if Object.const_defined?(name)
47
+ end
48
+ end
49
+
50
+ # Open a temp file and yield it to the block, closing it after
51
+ # @return [String] The path of the temp file
52
+ def temp_file(ext='.rb')
53
+ file = Tempfile.new(['pry', ext])
54
+ yield file
55
+ ensure
56
+ file.close(true) if file
57
+ File.unlink("#{file.path}c") if File.exists?("#{file.path}c") # rbx
58
+ end
59
+
60
+ def unindent(*args)
61
+ Pry::Helpers::CommandHelpers.unindent(*args)
62
+ end
63
+
64
+ def mock_command(cmd, args=[], opts={})
65
+ output = StringIO.new
66
+ pry = Pry.new(output: output)
67
+ ret = cmd.new(opts.merge(pry_instance: pry, :output => output)).call_safely(*args)
68
+ Struct.new(:output, :return).new(output.string, ret)
69
+ end
70
+
71
+ def mock_exception(*mock_backtrace)
72
+ StandardError.new.tap do |e|
73
+ e.define_singleton_method(:backtrace) { mock_backtrace }
74
+ end
75
+ end
76
+ end
77
+
78
+ def pry_tester(*args, &block)
79
+ if args.length == 0 || args[0].is_a?(Hash)
80
+ args.unshift(Pry.toplevel_binding)
81
+ end
82
+
83
+ PryTester.new(*args).tap do |t|
84
+ (class << t; self; end).class_eval(&block) if block
85
+ end
86
+ end
87
+
88
+ def pry_eval(*eval_strs)
89
+ if eval_strs.first.is_a? String
90
+ binding = Pry.toplevel_binding
91
+ else
92
+ binding = Pry.binding_for(eval_strs.shift)
93
+ end
94
+
95
+ pry_tester(binding).eval(*eval_strs)
96
+ end
97
+
98
+ class PryTester
99
+ extend Forwardable
100
+
101
+ attr_reader :pry, :out
102
+
103
+ def_delegators :@pry, :eval_string, :eval_string=
104
+
105
+ def initialize(target = TOPLEVEL_BINDING, options = {})
106
+ @pry = Pry.new(options.merge(:target => target))
107
+ @history = options[:history]
108
+
109
+ @pry.inject_sticky_locals!
110
+ reset_output
111
+ end
112
+
113
+ def eval(*strs)
114
+ reset_output
115
+ result = nil
116
+
117
+ strs.flatten.each do |str|
118
+ str = "#{str.strip}\n"
119
+ @history.push str if @history
120
+
121
+ if @pry.process_command(str)
122
+ result = last_command_result_or_output
123
+ else
124
+ result = @pry.evaluate_ruby(str)
125
+ end
126
+ end
127
+
128
+ result
129
+ end
130
+
131
+ def push(*lines)
132
+ Array(lines).flatten.each do |line|
133
+ @pry.eval(line)
134
+ end
135
+ end
136
+
137
+ def push_binding(context)
138
+ @pry.push_binding context
139
+ end
140
+
141
+ def last_output
142
+ @out.string if @out
143
+ end
144
+
145
+ def process_command(command_str)
146
+ @pry.process_command(command_str) or raise "Not a valid command"
147
+ last_command_result_or_output
148
+ end
149
+
150
+ def last_command_result
151
+ result = Pry.current[:pry_cmd_result]
152
+ result.retval if result
153
+ end
154
+
155
+ protected
156
+
157
+ def last_command_result_or_output
158
+ result = last_command_result
159
+ if result != Pry::Command::VOID_VALUE
160
+ result
161
+ else
162
+ last_output
163
+ end
164
+ end
165
+
166
+ def reset_output
167
+ @out = StringIO.new
168
+ @pry.output = @out
169
+ end
170
+ end
@@ -0,0 +1,3 @@
1
+ class Pry
2
+ VERSION = "0.10.0.pre2"
3
+ end
@@ -0,0 +1,373 @@
1
+ require 'pry/module_candidate'
2
+
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
+
16
+ class WrappedModule
17
+ include Helpers::BaseHelpers
18
+ include CodeObject::Helpers
19
+
20
+ attr_reader :wrapped
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
+ if safe_to_evaluate?(mod_name, target)
31
+ Pry::WrappedModule.new(target.eval(mod_name))
32
+ else
33
+ nil
34
+ end
35
+ rescue RescuableException
36
+ nil
37
+ end
38
+
39
+ class << self
40
+ private
41
+
42
+ # We use this method to decide whether code is safe to eval. Method's are
43
+ # generally not, but everything else is.
44
+ # TODO: is just checking != "method" enough??
45
+ # TODO: see duplication of this method in Pry::CodeObject
46
+ # @param [String] str The string to lookup.
47
+ # @param [Binding] target Where the lookup takes place.
48
+ # @return [Boolean]
49
+ def safe_to_evaluate?(str, target)
50
+ return true if str.strip == "self"
51
+ kind = target.eval("defined?(#{str})")
52
+ kind =~ /variable|constant/
53
+ end
54
+ end
55
+
56
+ # @raise [ArgumentError] if the argument is not a `Module`
57
+ # @param [Module] mod
58
+ def initialize(mod)
59
+ raise ArgumentError, "Tried to initialize a WrappedModule with a non-module #{mod.inspect}" unless ::Module === mod
60
+ @wrapped = mod
61
+ @memoized_candidates = []
62
+ @host_file_lines = nil
63
+ @source = nil
64
+ @source_location = nil
65
+ @doc = nil
66
+ end
67
+
68
+ # Returns an array of the names of the constants accessible in the wrapped
69
+ # module. This avoids the problem of accidentally calling the singleton
70
+ # method `Module.constants`.
71
+ # @param [Boolean] inherit Include the names of constants from included
72
+ # modules?
73
+ def constants(inherit = true)
74
+ Module.instance_method(:constants).bind(@wrapped).call(inherit)
75
+ end
76
+
77
+ # The prefix that would appear before methods defined on this class.
78
+ #
79
+ # i.e. the "String." or "String#" in String.new and String#initialize.
80
+ #
81
+ # @return String
82
+ def method_prefix
83
+ if singleton_class?
84
+ if Module === singleton_instance
85
+ "#{WrappedModule.new(singleton_instance).nonblank_name}."
86
+ else
87
+ "self."
88
+ end
89
+ else
90
+ "#{nonblank_name}#"
91
+ end
92
+ end
93
+
94
+ # The name of the Module if it has one, otherwise #<Class:0xf00>.
95
+ #
96
+ # @return [String]
97
+ def nonblank_name
98
+ if name.to_s == ""
99
+ wrapped.inspect
100
+ else
101
+ name
102
+ end
103
+ end
104
+
105
+ # Is this a singleton class?
106
+ # @return [Boolean]
107
+ def singleton_class?
108
+ if Pry::Method.safe_send(wrapped, :respond_to?, :singleton_class?)
109
+ Pry::Method.safe_send(wrapped, :singleton_class?)
110
+ else
111
+ wrapped != Pry::Method.safe_send(wrapped, :ancestors).first
112
+ end
113
+ end
114
+
115
+ # Is this strictly a module? (does not match classes)
116
+ # @return [Boolean]
117
+ def module?
118
+ wrapped.instance_of?(Module)
119
+ end
120
+
121
+ # Is this strictly a class?
122
+ # @return [Boolean]
123
+ def class?
124
+ wrapped.instance_of?(Class)
125
+ end
126
+
127
+ # Get the instance associated with this singleton class.
128
+ #
129
+ # @raise ArgumentError: tried to get instance of non singleton class
130
+ #
131
+ # @return [Object]
132
+ def singleton_instance
133
+ raise ArgumentError, "tried to get instance of non singleton class" unless singleton_class?
134
+
135
+ if Helpers::BaseHelpers.jruby?
136
+ wrapped.to_java.attached
137
+ else
138
+ @singleton_instance ||= ObjectSpace.each_object(wrapped).detect{ |x| (class << x; self; end) == wrapped }
139
+ end
140
+ end
141
+
142
+ # Forward method invocations to the wrapped module
143
+ def method_missing(method_name, *args, &block)
144
+ wrapped.send(method_name, *args, &block)
145
+ end
146
+
147
+ def respond_to?(method_name)
148
+ super || wrapped.respond_to?(method_name)
149
+ end
150
+
151
+ # Retrieve the source location of a module. Return value is in same
152
+ # format as Method#source_location. If the source location
153
+ # cannot be found this method returns `nil`.
154
+ #
155
+ # @param [Module] mod The module (or class).
156
+ # @return [Array<String, Fixnum>, nil] The source location of the
157
+ # module (or class), or `nil` if no source location found.
158
+ def source_location
159
+ @source_location ||= primary_candidate.source_location
160
+ rescue Pry::RescuableException
161
+ nil
162
+ end
163
+
164
+ # @return [String, nil] The associated file for the module (i.e
165
+ # the primary candidate: highest ranked monkeypatch).
166
+ def file
167
+ Array(source_location).first
168
+ end
169
+ alias_method :source_file, :file
170
+
171
+ # @return [Fixnum, nil] The associated line for the module (i.e
172
+ # the primary candidate: highest ranked monkeypatch).
173
+ def line
174
+ Array(source_location).last
175
+ end
176
+ alias_method :source_line, :line
177
+
178
+ # Returns documentation for the module.
179
+ # This documentation is for the primary candidate, if
180
+ # you would like documentation for other candidates use
181
+ # `WrappedModule#candidate` to select the candidate you're
182
+ # interested in.
183
+ # @raise [Pry::CommandError] If documentation cannot be found.
184
+ # @return [String] The documentation for the module.
185
+ def doc
186
+ @doc ||= primary_candidate.doc
187
+ end
188
+
189
+ # Returns the source for the module.
190
+ # This source is for the primary candidate, if
191
+ # you would like source for other candidates use
192
+ # `WrappedModule#candidate` to select the candidate you're
193
+ # interested in.
194
+ # @raise [Pry::CommandError] If source cannot be found.
195
+ # @return [String] The source for the module.
196
+ def source
197
+ @source ||= primary_candidate.source
198
+ end
199
+
200
+ # @return [String] Return the associated file for the
201
+ # module from YARD, if one exists.
202
+ def yard_file
203
+ YARD::Registry.at(name).file if yard_docs?
204
+ end
205
+
206
+ # @return [Fixnum] Return the associated line for the
207
+ # module from YARD, if one exists.
208
+ def yard_line
209
+ YARD::Registry.at(name).line if yard_docs?
210
+ end
211
+
212
+ # @return [String] Return the YARD docs for this module.
213
+ def yard_doc
214
+ YARD::Registry.at(name).docstring.to_s if yard_docs?
215
+ end
216
+
217
+ # Return a candidate for this module of specified rank. A `rank`
218
+ # of 0 is equivalent to the 'primary candidate', which is the
219
+ # module definition with the highest number of methods. A `rank`
220
+ # of 1 is the module definition with the second highest number of
221
+ # methods, and so on. Module candidates are necessary as modules
222
+ # can be reopened multiple times and in multiple places in Ruby,
223
+ # the candidate API gives you access to the module definition
224
+ # representing each of those reopenings.
225
+ # @raise [Pry::CommandError] If the `rank` is out of range. That
226
+ # is greater than `number_of_candidates - 1`.
227
+ # @param [Fixnum] rank
228
+ # @return [Pry::WrappedModule::Candidate]
229
+ def candidate(rank)
230
+ @memoized_candidates[rank] ||= Candidate.new(self, rank)
231
+ end
232
+
233
+ # @return [Fixnum] The number of candidate definitions for the
234
+ # current module.
235
+ def number_of_candidates
236
+ method_candidates.count
237
+ end
238
+
239
+ # @note On JRuby 1.9 and higher, in certain conditions, this method chucks
240
+ # away its ability to be quick (when there are lots of monkey patches,
241
+ # like in Rails). However, it should be efficient enough on other rubies.
242
+ # @see https://github.com/jruby/jruby/issues/525
243
+ # @return [Enumerator, Array] on JRuby 1.9 and higher returns Array, on
244
+ # other rubies returns Enumerator
245
+ def candidates
246
+ enum = Enumerator.new do |y|
247
+ (0...number_of_candidates).each do |num|
248
+ y.yield candidate(num)
249
+ end
250
+ end
251
+ Pry::Helpers::BaseHelpers.jruby_19? ? enum.to_a : enum
252
+ end
253
+
254
+ # @return [Boolean] Whether YARD docs are available for this module.
255
+ def yard_docs?
256
+ !!(defined?(YARD) && YARD::Registry.at(name))
257
+ end
258
+
259
+ # @param [Fixnum] times How far to travel up the ancestor chain.
260
+ # @return [Pry::WrappedModule, nil] The wrapped module that is the
261
+ # superclass.
262
+ # When `self` is a `Module` then return the
263
+ # nth ancestor, otherwise (in the case of classes) return the
264
+ # nth ancestor that is a class.
265
+ def super(times=1)
266
+ return self if times.zero?
267
+
268
+ if wrapped.is_a?(Class)
269
+ sup = ancestors.select { |v| v.is_a?(Class) }[times]
270
+ else
271
+ sup = ancestors[times]
272
+ end
273
+
274
+ Pry::WrappedModule(sup) if sup
275
+ end
276
+
277
+ private
278
+
279
+ # @return [Pry::WrappedModule::Candidate] The candidate with the
280
+ # highest rank, that is the 'monkey patch' of this module with the
281
+ # highest number of methods, which contains a source code line that
282
+ # defines the module. It is considered the 'canonical' definition
283
+ # for the module. In the absense of a suitable candidate, the
284
+ # candidate of rank 0 will be returned, or a CommandError raised if
285
+ # there are no candidates at all.
286
+ def primary_candidate
287
+ @primary_candidate ||= candidates.find { |c| c.file } ||
288
+ # This will raise an exception if there is no candidate at all.
289
+ candidate(0)
290
+ end
291
+
292
+ # @return [Array<Array<Pry::Method>>] The array of `Pry::Method` objects,
293
+ # there are two associated with each candidate. The first is the 'base
294
+ # method' for a candidate and it serves as the start point for
295
+ # the search in uncovering the module definition. The second is
296
+ # the last method defined for that candidate and it is used to
297
+ # speed up source code extraction.
298
+ def method_candidates
299
+ @method_candidates ||= all_source_locations_by_popularity.map do |group|
300
+ methods_sorted_by_source_line = group.last.sort_by(&:source_line)
301
+ [methods_sorted_by_source_line.first, methods_sorted_by_source_line.last]
302
+ end
303
+ end
304
+
305
+ # A helper method.
306
+ def all_source_locations_by_popularity
307
+ return @all_source_locations_by_popularity if @all_source_locations_by_popularity
308
+
309
+ ims = all_relevant_methods_for(wrapped)
310
+ @all_source_locations_by_popularity = ims.group_by { |v| Array(v.source_location).first }.
311
+ sort_by do |path, methods|
312
+ expanded = File.expand_path(path)
313
+ load_order = $LOADED_FEATURES.index{ |file| expanded.end_with?(file) }
314
+
315
+ [-methods.size, load_order || (1.0 / 0.0)]
316
+ end
317
+ end
318
+
319
+ # We only want methods that have a non-nil `source_location`. We also
320
+ # skip some spooky internal methods.
321
+ # (i.e we skip `__class_init__` because it's an odd rbx specific thing that causes tests to fail.)
322
+ # @return [Array<Pry::Method>]
323
+ def all_relevant_methods_for(mod)
324
+ methods = all_methods_for(mod).select(&:source_location).
325
+ reject{ |x| x.name == '__class_init__' || method_defined_by_forwardable_module?(x) }
326
+
327
+ return methods unless methods.empty?
328
+
329
+ safe_send(mod, :constants).map do |const_name|
330
+ if const = nested_module?(mod, const_name)
331
+ all_relevant_methods_for(const)
332
+ else
333
+ []
334
+ end
335
+ end.flatten
336
+ end
337
+
338
+ # Return all methods (instance methods and class methods) for a
339
+ # given module.
340
+ # @return [Array<Pry::Method>]
341
+ def all_methods_for(mod)
342
+ Pry::Method.all_from_obj(mod, false) + Pry::Method.all_from_class(mod, false)
343
+ end
344
+
345
+ def nested_module?(parent, name)
346
+ return if safe_send(parent, :autoload?, name)
347
+ child = safe_send(parent, :const_get, name)
348
+ return unless Module === child
349
+ return unless safe_send(child, :name) == "#{safe_send(parent, :name)}::#{name}"
350
+ child
351
+ end
352
+
353
+ # Detect methods that are defined with `def_delegator` from the Forwardable
354
+ # module. We want to reject these methods as they screw up module
355
+ # extraction since the `source_location` for such methods points at forwardable.rb
356
+ # TODO: make this more robust as valid user-defined files called
357
+ # forwardable.rb are also skipped.
358
+ def method_defined_by_forwardable_module?(method)
359
+ method.source_location.first =~ /forwardable\.rb/
360
+ end
361
+
362
+ # memoized lines for file
363
+ def lines_for_file(file)
364
+ @lines_for_file ||= {}
365
+
366
+ if file == Pry.eval_path
367
+ @lines_for_file[file] ||= Pry.line_buffer.drop(1)
368
+ else
369
+ @lines_for_file[file] ||= File.readlines(file)
370
+ end
371
+ end
372
+ end
373
+ end