pry 0.10.pre.1-i386-mswin32 → 0.10.0.pre3-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 (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 +122 -183
  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