pry 0.10.pre.1-java → 0.10.0.pre2-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (214) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +702 -0
  3. data/LICENSE +2 -2
  4. data/{README.markdown → README.md} +41 -35
  5. data/lib/pry.rb +82 -139
  6. data/lib/pry/cli.rb +77 -30
  7. data/lib/pry/code.rb +126 -182
  8. data/lib/pry/code/code_file.rb +103 -0
  9. data/lib/pry/code/code_range.rb +71 -0
  10. data/lib/pry/code/loc.rb +92 -0
  11. data/lib/pry/code_object.rb +172 -0
  12. data/lib/pry/color_printer.rb +55 -0
  13. data/lib/pry/command.rb +184 -28
  14. data/lib/pry/command_set.rb +113 -59
  15. data/lib/pry/commands.rb +4 -27
  16. data/lib/pry/commands/amend_line.rb +99 -0
  17. data/lib/pry/commands/bang.rb +20 -0
  18. data/lib/pry/commands/bang_pry.rb +17 -0
  19. data/lib/pry/commands/cat.rb +62 -0
  20. data/lib/pry/commands/cat/abstract_formatter.rb +27 -0
  21. data/lib/pry/commands/cat/exception_formatter.rb +77 -0
  22. data/lib/pry/commands/cat/file_formatter.rb +67 -0
  23. data/lib/pry/commands/cat/input_expression_formatter.rb +43 -0
  24. data/lib/pry/commands/cd.rb +41 -0
  25. data/lib/pry/commands/change_inspector.rb +27 -0
  26. data/lib/pry/commands/change_prompt.rb +26 -0
  27. data/lib/pry/commands/code_collector.rb +165 -0
  28. data/lib/pry/commands/disable_pry.rb +27 -0
  29. data/lib/pry/commands/disabled_commands.rb +2 -0
  30. data/lib/pry/commands/easter_eggs.rb +112 -0
  31. data/lib/pry/commands/edit.rb +195 -0
  32. data/lib/pry/commands/edit/exception_patcher.rb +25 -0
  33. data/lib/pry/commands/edit/file_and_line_locator.rb +36 -0
  34. data/lib/pry/commands/exit.rb +42 -0
  35. data/lib/pry/commands/exit_all.rb +29 -0
  36. data/lib/pry/commands/exit_program.rb +23 -0
  37. data/lib/pry/commands/find_method.rb +193 -0
  38. data/lib/pry/commands/fix_indent.rb +19 -0
  39. data/lib/pry/commands/gem_cd.rb +26 -0
  40. data/lib/pry/commands/gem_install.rb +32 -0
  41. data/lib/pry/commands/gem_list.rb +33 -0
  42. data/lib/pry/commands/gem_open.rb +29 -0
  43. data/lib/pry/commands/gist.rb +101 -0
  44. data/lib/pry/commands/help.rb +164 -0
  45. data/lib/pry/commands/hist.rb +180 -0
  46. data/lib/pry/commands/import_set.rb +22 -0
  47. data/lib/pry/commands/install_command.rb +53 -0
  48. data/lib/pry/commands/jump_to.rb +29 -0
  49. data/lib/pry/commands/list_inspectors.rb +35 -0
  50. data/lib/pry/commands/list_prompts.rb +35 -0
  51. data/lib/pry/commands/ls.rb +114 -0
  52. data/lib/pry/commands/ls/constants.rb +47 -0
  53. data/lib/pry/commands/ls/formatter.rb +49 -0
  54. data/lib/pry/commands/ls/globals.rb +48 -0
  55. data/lib/pry/commands/ls/grep.rb +21 -0
  56. data/lib/pry/commands/ls/instance_vars.rb +39 -0
  57. data/lib/pry/commands/ls/interrogatable.rb +18 -0
  58. data/lib/pry/commands/ls/jruby_hacks.rb +49 -0
  59. data/lib/pry/commands/ls/local_names.rb +35 -0
  60. data/lib/pry/commands/ls/local_vars.rb +39 -0
  61. data/lib/pry/commands/ls/ls_entity.rb +70 -0
  62. data/lib/pry/commands/ls/methods.rb +57 -0
  63. data/lib/pry/commands/ls/methods_helper.rb +46 -0
  64. data/lib/pry/commands/ls/self_methods.rb +32 -0
  65. data/lib/pry/commands/nesting.rb +25 -0
  66. data/lib/pry/commands/play.rb +103 -0
  67. data/lib/pry/commands/pry_backtrace.rb +25 -0
  68. data/lib/pry/commands/pry_version.rb +17 -0
  69. data/lib/pry/commands/raise_up.rb +32 -0
  70. data/lib/pry/commands/reload_code.rb +62 -0
  71. data/lib/pry/commands/reset.rb +18 -0
  72. data/lib/pry/commands/ri.rb +60 -0
  73. data/lib/pry/commands/save_file.rb +61 -0
  74. data/lib/pry/commands/shell_command.rb +48 -0
  75. data/lib/pry/commands/shell_mode.rb +25 -0
  76. data/lib/pry/commands/show_doc.rb +83 -0
  77. data/lib/pry/commands/show_info.rb +195 -0
  78. data/lib/pry/commands/show_input.rb +17 -0
  79. data/lib/pry/commands/show_source.rb +50 -0
  80. data/lib/pry/commands/simple_prompt.rb +22 -0
  81. data/lib/pry/commands/stat.rb +40 -0
  82. data/lib/pry/commands/switch_to.rb +23 -0
  83. data/lib/pry/commands/toggle_color.rb +24 -0
  84. data/lib/pry/commands/watch_expression.rb +105 -0
  85. data/lib/pry/commands/watch_expression/expression.rb +38 -0
  86. data/lib/pry/commands/whereami.rb +190 -0
  87. data/lib/pry/commands/wtf.rb +57 -0
  88. data/lib/pry/config.rb +20 -229
  89. data/lib/pry/config/behavior.rb +139 -0
  90. data/lib/pry/config/convenience.rb +26 -0
  91. data/lib/pry/config/default.rb +165 -0
  92. data/lib/pry/core_extensions.rb +59 -38
  93. data/lib/pry/editor.rb +133 -0
  94. data/lib/pry/exceptions.rb +77 -0
  95. data/lib/pry/helpers.rb +1 -0
  96. data/lib/pry/helpers/base_helpers.rb +40 -154
  97. data/lib/pry/helpers/command_helpers.rb +19 -130
  98. data/lib/pry/helpers/documentation_helpers.rb +21 -11
  99. data/lib/pry/helpers/table.rb +109 -0
  100. data/lib/pry/helpers/text.rb +8 -9
  101. data/lib/pry/history.rb +61 -45
  102. data/lib/pry/history_array.rb +11 -1
  103. data/lib/pry/hooks.rb +10 -32
  104. data/lib/pry/indent.rb +110 -38
  105. data/lib/pry/input_completer.rb +242 -0
  106. data/lib/pry/input_lock.rb +132 -0
  107. data/lib/pry/inspector.rb +27 -0
  108. data/lib/pry/last_exception.rb +61 -0
  109. data/lib/pry/method.rb +199 -200
  110. data/lib/pry/method/disowned.rb +53 -0
  111. data/lib/pry/method/patcher.rb +125 -0
  112. data/lib/pry/method/weird_method_locator.rb +186 -0
  113. data/lib/pry/module_candidate.rb +39 -33
  114. data/lib/pry/object_path.rb +82 -0
  115. data/lib/pry/output.rb +50 -0
  116. data/lib/pry/pager.rb +234 -0
  117. data/lib/pry/plugins.rb +4 -3
  118. data/lib/pry/prompt.rb +26 -0
  119. data/lib/pry/pry_class.rb +199 -227
  120. data/lib/pry/pry_instance.rb +344 -403
  121. data/lib/pry/rbx_path.rb +1 -1
  122. data/lib/pry/repl.rb +202 -0
  123. data/lib/pry/repl_file_loader.rb +20 -26
  124. data/lib/pry/rubygem.rb +82 -0
  125. data/lib/pry/terminal.rb +79 -0
  126. data/lib/pry/test/helper.rb +170 -0
  127. data/lib/pry/version.rb +1 -1
  128. data/lib/pry/wrapped_module.rb +133 -48
  129. metadata +132 -197
  130. data/.document +0 -2
  131. data/.gemtest +0 -0
  132. data/.gitignore +0 -16
  133. data/.travis.yml +0 -17
  134. data/.yardopts +0 -1
  135. data/CHANGELOG +0 -387
  136. data/CONTRIBUTORS +0 -36
  137. data/Gemfile +0 -2
  138. data/Rakefile +0 -137
  139. data/TODO +0 -117
  140. data/examples/example_basic.rb +0 -15
  141. data/examples/example_command_override.rb +0 -32
  142. data/examples/example_commands.rb +0 -36
  143. data/examples/example_hooks.rb +0 -9
  144. data/examples/example_image_edit.rb +0 -67
  145. data/examples/example_input.rb +0 -7
  146. data/examples/example_input2.rb +0 -29
  147. data/examples/example_output.rb +0 -11
  148. data/examples/example_print.rb +0 -6
  149. data/examples/example_prompt.rb +0 -9
  150. data/examples/helper.rb +0 -6
  151. data/lib/pry/completion.rb +0 -221
  152. data/lib/pry/custom_completions.rb +0 -6
  153. data/lib/pry/default_commands/cd.rb +0 -81
  154. data/lib/pry/default_commands/commands.rb +0 -62
  155. data/lib/pry/default_commands/context.rb +0 -98
  156. data/lib/pry/default_commands/easter_eggs.rb +0 -95
  157. data/lib/pry/default_commands/editing.rb +0 -420
  158. data/lib/pry/default_commands/find_method.rb +0 -169
  159. data/lib/pry/default_commands/gems.rb +0 -84
  160. data/lib/pry/default_commands/gist.rb +0 -187
  161. data/lib/pry/default_commands/help.rb +0 -127
  162. data/lib/pry/default_commands/hist.rb +0 -120
  163. data/lib/pry/default_commands/input_and_output.rb +0 -306
  164. data/lib/pry/default_commands/introspection.rb +0 -410
  165. data/lib/pry/default_commands/ls.rb +0 -272
  166. data/lib/pry/default_commands/misc.rb +0 -38
  167. data/lib/pry/default_commands/navigating_pry.rb +0 -110
  168. data/lib/pry/default_commands/whereami.rb +0 -92
  169. data/lib/pry/extended_commands/experimental.rb +0 -7
  170. data/lib/pry/rbx_method.rb +0 -13
  171. data/man/pry.1 +0 -195
  172. data/man/pry.1.html +0 -204
  173. data/man/pry.1.ronn +0 -141
  174. data/pry.gemspec +0 -46
  175. data/test/candidate_helper1.rb +0 -11
  176. data/test/candidate_helper2.rb +0 -8
  177. data/test/helper.rb +0 -223
  178. data/test/test_cli.rb +0 -78
  179. data/test/test_code.rb +0 -201
  180. data/test/test_command.rb +0 -712
  181. data/test/test_command_helpers.rb +0 -9
  182. data/test/test_command_integration.rb +0 -668
  183. data/test/test_command_set.rb +0 -610
  184. data/test/test_completion.rb +0 -62
  185. data/test/test_control_d_handler.rb +0 -45
  186. data/test/test_default_commands/example.erb +0 -5
  187. data/test/test_default_commands/test_cd.rb +0 -318
  188. data/test/test_default_commands/test_context.rb +0 -280
  189. data/test/test_default_commands/test_documentation.rb +0 -314
  190. data/test/test_default_commands/test_find_method.rb +0 -50
  191. data/test/test_default_commands/test_gems.rb +0 -18
  192. data/test/test_default_commands/test_help.rb +0 -57
  193. data/test/test_default_commands/test_input.rb +0 -428
  194. data/test/test_default_commands/test_introspection.rb +0 -511
  195. data/test/test_default_commands/test_ls.rb +0 -151
  196. data/test/test_default_commands/test_shell.rb +0 -343
  197. data/test/test_default_commands/test_show_source.rb +0 -432
  198. data/test/test_exception_whitelist.rb +0 -21
  199. data/test/test_history_array.rb +0 -65
  200. data/test/test_hooks.rb +0 -521
  201. data/test/test_indent.rb +0 -277
  202. data/test/test_input_stack.rb +0 -86
  203. data/test/test_method.rb +0 -401
  204. data/test/test_pry.rb +0 -463
  205. data/test/test_pry_defaults.rb +0 -419
  206. data/test/test_pry_history.rb +0 -84
  207. data/test/test_pry_output.rb +0 -41
  208. data/test/test_sticky_locals.rb +0 -155
  209. data/test/test_syntax_checking.rb +0 -65
  210. data/test/test_wrapped_module.rb +0 -174
  211. data/test/testrc +0 -2
  212. data/test/testrcbad +0 -2
  213. data/wiki/Customizing-pry.md +0 -397
  214. data/wiki/Home.md +0 -4
@@ -0,0 +1,132 @@
1
+ require 'thread'
2
+
3
+ class Pry
4
+ # There is one InputLock per input (such as STDIN) as two REPLs on the same
5
+ # input makes things delirious. InputLock serializes accesses to the input so
6
+ # that threads to not conflict with each other. The latest thread to request
7
+ # ownership of the input wins.
8
+ class InputLock
9
+ class Interrupt < Exception; end
10
+
11
+ class << self
12
+ attr_accessor :input_locks
13
+ attr_accessor :global_lock
14
+ end
15
+
16
+ self.input_locks = {}
17
+ self.global_lock = Mutex.new
18
+
19
+ def self.for(input)
20
+ # XXX This method leaks memory, as we never unregister an input once we
21
+ # are done with it. Fortunately, the leak is tiny (or so we hope). In
22
+ # usual scenarios, we would leak the StringIO that is passed to be
23
+ # evaluated from the command line.
24
+ global_lock.synchronize do
25
+ input_locks[input] ||= Pry::InputLock.new
26
+ end
27
+ end
28
+
29
+ def initialize
30
+ @mutex = Mutex.new
31
+ @cond = ConditionVariable.new
32
+ @owners = []
33
+ @interruptible = false
34
+ end
35
+
36
+ # Adds ourselves to the ownership list. The last one in the list may access
37
+ # the input through interruptible_region().
38
+ def __with_ownership(&block)
39
+ @mutex.synchronize do
40
+ # Three cases:
41
+ # 1) There are no owners, in this case we are good to go.
42
+ # 2) The current owner of the input is not reading the input (it might
43
+ # just be evaluating some ruby that the user typed).
44
+ # The current owner will figure out that it cannot go back to reading
45
+ # the input since we are adding ourselves to the @owners list, which
46
+ # in turns makes us the current owner.
47
+ # 3) The owner of the input is in the interruptible region, reading from
48
+ # the input. It's safe to send an Interrupt exception to interrupt
49
+ # the owner. It will then proceed like in case 2).
50
+ # We wait until the owner sets the interruptible flag back
51
+ # to false, meaning that he's out of the interruptible region.
52
+ # Note that the owner may receive multiple interrupts since, but that
53
+ # should be okay (and trying to avoid it is futile anyway).
54
+ while @interruptible
55
+ @owners.last.raise Interrupt
56
+ @cond.wait(@mutex)
57
+ end
58
+ @owners << Thread.current
59
+ end
60
+
61
+ block.call
62
+
63
+ ensure
64
+ @mutex.synchronize do
65
+ # We are releasing any desire to have the input ownership by removing
66
+ # ourselves from the list.
67
+ @owners.delete(Thread.current)
68
+
69
+ # We need to wake up the thread at the end of the @owners list, but
70
+ # sadly Ruby doesn't allow us to choose which one we wake up, so we wake
71
+ # them all up.
72
+ @cond.broadcast
73
+ end
74
+ end
75
+
76
+ def with_ownership(&block)
77
+ # If we are in a nested with_ownership() call (nested pry context), we do nothing.
78
+ nested = @mutex.synchronize { @owners.include?(Thread.current) }
79
+ nested ? block.call : __with_ownership(&block)
80
+ end
81
+
82
+ def enter_interruptible_region
83
+ @mutex.synchronize do
84
+ # We patiently wait until we are the owner. This may happen as another
85
+ # thread calls with_ownership() because of a binding.pry happening in
86
+ # another thread.
87
+ @cond.wait(@mutex) until @owners.last == Thread.current
88
+
89
+ # We are the legitimate owner of the input. We mark ourselves as
90
+ # interruptible, so other threads can send us an Interrupt exception
91
+ # while we are blocking from reading the input.
92
+ @interruptible = true
93
+ end
94
+ end
95
+
96
+ def leave_interruptible_region
97
+ @mutex.synchronize do
98
+ # We check if we are still the owner, because we could have received an
99
+ # Interrupt right after the following @cond.broadcast, making us retry.
100
+ @interruptible = false if @owners.last == Thread.current
101
+ @cond.broadcast
102
+ end
103
+ rescue Interrupt
104
+ # We need to guard against a spurious interrupt delivered while we are
105
+ # trying to acquire the lock (the rescue block is no longer in our scope).
106
+ retry
107
+ end
108
+
109
+ def interruptible_region(&block)
110
+ enter_interruptible_region
111
+
112
+ # XXX Note that there is a chance that we get the interrupt right after
113
+ # the readline call succeeded, but we'll never know, and we will retry the
114
+ # call, discarding that piece of input.
115
+ block.call
116
+
117
+ rescue Interrupt
118
+ # We were asked to back off. The one requesting the interrupt will be
119
+ # waiting on the conditional for the interruptible flag to change to false.
120
+ # Note that there can be some inefficiency, as we could immediately
121
+ # succeed in enter_interruptible_region(), even before the one requesting
122
+ # the ownership has the chance to register itself as an owner.
123
+ # To mitigate the issue, we sleep a little bit.
124
+ leave_interruptible_region
125
+ sleep 0.01
126
+ retry
127
+
128
+ ensure
129
+ leave_interruptible_region
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,27 @@
1
+ class Pry::Inspector
2
+ MAP = {
3
+ "default" => {
4
+ value: Pry::DEFAULT_PRINT,
5
+ description: <<-DESCRIPTION.each_line.map(&:lstrip!)
6
+ The default Pry inspector. It has paging and color support, and uses
7
+ pretty_inspect when printing an object.
8
+ DESCRIPTION
9
+ },
10
+
11
+ "simple" => {
12
+ value: Pry::SIMPLE_PRINT,
13
+ description: <<-DESCRIPTION.each_line.map(&:lstrip)
14
+ A simple inspector that uses #puts and #inspect when printing an
15
+ object. It has no pager, color, or pretty_inspect support.
16
+ DESCRIPTION
17
+ },
18
+
19
+ "clipped" => {
20
+ value: Pry::CLIPPED_PRINT,
21
+ description: <<-DESCRIPTION.each_line.map(&:lstrip)
22
+ The clipped inspector has the same features as the 'simple' inspector
23
+ but prints large objects as a smaller string.
24
+ DESCRIPTION
25
+ }
26
+ }
27
+ end
@@ -0,0 +1,61 @@
1
+ #
2
+ # {Pry::LastException} is a proxy class who wraps an Exception object for
3
+ # {Pry#last_exception}. it extends the exception object with methods that
4
+ # help pry commands be useful.
5
+ #
6
+ # the original exception object is not modified and method calls are forwarded
7
+ # to the wrapped exception object.
8
+ #
9
+ class Pry::LastException < BasicObject
10
+ attr_accessor :bt_index
11
+
12
+ def initialize(e)
13
+ @e = e
14
+ @bt_index = 0
15
+ @file, @line = bt_source_location_for(0)
16
+ end
17
+
18
+ def method_missing(name, *args, &block)
19
+ if @e.respond_to?(name)
20
+ @e.public_send(name, *args, &block)
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ def respond_to_missing?(name, include_private = false)
27
+ @e.respond_to?(name)
28
+ end
29
+
30
+ #
31
+ # @return [String]
32
+ # returns the path to a file for the current backtrace. see {#bt_index}.
33
+ #
34
+ def file
35
+ @file
36
+ end
37
+
38
+ #
39
+ # @return [Fixnum]
40
+ # returns the line for the current backtrace. see {#bt_index}.
41
+ #
42
+ def line
43
+ @line
44
+ end
45
+
46
+ # @return [Exception]
47
+ # returns the wrapped exception
48
+ #
49
+ def wrapped_exception
50
+ @e
51
+ end
52
+
53
+ def bt_source_location_for(index)
54
+ backtrace[index] =~ /(.*):(\d+)/
55
+ [$1, $2.to_i]
56
+ end
57
+
58
+ def inc_bt_index
59
+ @bt_index = (@bt_index + 1) % backtrace.size
60
+ end
61
+ end
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  require 'pry/helpers/documentation_helpers'
3
2
 
4
3
  class Pry
@@ -17,16 +16,21 @@ class Pry
17
16
  # This class wraps the normal `Method` and `UnboundMethod` classes
18
17
  # to provide extra functionality useful to Pry.
19
18
  class Method
20
- include RbxMethod if Helpers::BaseHelpers.rbx?
19
+ require 'pry/method/weird_method_locator'
20
+ require 'pry/method/disowned'
21
+ require 'pry/method/patcher'
22
+
23
+ extend Helpers::BaseHelpers
24
+ include Helpers::BaseHelpers
21
25
  include Helpers::DocumentationHelpers
26
+ include CodeObject::Helpers
22
27
 
23
28
  class << self
24
29
  # Given a string representing a method name and optionally a binding to
25
30
  # search in, find and return the requested method wrapped in a `Pry::Method`
26
31
  # instance.
27
32
  #
28
- # @param [String, nil] name The name of the method to retrieve, or `nil` to
29
- # delegate to `from_binding` instead.
33
+ # @param [String] name The name of the method to retrieve.
30
34
  # @param [Binding] target The context in which to search for the method.
31
35
  # @param [Hash] options
32
36
  # @option options [Boolean] :instance Look for an instance method if `name` doesn't
@@ -34,24 +38,30 @@ class Pry
34
38
  # @option options [Boolean] :methods Look for a bound/singleton method if `name` doesn't
35
39
  # contain any context.
36
40
  # @return [Pry::Method, nil] A `Pry::Method` instance containing the requested
37
- # method, or `nil` if no method could be located matching the parameters.
41
+ # method, or `nil` if name is `nil` or no method could be located matching the parameters.
38
42
  def from_str(name, target=TOPLEVEL_BINDING, options={})
39
43
  if name.nil?
40
- from_binding(target)
44
+ nil
41
45
  elsif name.to_s =~ /(.+)\#(\S+)\Z/
42
46
  context, meth_name = $1, $2
43
- from_module(target.eval(context), meth_name)
44
- elsif name.to_s =~ /(.+)\.(\S+)\Z/
47
+ from_module(target.eval(context), meth_name, target)
48
+ elsif name.to_s =~ /(.+)(\[\])\Z/
45
49
  context, meth_name = $1, $2
46
- from_obj(target.eval(context), meth_name)
50
+ from_obj(target.eval(context), meth_name, target)
51
+ elsif name.to_s =~ /(.+)(\.|::)(\S+)\Z/
52
+ context, meth_name = $1, $3
53
+ from_obj(target.eval(context), meth_name, target)
47
54
  elsif options[:instance]
48
- from_module(target.eval("self"), name)
55
+ from_module(target.eval("self"), name, target)
49
56
  elsif options[:methods]
50
- from_obj(target.eval("self"), name)
57
+ from_obj(target.eval("self"), name, target)
51
58
  else
52
59
  from_str(name, target, :instance => true) or
53
60
  from_str(name, target, :methods => true)
54
61
  end
62
+
63
+ rescue Pry::RescuableException
64
+ nil
55
65
  end
56
66
 
57
67
  # Given a `Binding`, try to extract the `::Method` it originated from and
@@ -62,59 +72,54 @@ class Pry
62
72
  # @return [Pry::Method, nil]
63
73
  #
64
74
  def from_binding(b)
65
- meth_name = b.eval('__method__')
75
+ meth_name = b.eval('::Kernel.__method__')
66
76
  if [:__script__, nil].include?(meth_name)
67
77
  nil
68
78
  else
69
79
  method = begin
70
- new(b.eval("Object.instance_method(:method).bind(self).call(#{meth_name.to_s.inspect})"))
80
+ if Object === b.eval('self')
81
+ new(Kernel.instance_method(:method).bind(b.eval("self")).call(meth_name))
82
+ else
83
+ new(b.eval('class << self; self; end.instance_method(::Kernel.__method__).bind(self)'))
84
+ end
71
85
  rescue NameError, NoMethodError
72
86
  Disowned.new(b.eval('self'), meth_name.to_s)
73
87
  end
74
88
 
75
- # it's possible in some cases that the method we find by this approach is a sub-method of
76
- # the one we're currently in, consider:
77
- #
78
- # class A; def b; binding.pry; end; end
79
- # class B < A; def b; super; end; end
80
- #
81
- # Given that we can normally find the source_range of methods, and that we know which
82
- # __FILE__ and __LINE__ the binding is at, we can hope to disambiguate these cases.
83
- #
84
- # This obviously won't work if the source is unavaiable for some reason, or if both
85
- # methods have the same __FILE__ and __LINE__, or if we're in rbx where b.eval('__LINE__')
86
- # is broken.
87
- #
88
- guess = method
89
-
90
- while guess
91
- # needs rescue if this is a Disowned method or a C method or something...
92
- # TODO: Fix up the exception handling so we don't need a bare rescue
93
- if (guess.source_file && guess.source_range rescue false) &&
94
- File.expand_path(guess.source_file) == File.expand_path(b.eval('__FILE__')) &&
95
- guess.source_range.include?(b.eval('__LINE__'))
96
- return guess
97
- else
98
- guess = guess.super
99
- end
89
+ if WeirdMethodLocator.weird_method?(method, b)
90
+ WeirdMethodLocator.new(method, b).get_method || method
91
+ else
92
+ method
100
93
  end
101
-
102
- # Uhoh... none of the methods in the chain had the right __FILE__ and __LINE__
103
- # This may be caused by rbx https://github.com/rubinius/rubinius/issues/953,
104
- # or other unknown circumstances (TODO: we should warn the user when this happens)
105
- method
106
94
  end
107
95
  end
108
96
 
97
+ # In order to support 2.0 Refinements we need to look up methods
98
+ # inside the relevant Binding.
99
+ # @param [Object] obj The owner/receiver of the method.
100
+ # @param [Symbol] method_name The name of the method.
101
+ # @param [Symbol] method_type The type of method: :method or :instance_method
102
+ # @param [Binding] target The binding where the method is looked up.
103
+ # @return [Method, UnboundMethod] The 'refined' method object.
104
+ def lookup_method_via_binding(obj, method_name, method_type, target=TOPLEVEL_BINDING)
105
+ Pry.current[:obj] = obj
106
+ Pry.current[:name] = method_name
107
+ receiver = obj.is_a?(Module) ? "Module" : "Kernel"
108
+ target.eval("::#{receiver}.instance_method(:#{method_type}).bind(Pry.current[:obj]).call(Pry.current[:name])")
109
+ ensure
110
+ Pry.current[:obj] = Pry.current[:name] = nil
111
+ end
112
+
109
113
  # Given a `Class` or `Module` and the name of a method, try to
110
114
  # instantiate a `Pry::Method` containing the instance method of
111
115
  # that name. Return `nil` if no such method exists.
112
116
  #
113
117
  # @param [Class, Module] klass
114
118
  # @param [String] name
119
+ # @param [Binding] target The binding where the method is looked up.
115
120
  # @return [Pry::Method, nil]
116
- def from_class(klass, name)
117
- new(safe_send(klass, :instance_method, name)) rescue nil
121
+ def from_class(klass, name, target=TOPLEVEL_BINDING)
122
+ new(lookup_method_via_binding(klass, name, :instance_method, target)) rescue nil
118
123
  end
119
124
  alias from_module from_class
120
125
 
@@ -124,9 +129,10 @@ class Pry
124
129
  #
125
130
  # @param [Object] obj
126
131
  # @param [String] name
132
+ # @param [Binding] target The binding where the method is looked up.
127
133
  # @return [Pry::Method, nil]
128
- def from_obj(obj, name)
129
- new(safe_send(obj, :method, name)) rescue nil
134
+ def from_obj(obj, name, target=TOPLEVEL_BINDING)
135
+ new(lookup_method_via_binding(obj, name, :method, target)) rescue nil
130
136
  end
131
137
 
132
138
  # Get all of the instance methods of a `Class` or `Module`
@@ -134,15 +140,34 @@ class Pry
134
140
  # @param [Boolean] include_super Whether to include methods from ancestors.
135
141
  # @return [Array[Pry::Method]]
136
142
  def all_from_class(klass, include_super=true)
137
- all_from_common(klass, :instance_method, include_super)
143
+ %w(public protected private).map do |visibility|
144
+ safe_send(klass, :"#{visibility}_instance_methods", include_super).map do |method_name|
145
+ new(safe_send(klass, :instance_method, method_name), :visibility => visibility.to_sym)
146
+ end
147
+ end.flatten(1)
138
148
  end
139
149
 
150
+ #
140
151
  # Get all of the methods on an `Object`
152
+ #
141
153
  # @param [Object] obj
142
- # @param [Boolean] include_super Whether to include methods from ancestors.
154
+ #
155
+ # @param [Boolean] include_super
156
+ # indicates whether or not to include methods from ancestors.
157
+ #
143
158
  # @return [Array[Pry::Method]]
159
+ #
144
160
  def all_from_obj(obj, include_super=true)
145
- all_from_common(obj, :method, include_super)
161
+ all_from_class(singleton_class_of(obj), include_super)
162
+ end
163
+
164
+ #
165
+ # @deprecated
166
+ # please use {#all_from_obj} instead.
167
+ # the `method_type` argument is ignored.
168
+ #
169
+ def all_from_common(obj, method_type = nil, include_super=true)
170
+ all_from_obj(obj, include_super)
146
171
  end
147
172
 
148
173
  # Get every `Class` and `Module`, in order, that will be checked when looking
@@ -153,7 +178,7 @@ class Pry
153
178
  if Class === obj
154
179
  singleton_class_resolution_order(obj) + instance_resolution_order(Class)
155
180
  else
156
- klass = singleton_class(obj) rescue obj.class
181
+ klass = singleton_class_of(obj) rescue obj.class
157
182
  instance_resolution_order(klass)
158
183
  end
159
184
  end
@@ -165,46 +190,42 @@ class Pry
165
190
  # @return [Array[Class, Module]]
166
191
  def instance_resolution_order(klass)
167
192
  # include klass in case it is a singleton class,
168
- ([klass] + klass.ancestors).uniq
193
+ ([klass] + Pry::Method.safe_send(klass, :ancestors)).uniq
169
194
  end
170
195
 
171
- private
196
+ def method_definition?(name, definition_line)
197
+ singleton_method_definition?(name, definition_line) ||
198
+ instance_method_definition?(name, definition_line)
199
+ end
172
200
 
173
- # See all_from_class and all_from_obj.
174
- # If method_type is :instance_method, obj must be a `Class` or a `Module`
175
- # If method_type is :method, obj can be any `Object`
176
- #
177
- # N.B. we pre-cache the visibility here to avoid O(N²) behaviour in "ls".
178
- def all_from_common(obj, method_type, include_super=true)
179
- %w(public protected private).map do |visibility|
180
- safe_send(obj, :"#{visibility}_#{method_type}s", include_super).map do |method_name|
181
- new(safe_send(obj, method_type, method_name), :visibility => visibility.to_sym)
182
- end
183
- end.flatten(1)
201
+ def singleton_method_definition?(name, definition_line)
202
+ /^define_singleton_method\(?\s*[:\"\']#{Regexp.escape(name)}|^def\s*self\.#{Regexp.escape(name)}/ =~ definition_line.strip
184
203
  end
185
204
 
186
- # Acts like send but ignores any methods defined below Object or Class in the
187
- # inheritance hierarchy.
188
- # This is required to introspect methods on objects like Net::HTTP::Get that
189
- # have overridden the `method` method.
190
- def safe_send(obj, method, *args, &block)
191
- (Module === obj ? Module : Object).instance_method(method).bind(obj).call(*args, &block)
205
+ def instance_method_definition?(name, definition_line)
206
+ /^define_method\(?\s*[:\"\']#{Regexp.escape(name)}|^def\s*#{Regexp.escape(name)}/ =~ definition_line.strip
192
207
  end
193
- public :safe_send
194
208
 
195
209
  # Get the singleton classes of superclasses that could define methods on
196
210
  # the given class object, and any modules they include.
197
211
  # If a module is included at multiple points in the ancestry, only
198
212
  # the lowest copy will be returned.
199
213
  def singleton_class_resolution_order(klass)
200
- resolution_order = klass.ancestors.map do |anc|
201
- [singleton_class(anc)] + singleton_class(anc).included_modules if anc.is_a?(Class)
202
- end.compact.flatten(1)
214
+ ancestors = Pry::Method.safe_send(klass, :ancestors)
215
+ resolution_order = ancestors.grep(Class).map do |anc|
216
+ [singleton_class_of(anc), *singleton_class_of(anc).included_modules]
217
+ end.flatten(1)
203
218
 
204
219
  resolution_order.reverse.uniq.reverse - Class.included_modules
205
220
  end
206
221
 
207
- def singleton_class(obj); class << obj; self; end end
222
+ def singleton_class_of(obj)
223
+ begin
224
+ class << obj; self; end
225
+ rescue TypeError # can't define singleton. Fixnum, Symbol, Float, ...
226
+ obj.class
227
+ end
228
+ end
208
229
  end
209
230
 
210
231
  # A new instance of `Pry::Method` wrapping the given `::Method`, `UnboundMethod`, or `Proc`.
@@ -229,6 +250,12 @@ class Pry
229
250
  @wrapped_owner ||= Pry::WrappedModule.new(owner)
230
251
  end
231
252
 
253
+ # Get underlying object wrapped by this Pry::Method instance
254
+ # @return [Method, UnboundMethod, Proc]
255
+ def wrapped
256
+ @method
257
+ end
258
+
232
259
  # Is the method undefined? (aka `Disowned`)
233
260
  # @return [Boolean] false
234
261
  def undefined?
@@ -248,26 +275,18 @@ class Pry
248
275
  def source
249
276
  @source ||= case source_type
250
277
  when :c
251
- info = pry_doc_info
252
- if info and info.source
253
- code = strip_comments_from_c_code(info.source)
254
- end
278
+ c_source
255
279
  when :ruby
256
- # clone of MethodSource.source_helper that knows to use our
257
- # hacked version of source_location for rbx core methods, and
258
- # our input buffer for methods defined in (pry)
259
- file, line = *source_location
260
- raise SourceNotFoundError, "Could not locate source for #{name_with_owner}!" unless file
261
-
262
- begin
263
- code = Pry::Code.from_file(file).expression_at(line)
264
- rescue SyntaxError => e
265
- raise MethodSource::SourceNotFoundError.new(e.message)
266
- end
267
- strip_leading_whitespace(code)
280
+ ruby_source
268
281
  end
269
282
  end
270
283
 
284
+ # Update the live copy of the method's source.
285
+ def redefine(source)
286
+ Patcher.new(self).patch_in_ram source
287
+ Pry::Method(owner.instance_method(name))
288
+ end
289
+
271
290
  # Can we get the source code for this method?
272
291
  # @return [Boolean]
273
292
  def source?
@@ -278,20 +297,13 @@ class Pry
278
297
 
279
298
  # @return [String, nil] The documentation for the method, or `nil` if it's
280
299
  # unavailable.
281
- # @raise [CommandError] Raises when the method was defined in the REPL.
282
300
  def doc
283
301
  @doc ||= case source_type
284
302
  when :c
285
303
  info = pry_doc_info
286
304
  info.docstring if info
287
305
  when :ruby
288
- if Helpers::BaseHelpers.rbx? && !pry_method?
289
- strip_leading_hash_and_whitespace_from_ruby_comments(core_doc)
290
- elsif pry_method?
291
- strip_leading_hash_and_whitespace_from_ruby_comments(doc_for_pry_method)
292
- else
293
- strip_leading_hash_and_whitespace_from_ruby_comments(@method.comment)
294
- end
306
+ get_comment_content(comment)
295
307
  end
296
308
  end
297
309
 
@@ -301,20 +313,11 @@ class Pry
301
313
  source_location.nil? ? :c : :ruby
302
314
  end
303
315
 
304
- def source_location
305
- if @method.source_location && Helpers::BaseHelpers.rbx?
306
- file, line = @method.source_location
307
- [RbxPath.convert_path_to_full(file), line]
308
- else
309
- @method.source_location
310
- end
311
- end
312
-
313
316
  # @return [String, nil] The name of the file the method is defined in, or
314
317
  # `nil` if the filename is unavailable.
315
318
  def source_file
316
319
  if source_location.nil?
317
- if !Helpers::BaseHelpers.rbx? and source_type == :c
320
+ if !rbx? and source_type == :c
318
321
  info = pry_doc_info
319
322
  info.file if info
320
323
  end
@@ -398,11 +401,43 @@ class Pry
398
401
  !!(source_file and source_file =~ /(\(.*\))|<.*>/)
399
402
  end
400
403
 
404
+ # @return [Boolean] Whether the method is unbound.
405
+ def unbound_method?
406
+ is_a?(::UnboundMethod)
407
+ end
408
+
409
+ # @return [Boolean] Whether the method is bound.
410
+ def bound_method?
411
+ is_a?(::Method)
412
+ end
413
+
414
+ # @return [Boolean] Whether the method is a singleton method.
415
+ def singleton_method?
416
+ wrapped_owner.singleton_class?
417
+ end
418
+
401
419
  # @return [Boolean] Was the method defined within the Pry REPL?
402
420
  def pry_method?
403
421
  source_file == Pry.eval_path
404
422
  end
405
423
 
424
+ # @return [Array<String>] All known aliases for the method.
425
+ def aliases
426
+ owner = @method.owner
427
+ # Avoid using `to_sym` on {Method#name}, which returns a `String`, because
428
+ # it won't be garbage collected.
429
+ name = @method.name
430
+
431
+ all_methods_to_compare = owner.instance_methods | owner.private_instance_methods
432
+ alias_list = all_methods_to_compare.combination(2).select do |pair|
433
+ pair.include?(name) &&
434
+ owner.instance_method(pair.first) == owner.instance_method(pair.last)
435
+ end.flatten
436
+ alias_list.delete(name)
437
+
438
+ alias_list.map(&:to_s)
439
+ end
440
+
406
441
  # @return [Boolean] Is the method definitely an alias?
407
442
  def alias?
408
443
  name != original_name
@@ -435,113 +470,77 @@ class Pry
435
470
  @method.send(method_name, *args, &block)
436
471
  end
437
472
 
438
- private
439
- # @return [YARD::CodeObjects::MethodObject]
440
- # @raise [CommandError] Raises when the method can't be found or `pry-doc` isn't installed.
441
- def pry_doc_info
442
- if Pry.config.has_pry_doc
443
- Pry::MethodInfo.info_for(@method) or raise CommandError, "Cannot locate this method: #{name}. (source_location returns nil)"
444
- else
445
- raise CommandError, "Cannot locate this method: #{name}. Try `gem install pry-doc` to get access to Ruby Core documentation."
446
- end
447
- end
448
-
449
- # FIXME: a very similar method to this exists on WrappedModule: extract_doc_for_candidate
450
- def doc_for_pry_method
451
- _, line_num = source_location
452
-
453
- buffer = ""
454
- Pry.line_buffer[0..(line_num - 1)].each do |line|
455
- # Add any line that is a valid ruby comment,
456
- # but clear as soon as we hit a non comment line.
457
- if (line =~ /^\s*#/) || (line =~ /^\s*$/)
458
- buffer << line.lstrip
459
- else
460
- buffer.replace("")
461
- end
462
- end
473
+ def comment
474
+ Pry::Code.from_file(source_file).comment_describing(source_line)
475
+ end
463
476
 
464
- buffer
465
- end
477
+ private
466
478
 
467
- # @param [Class, Module] ancestors The ancestors to investigate
468
- # @return [Method] The unwrapped super-method
469
- def super_using_ancestors(ancestors, times=1)
470
- next_owner = self.owner
471
- times.times do
472
- i = ancestors.index(next_owner) + 1
473
- while ancestors[i] && !(ancestors[i].method_defined?(name) || ancestors[i].private_method_defined?(name))
474
- i += 1
475
- end
476
- next_owner = ancestors[i] or return nil
479
+ # @return [YARD::CodeObjects::MethodObject]
480
+ # @raise [CommandError] when the method can't be found or `pry-doc` isn't installed.
481
+ def pry_doc_info
482
+ if Pry.config.has_pry_doc
483
+ Pry::MethodInfo.info_for(@method) or raise CommandError, "Cannot locate this method: #{name}. (source_location returns nil)"
484
+ else
485
+ fail_msg = "Cannot locate this method: #{name}."
486
+ if mri?
487
+ fail_msg += ' Try `gem-install pry-doc` to get access to Ruby Core documentation.'
477
488
  end
478
- next_owner.instance_method(name) rescue nil
489
+ raise CommandError, fail_msg
479
490
  end
491
+ end
480
492
 
481
- # @param [String] first_ln The first line of a method definition.
482
- # @return [String, nil]
483
- def method_name_from_first_line(first_ln)
484
- return nil if first_ln.strip !~ /^def /
485
-
486
- tokens = CodeRay.scan(first_ln, :ruby)
487
- tokens = tokens.tokens.each_slice(2) if tokens.respond_to?(:tokens)
488
- tokens.each_cons(2) do |t1, t2|
489
- if t2.last == :method || t2.last == :ident && t1 == [".", :operator]
490
- return t2.first
491
- end
493
+ # @param [Class, Module] ancestors The ancestors to investigate
494
+ # @return [Method] The unwrapped super-method
495
+ def super_using_ancestors(ancestors, times=1)
496
+ next_owner = self.owner
497
+ times.times do
498
+ i = ancestors.index(next_owner) + 1
499
+ while ancestors[i] && !(ancestors[i].method_defined?(name) || ancestors[i].private_method_defined?(name))
500
+ i += 1
492
501
  end
493
-
494
- nil
502
+ next_owner = ancestors[i] or return nil
495
503
  end
496
504
 
497
- # A Disowned Method is one that's been removed from the class on which it was defined.
498
- #
499
- # e.g.
500
- # class C
501
- # def foo
502
- # C.send(:undefine_method, :foo)
503
- # Pry::Method.from_binding(binding)
504
- # end
505
- # end
506
- #
507
- # In this case we assume that the "owner" is the singleton class of the receiver.
508
- #
509
- # This occurs mainly in Sinatra applications.
510
- class Disowned < Method
511
- attr_reader :receiver, :name
505
+ safe_send(next_owner, :instance_method, name) rescue nil
506
+ end
512
507
 
513
- # Create a new Disowned method.
514
- #
515
- # @param [Object] receiver
516
- # @param [String] method_name
517
- def initialize(receiver, method_name)
518
- @receiver, @name = receiver, method_name
519
- end
508
+ # @param [String] first_ln The first line of a method definition.
509
+ # @return [String, nil]
510
+ def method_name_from_first_line(first_ln)
511
+ return nil if first_ln.strip !~ /^def /
520
512
 
521
- # Is the method undefined? (aka `Disowned`)
522
- # @return [Boolean] true
523
- def undefined?
524
- true
513
+ tokens = CodeRay.scan(first_ln, :ruby)
514
+ tokens = tokens.tokens.each_slice(2) if tokens.respond_to?(:tokens)
515
+ tokens.each_cons(2) do |t1, t2|
516
+ if t2.last == :method || t2.last == :ident && t1 == [".", :operator]
517
+ return t2.first
518
+ end
525
519
  end
526
520
 
527
- # Can we get the source for this method?
528
- # @return [Boolean] false
529
- def source?
530
- false
531
- end
521
+ nil
522
+ end
532
523
 
533
- # Get the hypothesized owner of the method.
534
- #
535
- # @return [Object]
536
- def owner
537
- class << receiver; self; end
524
+ def c_source
525
+ info = pry_doc_info
526
+ if info and info.source
527
+ strip_comments_from_c_code(info.source)
538
528
  end
529
+ end
539
530
 
540
- # Raise a more useful error message instead of trying to forward to nil.
541
- def method_missing(meth_name, *args, &block)
542
- raise "Cannot call '#{meth_name}' on an undef'd method." if method(:name).respond_to?(meth_name)
543
- Object.instance_method(:method_missing).bind(self).call(meth_name, *args, &block)
531
+ def ruby_source
532
+ # clone of MethodSource.source_helper that knows to use our
533
+ # hacked version of source_location for rbx core methods, and
534
+ # our input buffer for methods defined in (pry)
535
+ file, line = *source_location
536
+ raise SourceNotFoundError, "Could not locate source for #{name_with_owner}!" unless file
537
+
538
+ begin
539
+ code = Pry::Code.from_file(file).expression_at(line)
540
+ rescue SyntaxError => e
541
+ raise MethodSource::SourceNotFoundError.new(e.message)
544
542
  end
543
+ strip_leading_whitespace(code)
545
544
  end
546
545
  end
547
546
  end