pry 0.9.10 → 0.9.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (194) hide show
  1. data/.travis.yml +3 -1
  2. data/CHANGELOG +60 -1
  3. data/CONTRIBUTORS +43 -25
  4. data/Gemfile +7 -0
  5. data/Guardfile +62 -0
  6. data/README.markdown +4 -4
  7. data/Rakefile +34 -35
  8. data/lib/pry.rb +107 -54
  9. data/lib/pry/cli.rb +34 -11
  10. data/lib/pry/code.rb +165 -182
  11. data/lib/pry/code/code_range.rb +70 -0
  12. data/lib/pry/code/loc.rb +92 -0
  13. data/lib/pry/code_object.rb +153 -0
  14. data/lib/pry/command.rb +160 -22
  15. data/lib/pry/command_set.rb +37 -26
  16. data/lib/pry/commands.rb +4 -27
  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 +53 -0
  21. data/lib/pry/commands/cat/abstract_formatter.rb +27 -0
  22. data/lib/pry/commands/cat/exception_formatter.rb +78 -0
  23. data/lib/pry/commands/cat/file_formatter.rb +84 -0
  24. data/lib/pry/commands/cat/input_expression_formatter.rb +43 -0
  25. data/lib/pry/commands/cd.rb +30 -0
  26. data/lib/pry/commands/code_collector.rb +165 -0
  27. data/lib/pry/commands/deprecated_commands.rb +2 -0
  28. data/lib/pry/commands/disable_pry.rb +27 -0
  29. data/lib/pry/commands/easter_eggs.rb +112 -0
  30. data/lib/pry/commands/edit.rb +206 -0
  31. data/lib/pry/commands/edit/exception_patcher.rb +25 -0
  32. data/lib/pry/commands/edit/file_and_line_locator.rb +38 -0
  33. data/lib/pry/commands/edit/method_patcher.rb +122 -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 +24 -0
  37. data/lib/pry/commands/find_method.rb +199 -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 +29 -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 +95 -0
  44. data/lib/pry/commands/help.rb +164 -0
  45. data/lib/pry/commands/hist.rb +161 -0
  46. data/lib/pry/commands/import_set.rb +22 -0
  47. data/lib/pry/commands/install_command.rb +51 -0
  48. data/lib/pry/commands/jump_to.rb +29 -0
  49. data/lib/pry/commands/ls.rb +339 -0
  50. data/lib/pry/commands/nesting.rb +25 -0
  51. data/lib/pry/commands/play.rb +69 -0
  52. data/lib/pry/commands/pry_backtrace.rb +26 -0
  53. data/lib/pry/commands/pry_version.rb +17 -0
  54. data/lib/pry/commands/raise_up.rb +32 -0
  55. data/lib/pry/commands/reload_code.rb +39 -0
  56. data/lib/pry/commands/reset.rb +18 -0
  57. data/lib/pry/commands/ri.rb +56 -0
  58. data/lib/pry/commands/save_file.rb +61 -0
  59. data/lib/pry/commands/shell_command.rb +43 -0
  60. data/lib/pry/commands/shell_mode.rb +27 -0
  61. data/lib/pry/commands/show_doc.rb +78 -0
  62. data/lib/pry/commands/show_info.rb +139 -0
  63. data/lib/pry/commands/show_input.rb +17 -0
  64. data/lib/pry/commands/show_source.rb +37 -0
  65. data/lib/pry/commands/simple_prompt.rb +22 -0
  66. data/lib/pry/commands/stat.rb +40 -0
  67. data/lib/pry/commands/switch_to.rb +23 -0
  68. data/lib/pry/commands/toggle_color.rb +20 -0
  69. data/lib/pry/commands/whereami.rb +114 -0
  70. data/lib/pry/commands/wtf.rb +57 -0
  71. data/lib/pry/completion.rb +120 -46
  72. data/lib/pry/config.rb +11 -0
  73. data/lib/pry/core_extensions.rb +27 -16
  74. data/lib/pry/editor.rb +129 -0
  75. data/lib/pry/helpers.rb +1 -0
  76. data/lib/pry/helpers/base_helpers.rb +89 -119
  77. data/lib/pry/helpers/command_helpers.rb +6 -121
  78. data/lib/pry/helpers/table.rb +100 -0
  79. data/lib/pry/helpers/text.rb +4 -4
  80. data/lib/pry/history_array.rb +5 -0
  81. data/lib/pry/hooks.rb +1 -3
  82. data/lib/pry/indent.rb +104 -30
  83. data/lib/pry/method.rb +66 -22
  84. data/lib/pry/module_candidate.rb +26 -15
  85. data/lib/pry/pager.rb +70 -0
  86. data/lib/pry/plugins.rb +1 -2
  87. data/lib/pry/pry_class.rb +63 -22
  88. data/lib/pry/pry_instance.rb +58 -37
  89. data/lib/pry/rubygem.rb +74 -0
  90. data/lib/pry/terminal_info.rb +43 -0
  91. data/lib/pry/test/helper.rb +185 -0
  92. data/lib/pry/version.rb +1 -1
  93. data/lib/pry/wrapped_module.rb +58 -24
  94. data/pry.gemspec +21 -37
  95. data/{test/test_cli.rb → spec/cli_spec.rb} +0 -0
  96. data/spec/code_object_spec.rb +277 -0
  97. data/{test/test_code.rb → spec/code_spec.rb} +19 -1
  98. data/{test/test_command_helpers.rb → spec/command_helpers_spec.rb} +0 -0
  99. data/{test/test_command_integration.rb → spec/command_integration_spec.rb} +38 -46
  100. data/{test/test_command_set.rb → spec/command_set_spec.rb} +18 -1
  101. data/{test/test_command.rb → spec/command_spec.rb} +250 -149
  102. data/spec/commands/amend_line_spec.rb +247 -0
  103. data/spec/commands/bang_spec.rb +19 -0
  104. data/spec/commands/cat_spec.rb +164 -0
  105. data/spec/commands/cd_spec.rb +250 -0
  106. data/spec/commands/disable_pry_spec.rb +25 -0
  107. data/spec/commands/edit_spec.rb +727 -0
  108. data/spec/commands/exit_all_spec.rb +34 -0
  109. data/spec/commands/exit_program_spec.rb +19 -0
  110. data/spec/commands/exit_spec.rb +34 -0
  111. data/{test/test_default_commands/test_find_method.rb → spec/commands/find_method_spec.rb} +27 -7
  112. data/spec/commands/gem_list_spec.rb +26 -0
  113. data/spec/commands/gist_spec.rb +75 -0
  114. data/{test/test_default_commands/test_help.rb → spec/commands/help_spec.rb} +8 -9
  115. data/spec/commands/hist_spec.rb +181 -0
  116. data/spec/commands/jump_to_spec.rb +15 -0
  117. data/spec/commands/ls_spec.rb +177 -0
  118. data/spec/commands/play_spec.rb +140 -0
  119. data/spec/commands/raise_up_spec.rb +56 -0
  120. data/spec/commands/save_file_spec.rb +177 -0
  121. data/spec/commands/show_doc_spec.rb +378 -0
  122. data/spec/commands/show_input_spec.rb +17 -0
  123. data/spec/commands/show_source_spec.rb +597 -0
  124. data/spec/commands/whereami_spec.rb +154 -0
  125. data/spec/completion_spec.rb +233 -0
  126. data/spec/control_d_handler_spec.rb +58 -0
  127. data/spec/editor_spec.rb +79 -0
  128. data/{test/test_exception_whitelist.rb → spec/exception_whitelist_spec.rb} +0 -0
  129. data/{test → spec/fixtures}/candidate_helper1.rb +0 -0
  130. data/{test → spec/fixtures}/candidate_helper2.rb +0 -0
  131. data/{test/test_default_commands → spec/fixtures}/example.erb +0 -0
  132. data/spec/fixtures/example_nesting.rb +33 -0
  133. data/spec/fixtures/show_source_doc_examples.rb +15 -0
  134. data/{test → spec/fixtures}/testrc +0 -0
  135. data/{test → spec/fixtures}/testrcbad +0 -0
  136. data/spec/helper.rb +34 -0
  137. data/spec/helpers/bacon.rb +86 -0
  138. data/spec/helpers/mock_pry.rb +43 -0
  139. data/spec/helpers/table_spec.rb +83 -0
  140. data/{test/test_history_array.rb → spec/history_array_spec.rb} +21 -19
  141. data/{test/test_hooks.rb → spec/hooks_spec.rb} +0 -0
  142. data/{test/test_indent.rb → spec/indent_spec.rb} +24 -0
  143. data/{test/test_input_stack.rb → spec/input_stack_spec.rb} +4 -0
  144. data/{test/test_method.rb → spec/method_spec.rb} +65 -1
  145. data/{test/test_prompt.rb → spec/prompt_spec.rb} +0 -0
  146. data/{test/test_pry_defaults.rb → spec/pry_defaults_spec.rb} +14 -14
  147. data/{test/test_pry_history.rb → spec/pry_history_spec.rb} +15 -0
  148. data/spec/pry_output_spec.rb +95 -0
  149. data/{test/test_pry.rb → spec/pry_spec.rb} +74 -32
  150. data/{test/test_sticky_locals.rb → spec/sticky_locals_spec.rb} +27 -25
  151. data/{test/test_syntax_checking.rb → spec/syntax_checking_spec.rb} +17 -1
  152. data/{test/test_wrapped_module.rb → spec/wrapped_module_spec.rb} +92 -5
  153. metadata +236 -112
  154. data/examples/example_basic.rb +0 -15
  155. data/examples/example_command_override.rb +0 -32
  156. data/examples/example_commands.rb +0 -36
  157. data/examples/example_hooks.rb +0 -9
  158. data/examples/example_image_edit.rb +0 -67
  159. data/examples/example_input.rb +0 -7
  160. data/examples/example_input2.rb +0 -29
  161. data/examples/example_output.rb +0 -11
  162. data/examples/example_print.rb +0 -6
  163. data/examples/example_prompt.rb +0 -9
  164. data/examples/helper.rb +0 -6
  165. data/lib/pry/default_commands/cd.rb +0 -81
  166. data/lib/pry/default_commands/commands.rb +0 -62
  167. data/lib/pry/default_commands/context.rb +0 -98
  168. data/lib/pry/default_commands/easter_eggs.rb +0 -95
  169. data/lib/pry/default_commands/editing.rb +0 -420
  170. data/lib/pry/default_commands/find_method.rb +0 -169
  171. data/lib/pry/default_commands/gems.rb +0 -84
  172. data/lib/pry/default_commands/gist.rb +0 -187
  173. data/lib/pry/default_commands/help.rb +0 -127
  174. data/lib/pry/default_commands/hist.rb +0 -120
  175. data/lib/pry/default_commands/input_and_output.rb +0 -306
  176. data/lib/pry/default_commands/introspection.rb +0 -410
  177. data/lib/pry/default_commands/ls.rb +0 -272
  178. data/lib/pry/default_commands/misc.rb +0 -38
  179. data/lib/pry/default_commands/navigating_pry.rb +0 -110
  180. data/lib/pry/default_commands/whereami.rb +0 -92
  181. data/lib/pry/extended_commands/experimental.rb +0 -7
  182. data/test/helper.rb +0 -223
  183. data/test/test_completion.rb +0 -62
  184. data/test/test_control_d_handler.rb +0 -45
  185. data/test/test_default_commands/test_cd.rb +0 -321
  186. data/test/test_default_commands/test_context.rb +0 -288
  187. data/test/test_default_commands/test_documentation.rb +0 -315
  188. data/test/test_default_commands/test_gems.rb +0 -18
  189. data/test/test_default_commands/test_input.rb +0 -428
  190. data/test/test_default_commands/test_introspection.rb +0 -511
  191. data/test/test_default_commands/test_ls.rb +0 -151
  192. data/test/test_default_commands/test_shell.rb +0 -343
  193. data/test/test_default_commands/test_show_source.rb +0 -432
  194. data/test/test_pry_output.rb +0 -41
@@ -33,7 +33,7 @@ class Pry
33
33
  #
34
34
  # @param [String, #to_s] text
35
35
  # @return [String] _text_ stripped of any color codes.
36
- def strip_color text
36
+ def strip_color(text)
37
37
  text.to_s.gsub(/\e\[.*?(\d)+m/ , '')
38
38
  end
39
39
 
@@ -42,7 +42,7 @@ class Pry
42
42
  #
43
43
  # @param [String, #to_s] text
44
44
  # @return [String] _text_
45
- def bold text
45
+ def bold(text)
46
46
  Pry.color ? "\e[1m#{text}\e[0m" : text.to_s
47
47
  end
48
48
 
@@ -59,7 +59,7 @@ class Pry
59
59
  # Executes the block with `Pry.color` set to false.
60
60
  # @yield
61
61
  # @return [void]
62
- def no_color &block
62
+ def no_color(&block)
63
63
  boolean = Pry.config.color
64
64
  Pry.config.color = false
65
65
  yield
@@ -70,7 +70,7 @@ class Pry
70
70
  # Executes the block with `Pry.config.pager` set to false.
71
71
  # @yield
72
72
  # @return [void]
73
- def no_pager &block
73
+ def no_pager(&block)
74
74
  boolean = Pry.config.pager
75
75
  Pry.config.pager = false
76
76
  yield
@@ -89,6 +89,11 @@ class Pry
89
89
  ((@count - size)...@count).map { |n| @hash[n] }
90
90
  end
91
91
 
92
+ def pop!
93
+ @hash.delete @count - 1
94
+ @count -= 1
95
+ end
96
+
92
97
  def inspect
93
98
  "#<#{self.class} size=#{size} first=#{@count - size} max_size=#{max_size}>"
94
99
  end
@@ -244,9 +244,7 @@ class Pry
244
244
  # @param [Symbol] hook_name Name of the hook.
245
245
  # @return [Boolean] Whether the hook by the name `hook_name`
246
246
  def hook_exists?(event_name, hook_name)
247
- !!@hooks[event_name].find { |name, _| name == hook_name }
247
+ !!(@hooks[event_name] && @hooks[event_name].find { |name, _| name == hook_name })
248
248
  end
249
- private :hook_exists?
250
-
251
249
  end
252
250
  end
@@ -17,9 +17,12 @@ class Pry
17
17
  class Indent
18
18
  include Helpers::BaseHelpers
19
19
 
20
+ # Raised if {#module_nesting} would not work.
21
+ class UnparseableNestingError < StandardError; end
22
+
20
23
  # @return [String] String containing the spaces to be inserted before the next line.
21
24
  attr_reader :indent_level
22
-
25
+
23
26
  # @return [Array<String>] The stack of open tokens.
24
27
  attr_reader :stack
25
28
 
@@ -51,6 +54,9 @@ class Pry
51
54
  # a single-line.
52
55
  SINGLELINE_TOKENS = %w(if while until unless rescue)
53
56
 
57
+ # Which tokens can be followed by an optional "do" keyword.
58
+ OPTIONAL_DO_TOKENS = %w(for while until)
59
+
54
60
  # Collection of token types that should be ignored. Without this list
55
61
  # keywords such as "class" inside strings would cause the code to be
56
62
  # indented incorrectly.
@@ -73,6 +79,32 @@ class Pry
73
79
  # don't affect the surrounding code.
74
80
  MIDWAY_TOKENS = %w(when else elsif ensure rescue)
75
81
 
82
+ # Clean the indentation of a fragment of ruby.
83
+ #
84
+ # @param [String] str
85
+ # @return [String]
86
+ def self.indent(str)
87
+ new.indent(str)
88
+ end
89
+
90
+ # Get the module nesting at the given point in the given string.
91
+ #
92
+ # NOTE If the line specified contains a method definition, then the nesting
93
+ # at the start of the method definition is used. Otherwise the nesting from
94
+ # the end of the line is used.
95
+ #
96
+ # @param [String] str The ruby code to analyze
97
+ # @param [Fixnum] line_number The line number (starting from 1)
98
+ # @return [Array<String>]
99
+ def self.nesting_at(str, line_number)
100
+ indent = new
101
+ lines = str.split("\n")
102
+ n = line_number - 1
103
+ to_indent = lines[0...n] + (lines[n] || "").split("def").first(1)
104
+ indent.indent(to_indent.join("\n") + "\n")
105
+ indent.module_nesting
106
+ end
107
+
76
108
  def initialize
77
109
  reset
78
110
  end
@@ -84,6 +116,8 @@ class Pry
84
116
  @heredoc_queue = []
85
117
  @close_heredocs = {}
86
118
  @string_start = nil
119
+ @awaiting_class = false
120
+ @module_nesting = []
87
121
  self
88
122
  end
89
123
 
@@ -129,7 +163,6 @@ class Pry
129
163
  new_prefix = prefix + SPACES * after
130
164
 
131
165
  line = prefix + line.lstrip unless previously_in_string
132
- line = line.rstrip + "\n" unless in_string?
133
166
 
134
167
  output += line
135
168
 
@@ -138,7 +171,7 @@ class Pry
138
171
 
139
172
  @indent_level = prefix
140
173
 
141
- return output.gsub(/\s+$/, '')
174
+ return output
142
175
  end
143
176
 
144
177
  # Get the indentation for the start of the next line.
@@ -192,7 +225,9 @@ class Pry
192
225
  last_token, last_kind = token, kind unless kind == :space
193
226
  next if IGNORE_TOKENS.include?(kind)
194
227
 
195
- seen_for_at << add_after if token == "for"
228
+ track_module_nesting(token, kind)
229
+
230
+ seen_for_at << add_after if OPTIONAL_DO_TOKENS.include?(token)
196
231
 
197
232
  if kind == :delimiter
198
233
  track_delimiter(token)
@@ -200,7 +235,8 @@ class Pry
200
235
  @stack << token
201
236
  add_after += 1
202
237
  elsif token == OPEN_TOKENS[@stack.last]
203
- @stack.pop
238
+ popped = @stack.pop
239
+ track_module_nesting_end(popped)
204
240
  if add_after == 0
205
241
  remove_before += 1
206
242
  else
@@ -282,6 +318,68 @@ class Pry
282
318
  "puts #{open_delimiters.join(", ")}"
283
319
  end
284
320
 
321
+ # Update the internal state relating to module nesting.
322
+ #
323
+ # It's responsible for adding to the @module_nesting array, which looks
324
+ # something like:
325
+ #
326
+ # [ ["class", "Foo"], ["module", "Bar::Baz"], ["class <<", "self"] ]
327
+ #
328
+ # A nil value in the @module_nesting array happens in two places: either
329
+ # when @awaiting_token is true and we're still waiting for the string to
330
+ # fill that space, or when a parse was rejected.
331
+ #
332
+ # At the moment this function is quite restricted about what formats it will
333
+ # parse, for example we disallow expressions after the class keyword. This
334
+ # could maybe be improved in the future.
335
+ #
336
+ # @param [String] token a token from Coderay
337
+ # @param [Symbol] kind the kind of that token
338
+ def track_module_nesting(token, kind)
339
+ if kind == :keyword && (token == "class" || token == "module")
340
+ @module_nesting << [token, nil]
341
+ @awaiting_class = true
342
+ elsif @awaiting_class
343
+ if kind == :operator && token == "<<" && @module_nesting.last[0] == "class"
344
+ @module_nesting.last[0] = "class <<"
345
+ @awaiting_class = true
346
+ elsif kind == :class && token =~ /\A(self|[A-Z:][A-Za-z0-9_:]*)\z/
347
+ @module_nesting.last[1] = token if kind == :class
348
+ @awaiting_class = false
349
+ else
350
+ # leave @nesting[-1][
351
+ @awaiting_class = false
352
+ end
353
+ end
354
+ end
355
+
356
+ # Update the internal state relating to module nesting on 'end'.
357
+ #
358
+ # If the current 'end' pairs up with a class or a module then we should
359
+ # pop an array off of @module_nesting
360
+ #
361
+ # @param [String] token a token from Coderay
362
+ # @param [Symbol] kind the kind of that token
363
+ def track_module_nesting_end(token, kind=:keyword)
364
+ if kind == :keyword && (token == "class" || token == "module")
365
+ @module_nesting.pop
366
+ end
367
+ end
368
+
369
+ # Return a list of strings which can be used to re-construct the Module.nesting at
370
+ # the current point in the file.
371
+ #
372
+ # Returns nil if the syntax of the file was not recognizable.
373
+ #
374
+ # @return [Array<String>]
375
+ def module_nesting
376
+ @module_nesting.map do |(kind, token)|
377
+ raise UnparseableNestingError, @module_nesting.inspect if token.nil?
378
+
379
+ "#{kind} #{token}"
380
+ end
381
+ end
382
+
285
383
  # Return a string which, when printed, will rewrite the previous line with
286
384
  # the correct indentation. Mostly useful for fixing 'end'.
287
385
  #
@@ -294,7 +392,7 @@ class Pry
294
392
  full_line = prompt + code
295
393
  whitespace = ' ' * overhang
296
394
 
297
- _, cols = screen_size
395
+ _, cols = TerminalInfo.screen_size
298
396
 
299
397
  cols = cols.to_i
300
398
  lines = cols != 0 ? (full_line.length / cols + 1) : 1
@@ -309,29 +407,5 @@ class Pry
309
407
 
310
408
  "#{move_up}#{prompt}#{colorize_code(code)}#{whitespace}#{move_down}"
311
409
  end
312
-
313
- # Return a pair of [rows, columns] which gives the size of the window.
314
- #
315
- # If the window size cannot be determined, return nil.
316
- def screen_size
317
- [
318
- # io/console adds a winsize method to IO streams.
319
- $stdout.tty? && $stdout.respond_to?(:winsize) && $stdout.winsize,
320
-
321
- # Some readlines also provides get_screen_size.
322
- Readline.respond_to?(:get_screen_size) && Readline.get_screen_size,
323
-
324
- # Otherwise try to use the environment (this may be out of date due
325
- # to window resizing, but it's better than nothing).
326
- [ENV["ROWS"], ENV["COLUMNS"],
327
-
328
- # If the user is running within ansicon, then use the screen size
329
- # that it reports (same caveats apply as with ROWS and COLUMNS)
330
- ENV['ANSICON'] =~ /\((.*)x(.*)\)/ && [$2, $1]
331
- ]
332
- ].detect do |(_, cols)|
333
- cols.to_i > 0
334
- end
335
- end
336
410
  end
337
411
  end
@@ -17,8 +17,11 @@ class Pry
17
17
  # This class wraps the normal `Method` and `UnboundMethod` classes
18
18
  # to provide extra functionality useful to Pry.
19
19
  class Method
20
+ extend Helpers::BaseHelpers
21
+ include Helpers::BaseHelpers
20
22
  include RbxMethod if Helpers::BaseHelpers.rbx?
21
23
  include Helpers::DocumentationHelpers
24
+ include CodeObject::Helpers
22
25
 
23
26
  class << self
24
27
  # Given a string representing a method name and optionally a binding to
@@ -40,18 +43,21 @@ class Pry
40
43
  from_binding(target)
41
44
  elsif name.to_s =~ /(.+)\#(\S+)\Z/
42
45
  context, meth_name = $1, $2
43
- from_module(target.eval(context), meth_name)
44
- elsif name.to_s =~ /(.+)\.(\S+)\Z/
45
- context, meth_name = $1, $2
46
- from_obj(target.eval(context), meth_name)
46
+ from_module(target.eval(context), meth_name, target)
47
+ elsif name.to_s =~ /(.+)(\.|::)(\S+)\Z/
48
+ context, meth_name = $1, $3
49
+ from_obj(target.eval(context), meth_name, target)
47
50
  elsif options[:instance]
48
- from_module(target.eval("self"), name)
51
+ from_module(target.eval("self"), name, target)
49
52
  elsif options[:methods]
50
- from_obj(target.eval("self"), name)
53
+ from_obj(target.eval("self"), name, target)
51
54
  else
52
55
  from_str(name, target, :instance => true) or
53
56
  from_str(name, target, :methods => true)
54
57
  end
58
+
59
+ rescue Pry::RescuableException
60
+ nil
55
61
  end
56
62
 
57
63
  # Given a `Binding`, try to extract the `::Method` it originated from and
@@ -62,12 +68,16 @@ class Pry
62
68
  # @return [Pry::Method, nil]
63
69
  #
64
70
  def from_binding(b)
65
- meth_name = b.eval('__method__')
71
+ meth_name = b.eval('::Kernel.__method__')
66
72
  if [:__script__, nil].include?(meth_name)
67
73
  nil
68
74
  else
69
75
  method = begin
70
- new(b.eval("Object.instance_method(:method).bind(self).call(#{meth_name.to_s.inspect})"))
76
+ if Object === b.eval('self')
77
+ new(Kernel.instance_method(:method).bind(b.eval("self")).call(meth_name))
78
+ else
79
+ new(b.eval('class << self; self; end.instance_method(::Kernel.__method__).bind(self)'))
80
+ end
71
81
  rescue NameError, NoMethodError
72
82
  Disowned.new(b.eval('self'), meth_name.to_s)
73
83
  end
@@ -106,15 +116,32 @@ class Pry
106
116
  end
107
117
  end
108
118
 
119
+ # In order to support 2.0 Refinements we need to look up methods
120
+ # inside the relevant Binding.
121
+ # @param [Object] obj The owner/receiver of the method.
122
+ # @param [Symbol] method_name The name of the method.
123
+ # @param [Symbol] method_type The type of method: :method or :instance_method
124
+ # @param [Binding] target The binding where the method is looked up.
125
+ # @return [Method, UnboundMethod] The 'refined' method object.
126
+ def lookup_method_via_binding(obj, method_name, method_type, target=TOPLEVEL_BINDING)
127
+ Pry.current[:obj] = obj
128
+ Pry.current[:name] = method_name
129
+ receiver = obj.is_a?(Module) ? "Module" : "Kernel"
130
+ target.eval("::#{receiver}.instance_method(:#{method_type}).bind(Pry.current[:obj]).call(Pry.current[:name])")
131
+ ensure
132
+ Pry.current[:obj] = Pry.current[:name] = nil
133
+ end
134
+
109
135
  # Given a `Class` or `Module` and the name of a method, try to
110
136
  # instantiate a `Pry::Method` containing the instance method of
111
137
  # that name. Return `nil` if no such method exists.
112
138
  #
113
139
  # @param [Class, Module] klass
114
140
  # @param [String] name
141
+ # @param [Binding] target The binding where the method is looked up.
115
142
  # @return [Pry::Method, nil]
116
- def from_class(klass, name)
117
- new(safe_send(klass, :instance_method, name)) rescue nil
143
+ def from_class(klass, name, target=TOPLEVEL_BINDING)
144
+ new(lookup_method_via_binding(klass, name, :instance_method, target)) rescue nil
118
145
  end
119
146
  alias from_module from_class
120
147
 
@@ -124,9 +151,10 @@ class Pry
124
151
  #
125
152
  # @param [Object] obj
126
153
  # @param [String] name
154
+ # @param [Binding] target The binding where the method is looked up.
127
155
  # @return [Pry::Method, nil]
128
- def from_obj(obj, name)
129
- new(safe_send(obj, :method, name)) rescue nil
156
+ def from_obj(obj, name, target=TOPLEVEL_BINDING)
157
+ new(lookup_method_via_binding(obj, name, :method, target)) rescue nil
130
158
  end
131
159
 
132
160
  # Get all of the instance methods of a `Class` or `Module`
@@ -183,15 +211,6 @@ class Pry
183
211
  end.flatten(1)
184
212
  end
185
213
 
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)
192
- end
193
- public :safe_send
194
-
195
214
  # Get the singleton classes of superclasses that could define methods on
196
215
  # the given class object, and any modules they include.
197
216
  # If a module is included at multiple points in the ancestry, only
@@ -229,6 +248,12 @@ class Pry
229
248
  @wrapped_owner ||= Pry::WrappedModule.new(owner)
230
249
  end
231
250
 
251
+ # Get underlying object wrapped by this Pry::Method instance
252
+ # @return [Method, UnboundMethod, Proc]
253
+ def wrapped
254
+ @method
255
+ end
256
+
232
257
  # Is the method undefined? (aka `Disowned`)
233
258
  # @return [Boolean] false
234
259
  def undefined?
@@ -403,6 +428,24 @@ class Pry
403
428
  source_file == Pry.eval_path
404
429
  end
405
430
 
431
+ # @return [Array<String>] All known aliases for the method.
432
+ # @note On Ruby 1.8 this method always returns an empty Array for methods
433
+ # implemented in C.
434
+ def aliases
435
+ owner = @method.owner
436
+ # Avoid using `to_sym` on {Method#name}, which returns a `String`, because
437
+ # it won't be garbage collected.
438
+ name = @method.name
439
+
440
+ alias_list = owner.instance_methods.combination(2).select do |pair|
441
+ pair.include?(name) &&
442
+ owner.instance_method(pair.first) == owner.instance_method(pair.last)
443
+ end.flatten
444
+ alias_list.delete(name)
445
+
446
+ alias_list.map(&:to_s)
447
+ end
448
+
406
449
  # @return [Boolean] Is the method definitely an alias?
407
450
  def alias?
408
451
  name != original_name
@@ -475,7 +518,8 @@ class Pry
475
518
  end
476
519
  next_owner = ancestors[i] or return nil
477
520
  end
478
- next_owner.instance_method(name) rescue nil
521
+
522
+ safe_send(next_owner, :instance_method, name) rescue nil
479
523
  end
480
524
 
481
525
  # @param [String] first_ln The first line of a method definition.
@@ -8,18 +8,21 @@ class Pry
8
8
  # It provides access to the source, documentation, line and file
9
9
  # for a monkeypatch (reopening) of a class/module.
10
10
  class Candidate
11
+ include Pry::Helpers::DocumentationHelpers
12
+ include Pry::CodeObject::Helpers
11
13
  extend Forwardable
12
14
 
13
15
  # @return [String] The file where the module definition is located.
14
16
  attr_reader :file
17
+ alias_method :source_file, :file
15
18
 
16
19
  # @return [Fixnum] The line where the module definition is located.
17
20
  attr_reader :line
21
+ alias_method :source_line, :line
18
22
 
19
23
  # Methods to delegate to associated `Pry::WrappedModule instance`.
20
24
  to_delegate = [:lines_for_file, :method_candidates, :name, :wrapped,
21
- :yard_docs?, :number_of_candidates, :process_doc,
22
- :strip_leading_whitespace]
25
+ :yard_docs?, :number_of_candidates]
23
26
 
24
27
  def_delegators :@wrapper, *to_delegate
25
28
  private(*to_delegate)
@@ -61,7 +64,7 @@ class Pry
61
64
  return @doc if @doc
62
65
  raise CommandError, "Could not locate doc for #{wrapped}!" if file.nil?
63
66
 
64
- @doc = process_doc(Pry::Code.from_file(file).comment_describing(line))
67
+ @doc = strip_leading_hash_and_whitespace_from_ruby_comments(Pry::Code.from_file(file).comment_describing(line))
65
68
  end
66
69
 
67
70
  # @return [Array, nil] A `[String, Fixnum]` pair representing the
@@ -70,27 +73,35 @@ class Pry
70
73
  def source_location
71
74
  return @source_location if @source_location
72
75
 
73
- mod_type_string = wrapped.class.to_s.downcase
74
76
  file, line = first_method_source_location
75
-
76
77
  return nil if !file.is_a?(String)
77
78
 
78
- class_regexes = [/^\s*#{mod_type_string}\s*(\w*)(::)?#{wrapped.name.split(/::/).last}/,
79
- /^\s*(::)?#{wrapped.name.split(/::/).last}\s*?=\s*?#{wrapped.class}/,
80
- /^\s*(::)?#{wrapped.name.split(/::/).last}\.(class|instance)_eval/]
81
-
82
- host_file_lines = lines_for_file(file)
83
-
84
- search_lines = host_file_lines[0..(line - 2)]
85
- idx = search_lines.rindex { |v| class_regexes.any? { |r| r =~ v } }
86
-
87
- @source_location = [file, idx + 1]
79
+ @source_location = [file, first_line_of_module_definition(file, line)]
88
80
  rescue Pry::RescuableException
89
81
  nil
90
82
  end
91
83
 
92
84
  private
93
85
 
86
+ # Locate the first line of the module definition.
87
+ # @param [String] file The file that contains the module
88
+ # definition (somewhere).
89
+ # @param [Fixnum] line The module definition should appear
90
+ # before this line (if it exists).
91
+ # @return [Fixnum] The line where the module is defined. This
92
+ # line number is one-indexed.
93
+ def first_line_of_module_definition(file, line)
94
+ searchable_lines = lines_for_file(file)[0..(line - 2)]
95
+ searchable_lines.rindex { |v| class_regexes.any? { |r| r =~ v } } + 1
96
+ end
97
+
98
+ def class_regexes
99
+ mod_type_string = wrapped.class.to_s.downcase
100
+ [/^\s*#{mod_type_string}\s+(?:(?:\w*)::)*?#{wrapped.name.split(/::/).last}/,
101
+ /^\s*(::)?#{wrapped.name.split(/::/).last}\s*?=\s*?#{wrapped.class}/,
102
+ /^\s*(::)?#{wrapped.name.split(/::/).last}\.(class|instance)_eval/]
103
+ end
104
+
94
105
  # This method is used by `Candidate#source_location` as a
95
106
  # starting point for the search for the candidate's definition.
96
107
  # @return [Array] The source location of the base method used to