pry 0.9.6.2 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +6 -0
  2. data/CHANGELOG +19 -1
  3. data/CONTRIBUTORS +22 -16
  4. data/Rakefile +12 -6
  5. data/bin/pry +15 -12
  6. data/lib/pry.rb +39 -28
  7. data/lib/pry/command_context.rb +1 -0
  8. data/lib/pry/command_processor.rb +9 -2
  9. data/lib/pry/command_set.rb +7 -0
  10. data/lib/pry/config.rb +8 -0
  11. data/lib/pry/default_commands/basic.rb +7 -10
  12. data/lib/pry/default_commands/context.rb +36 -26
  13. data/lib/pry/default_commands/documentation.rb +31 -123
  14. data/lib/pry/default_commands/gems.rb +9 -4
  15. data/lib/pry/default_commands/input.rb +21 -11
  16. data/lib/pry/default_commands/introspection.rb +79 -88
  17. data/lib/pry/default_commands/ls.rb +165 -176
  18. data/lib/pry/default_commands/shell.rb +8 -8
  19. data/lib/pry/extended_commands/experimental.rb +1 -5
  20. data/lib/pry/extended_commands/user_command_api.rb +17 -5
  21. data/lib/pry/helpers.rb +1 -0
  22. data/lib/pry/helpers/base_helpers.rb +5 -1
  23. data/lib/pry/helpers/command_helpers.rb +22 -241
  24. data/lib/pry/helpers/options_helpers.rb +58 -0
  25. data/lib/pry/helpers/text.rb +10 -4
  26. data/lib/pry/history.rb +1 -1
  27. data/lib/pry/indent.rb +205 -0
  28. data/lib/pry/method.rb +412 -0
  29. data/lib/pry/pry_class.rb +56 -15
  30. data/lib/pry/pry_instance.rb +63 -16
  31. data/lib/pry/rbx_method.rb +20 -0
  32. data/lib/pry/rbx_path.rb +34 -0
  33. data/lib/pry/version.rb +1 -1
  34. data/pry.gemspec +16 -16
  35. data/test/helper.rb +8 -4
  36. data/test/test_command_helpers.rb +1 -69
  37. data/test/test_command_set.rb +29 -28
  38. data/test/test_default_commands/test_documentation.rb +23 -10
  39. data/test/test_default_commands/test_introspection.rb +58 -13
  40. data/test/test_default_commands/test_ls.rb +148 -0
  41. data/test/test_indent.rb +234 -0
  42. data/test/test_input_stack.rb +13 -0
  43. data/test/test_method.rb +291 -0
  44. data/test/test_pry.rb +10 -1
  45. metadata +82 -65
@@ -34,7 +34,7 @@ class Pry
34
34
  # @param [String] line
35
35
  # @return [String] The same line that was passed in
36
36
  def push(line)
37
- unless line.empty? || (@history.last && line.strip == @history.last.strip)
37
+ unless line.empty? || (@history.last && line == @history.last)
38
38
  Readline::HISTORY << line
39
39
  @history << line
40
40
  end
@@ -0,0 +1,205 @@
1
+ require 'coderay'
2
+
3
+ class Pry
4
+ ##
5
+ # Pry::Indent is a class that can be used to indent a number of lines
6
+ # containing Ruby code similar as to how IRB does it (but better). The class
7
+ # works by tokenizing a string using CodeRay and then looping over those
8
+ # tokens. Based on the tokens in a line of code that line (or the next one)
9
+ # will be indented or un-indented by correctly.
10
+ #
11
+ class Indent
12
+ # String containing the spaces to be inserted before the next line.
13
+ attr_reader :indent_level
14
+
15
+ # The amount of spaces to insert for each indent level.
16
+ SPACES = ' '
17
+
18
+ # Hash containing all the tokens that should increase the indentation
19
+ # level. The keys of this hash are open tokens, the values the matching
20
+ # tokens that should prevent a line from being indented if they appear on
21
+ # the same line.
22
+ OPEN_TOKENS = {
23
+ 'def' => 'end',
24
+ 'class' => 'end',
25
+ 'module' => 'end',
26
+ 'do' => 'end',
27
+ 'if' => 'end',
28
+ 'unless' => 'end',
29
+ 'while' => 'end',
30
+ 'until' => 'end',
31
+ 'for' => 'end',
32
+ 'case' => 'end',
33
+ 'begin' => 'end',
34
+ '[' => ']',
35
+ '{' => '}',
36
+ '(' => ')'
37
+ }
38
+
39
+ # Which tokens can either be open tokens, or appear as modifiers on
40
+ # a single-line.
41
+ SINGLELINE_TOKENS = %w(if while until unless rescue)
42
+
43
+ # Collection of token types that should be ignored. Without this list
44
+ # keywords such as "class" inside strings would cause the code to be
45
+ # indented incorrectly.
46
+ IGNORE_TOKENS = [:space, :content, :string, :delimiter, :method, :ident]
47
+
48
+ # Tokens that indicate the end of a statement (i.e. that, if they appear
49
+ # directly before an "if" indicates that that if applies to the same line,
50
+ # not the next line)
51
+ STATEMENT_END_TOKENS = IGNORE_TOKENS + [:regexp, :integer, :float]
52
+
53
+ # Collection of tokens that should appear dedented even though they
54
+ # don't affect the surrounding code.
55
+ MIDWAY_TOKENS = %w(when else elsif rescue)
56
+
57
+ def initialize
58
+ reset
59
+ end
60
+
61
+ # reset internal state
62
+ def reset
63
+ @stack = []
64
+ @indent_level = ''
65
+ self
66
+ end
67
+
68
+ # Indents a string and returns it. This string can either be a single line
69
+ # or multiple ones.
70
+ #
71
+ # @example
72
+ # str = <<TXT
73
+ # class User
74
+ # attr_accessor :name
75
+ # end
76
+ # TXT
77
+ #
78
+ # # This would result in the following being displayed:
79
+ # #
80
+ # # class User
81
+ # # attr_accessor :name
82
+ # # end
83
+ # #
84
+ # puts Pry::Indent.new.indent(str)
85
+ #
86
+ # @param [String] input The input string to indent.
87
+ # @return [String] The indented version of +input+.
88
+ #
89
+ def indent(input)
90
+ output = ''
91
+ open_tokens = OPEN_TOKENS.keys
92
+ prefix = indent_level
93
+
94
+ input.lines.each do |line|
95
+ tokens = CodeRay.scan(line, :ruby)
96
+ tokens = tokens.tokens.each_slice(2) if tokens.respond_to?(:tokens) # Coderay 1.0.0
97
+
98
+ before, after = indentation_delta(tokens)
99
+
100
+ before.times{ prefix.sub! SPACES, '' }
101
+ output += prefix + line.strip + "\n"
102
+ prefix += SPACES * after
103
+ end
104
+
105
+ @indent_level = prefix
106
+
107
+ return output.gsub(/\s+$/, '')
108
+ end
109
+
110
+ # Get the change in indentation indicated by the line.
111
+ #
112
+ # By convention, you remove indent from the line containing end tokens,
113
+ # but add indent to the line *after* that which contains the start tokens.
114
+ #
115
+ # This method returns a pair, where the first number is the number of closings
116
+ # on this line (i.e. the number of indents to remove before the line) and the
117
+ # second is the number of openings (i.e. the number of indents to add after
118
+ # this line)
119
+ #
120
+ # @param [Array] tokens A list of tokens to scan.
121
+ # @return [Array[Integer]]
122
+ #
123
+ def indentation_delta(tokens)
124
+
125
+ # We need to keep track of whether we've seen a "for" on this line because
126
+ # if the line ends with "do" then that "do" should be discounted (i.e. we're
127
+ # only opening one level not two) To do this robustly we want to keep track
128
+ # of the indent level at which we saw the for, so we can differentiate
129
+ # between "for x in [1,2,3] do" and "for x in ([1,2,3].map do" properly
130
+ seen_for_at = []
131
+
132
+ # When deciding whether an "if" token is the start of a multiline statement,
133
+ # or just the middle of a single-line if statement, we just look at the
134
+ # preceding token, which is tracked here.
135
+ last_token, last_kind = [nil, nil]
136
+
137
+ # delta keeps track of the total difference from the start of each line after
138
+ # the given token, 0 is just the level at which the current line started for
139
+ # reference.
140
+ remove_before, add_after = [0, 0]
141
+
142
+ # If the list of tokens contains a matching closing token the line should
143
+ # not be indented (and thus we should return true).
144
+ tokens.each do |token, kind|
145
+ is_singleline_if = (SINGLELINE_TOKENS.include?(token)) && end_of_statement?(last_token, last_kind)
146
+ is_optional_do = (token == "do" && seen_for_at.include?(add_after - 1))
147
+
148
+ last_token, last_kind = token, kind unless kind == :space
149
+ next if IGNORE_TOKENS.include?(kind)
150
+
151
+ seen_for_at << add_after if token == "for"
152
+
153
+ if OPEN_TOKENS.keys.include?(token) && !is_optional_do && !is_singleline_if
154
+ @stack << token
155
+ add_after += 1
156
+ elsif token == OPEN_TOKENS[@stack.last]
157
+ @stack.pop
158
+ if add_after == 0
159
+ remove_before += 1
160
+ else
161
+ add_after -= 1
162
+ end
163
+ elsif MIDWAY_TOKENS.include?(token)
164
+ if add_after == 0
165
+ remove_before += 1
166
+ add_after += 1
167
+ end
168
+ end
169
+ end
170
+
171
+ return [remove_before, add_after]
172
+ end
173
+
174
+ # If the code just before an "if" or "while" token on a line looks like the end of a statement,
175
+ # then we want to treat that "if" as a singleline, not multiline statement.
176
+ def end_of_statement?(last_token, last_kind)
177
+ (last_token =~ /^[)\]}\/]$/ || STATEMENT_END_TOKENS.include?(last_kind))
178
+ end
179
+
180
+ # Return a string which, when printed, will rewrite the previous line with
181
+ # the correct indentation. Mostly useful for fixing 'end'.
182
+ #
183
+ # @param [String] full_line The full line of input, including the prompt.
184
+ # @param [Fixnum] overhang (0) The number of chars to erase afterwards (i.e.,
185
+ # the difference in length between the old line and the new one).
186
+ # @return [String]
187
+ def correct_indentation(full_line, overhang=0)
188
+ if Readline.respond_to?(:get_screen_size)
189
+ _, cols = Readline.get_screen_size
190
+ lines = full_line.length / cols + 1
191
+ elsif ENV['COLUMNS'] && ENV['COLUMNS'] != ''
192
+ cols = ENV['COLUMNS'].to_i
193
+ lines = full_line.length / cols + 1
194
+ else
195
+ lines = 1
196
+ end
197
+
198
+ move_up = "\e[#{lines}F"
199
+ whitespace = ' ' * overhang
200
+ move_down = "\e[#{lines}E"
201
+
202
+ "#{move_up}#{full_line}#{whitespace}#{move_down}"
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,412 @@
1
+ class Pry
2
+ class Method
3
+ include RbxMethod if Helpers::BaseHelpers.rbx?
4
+
5
+ class << self
6
+ # Given a string representing a method name and optionally a binding to
7
+ # search in, find and return the requested method wrapped in a `Pry::Method`
8
+ # instance.
9
+ #
10
+ # @param [String, nil] name The name of the method to retrieve, or `nil` to
11
+ # delegate to `from_binding` instead.
12
+ # @param [Binding] target The context in which to search for the method.
13
+ # @param [Hash] options
14
+ # @option options [Boolean] :instance Look for an instance method if `name` doesn't
15
+ # contain any context.
16
+ # @option options [Boolean] :methods Look for a bound/singleton method if `name` doesn't
17
+ # contain any context.
18
+ # @return [Pry::Method, nil] A `Pry::Method` instance containing the requested
19
+ # method, or `nil` if no method could be located matching the parameters.
20
+ def from_str(name, target=TOPLEVEL_BINDING, options={})
21
+ if name.nil?
22
+ from_binding(target)
23
+ elsif name.to_s =~ /(.+)\#(\S+)\Z/
24
+ context, meth_name = $1, $2
25
+ from_module(target.eval(context), meth_name)
26
+ elsif name.to_s =~ /(.+)\.(\S+)\Z/
27
+ context, meth_name = $1, $2
28
+ from_obj(target.eval(context), meth_name)
29
+ elsif options[:instance]
30
+ from_module(target.eval("self"), name)
31
+ elsif options[:methods]
32
+ from_obj(target.eval("self"), name)
33
+ else
34
+ from_str(name, target, :instance => true) or
35
+ from_str(name, target, :methods => true)
36
+ end
37
+ end
38
+
39
+ # Given a `Binding`, try to extract the `::Method` it originated from and
40
+ # use it to instantiate a `Pry::Method`. Return `nil` if this isn't
41
+ # possible.
42
+ #
43
+ # @param [Binding] b
44
+ # @return [Pry::Method, nil]
45
+ #
46
+ def from_binding(b)
47
+ meth_name = b.eval('__method__')
48
+ if [:__script__, nil, :__binding__, :__binding_impl__].include?(meth_name)
49
+ nil
50
+ else
51
+ new(b.eval("method(:#{meth_name})"))
52
+ end
53
+ end
54
+
55
+ # Given a `Class` or `Module` and the name of a method, try to
56
+ # instantiate a `Pry::Method` containing the instance method of
57
+ # that name. Return `nil` if no such method exists.
58
+ #
59
+ # @param [Class, Module] klass
60
+ # @param [String] name
61
+ # @return [Pry::Method, nil]
62
+ def from_class(klass, name)
63
+ new(klass.instance_method(name)) rescue nil
64
+ end
65
+ alias from_module from_class
66
+
67
+ # Given an object and the name of a method, try to instantiate
68
+ # a `Pry::Method` containing the method of that name bound to
69
+ # that object. Return `nil` if no such method exists.
70
+ #
71
+ # @param [Object] obj
72
+ # @param [String] name
73
+ # @return [Pry::Method, nil]
74
+ def from_obj(obj, name)
75
+ new(obj.method(name)) rescue nil
76
+ end
77
+
78
+ # Get all of the instance methods of a `Class` or `Module`
79
+ # @param [Class,Module] klass
80
+ # @return [Array[Pry::Method]]
81
+ def all_from_class(klass)
82
+ all_from_common(klass, :instance_method)
83
+ end
84
+
85
+ # Get all of the methods on an `Object`
86
+ # @param [Object] obj
87
+ # @return [Array[Pry::Method]]
88
+ def all_from_obj(obj)
89
+ all_from_common(obj, :method)
90
+ end
91
+
92
+ # Get every `Class` and `Module`, in order, that will be checked when looking
93
+ # for an instance method to call on this object.
94
+ # @param [Object] obj
95
+ # @return [Array[Class, Module]]
96
+ def resolution_order(obj)
97
+ if Class === obj
98
+ singleton_class_resolution_order(obj) + instance_resolution_order(Class)
99
+ else
100
+ klass = singleton_class(obj) rescue obj.class
101
+ instance_resolution_order(klass)
102
+ end
103
+ end
104
+
105
+ # Get every `Class` and `Module`, in order, that will be checked when looking
106
+ # for methods on instances of the given `Class` or `Module`.
107
+ # This does not treat singleton classes of classes specially.
108
+ # @param [Class, Module] klass
109
+ # @return [Array[Class, Module]]
110
+ def instance_resolution_order(klass)
111
+ # include klass in case it is a singleton class,
112
+ ([klass] + klass.ancestors).uniq
113
+ end
114
+
115
+ private
116
+
117
+ # See all_from_class and all_from_obj.
118
+ # If method_type is :instance_method, obj must be a `Class` or a `Module`
119
+ # If method_type is :method, obj can be any `Object`
120
+ #
121
+ # N.B. we pre-cache the visibility here to avoid O(N²) behaviour in "ls".
122
+ def all_from_common(obj, method_type)
123
+ %w(public protected private).map do |visibility|
124
+ safe_send(obj, :"#{visibility}_#{method_type}s").map do |method_name|
125
+ new(safe_send(obj, method_type, method_name), :visibility => visibility.to_sym)
126
+ end
127
+ end.flatten(1)
128
+ end
129
+
130
+ # Acts like send but ignores any methods defined below Object or Class in the
131
+ # inheritance heirarchy.
132
+ # This is required to introspect methods on objects like Net::HTTP::Get that
133
+ # have overridden the `method` method.
134
+ def safe_send(obj, method, *args, &block)
135
+ (Class === obj ? Class : Object).instance_method(method).bind(obj).call(*args, &block)
136
+ end
137
+
138
+ # Get the singleton classes of superclasses that could define methods on
139
+ # the given class object, and any modules they include.
140
+ # If a module is included at multiple points in the ancestry, only
141
+ # the lowest copy will be returned.
142
+ def singleton_class_resolution_order(klass)
143
+ resolution_order = klass.ancestors.map do |anc|
144
+ [singleton_class(anc)] + singleton_class(anc).included_modules if anc.is_a?(Class)
145
+ end.compact.flatten(1)
146
+
147
+ resolution_order.reverse.uniq.reverse - Class.included_modules
148
+ end
149
+
150
+ def singleton_class(obj); class << obj; self; end end
151
+ end
152
+
153
+ # A new instance of `Pry::Method` wrapping the given `::Method`, `UnboundMethod`, or `Proc`.
154
+ #
155
+ # @param [::Method, UnboundMethod, Proc] method
156
+ # @param [Hash] known_info, can be used to pre-cache expensive to compute stuff.
157
+ # @return [Pry::Method]
158
+ def initialize(method, known_info={})
159
+ @method = method
160
+ @visibility = known_info[:visibility]
161
+ end
162
+
163
+ # Get the name of the method as a String, regardless of the underlying Method#name type.
164
+ # @return [String]
165
+ def name
166
+ @method.name.to_s
167
+ end
168
+
169
+ # @return [String, nil] The source code of the method, or `nil` if it's unavailable.
170
+ def source
171
+ @source ||= case source_type
172
+ when :c
173
+ info = pry_doc_info
174
+ if info and info.source
175
+ code = strip_comments_from_c_code(info.source)
176
+ end
177
+ when :rbx
178
+ strip_leading_whitespace(core_code)
179
+ when :ruby
180
+ if pry_method?
181
+ code = Pry.new(:input => StringIO.new(Pry.line_buffer[source_line..-1].join), :prompt => proc {""}, :hooks => {}).r
182
+ else
183
+ code = @method.source
184
+ end
185
+ strip_leading_whitespace(code)
186
+ end
187
+ end
188
+
189
+ # @return [String, nil] The documentation for the method, or `nil` if it's
190
+ # unavailable.
191
+ # @raise [CommandError] Raises when the method was defined in the REPL.
192
+ def doc
193
+ @doc ||= case source_type
194
+ when :c
195
+ info = pry_doc_info
196
+ info.docstring if info
197
+ when :rbx
198
+ strip_leading_hash_and_whitespace_from_ruby_comments(core_doc)
199
+ when :ruby
200
+ if pry_method?
201
+ raise CommandError, "Can't view doc for a REPL-defined method."
202
+ else
203
+ strip_leading_hash_and_whitespace_from_ruby_comments(@method.comment)
204
+ end
205
+ end
206
+ end
207
+
208
+ # @return [Symbol] The source type of the method. The options are
209
+ # `:ruby` for ordinary Ruby methods, `:c` for methods written in
210
+ # C, or `:rbx` for Rubinius core methods written in Ruby.
211
+ def source_type
212
+ if Helpers::BaseHelpers.rbx?
213
+ if core? then :rbx else :ruby end
214
+ else
215
+ if source_location.nil? then :c else :ruby end
216
+ end
217
+ end
218
+
219
+ # @return [String, nil] The name of the file the method is defined in, or
220
+ # `nil` if the filename is unavailable.
221
+ def source_file
222
+ if source_location.nil?
223
+ if !Helpers::BaseHelpers.rbx? and source_type == :c
224
+ info = pry_doc_info
225
+ info.file if info
226
+ end
227
+ else
228
+ source_location.first
229
+ end
230
+ end
231
+
232
+ # @return [Fixnum, nil] The line of code in `source_file` which begins
233
+ # the method's definition, or `nil` if that information is unavailable.
234
+ def source_line
235
+ source_location.nil? ? nil : source_location.last
236
+ end
237
+
238
+ # @return [Symbol] The visibility of the method. May be `:public`,
239
+ # `:protected`, or `:private`.
240
+ def visibility
241
+ @visibility ||= if owner.public_instance_methods.any? { |m| m.to_s == name }
242
+ :public
243
+ elsif owner.protected_instance_methods.any? { |m| m.to_s == name }
244
+ :protected
245
+ elsif owner.private_instance_methods.any? { |m| m.to_s == name }
246
+ :private
247
+ else
248
+ :none
249
+ end
250
+ end
251
+
252
+ # @return [String] A representation of the method's signature, including its
253
+ # name and parameters. Optional and "rest" parameters are marked with `*`
254
+ # and block parameters with `&`. If the parameter names are unavailable,
255
+ # they're given numbered names instead.
256
+ # Paraphrased from `awesome_print` gem.
257
+ def signature
258
+ if respond_to?(:parameters)
259
+ args = parameters.inject([]) do |arr, (type, name)|
260
+ name ||= (type == :block ? 'block' : "arg#{arr.size + 1}")
261
+ arr << case type
262
+ when :req then name.to_s
263
+ when :opt, :rest then "*#{name}"
264
+ when :block then "&#{name}"
265
+ else '?'
266
+ end
267
+ end
268
+ else
269
+ args = (1..arity.abs).map { |i| "arg#{i}" }
270
+ args[-1] = "*#{args[-1]}" if arity < 0
271
+ end
272
+
273
+ "#{name}(#{args.join(', ')})"
274
+ end
275
+
276
+ # @return [Pry::Method, nil] The wrapped method that is called when you
277
+ # use "super" in the body of this method.
278
+ def super(times=1)
279
+ if respond_to?(:receiver)
280
+ sup = super_using_ancestors(Pry::Method.resolution_order(receiver), times)
281
+ sup &&= sup.bind(receiver)
282
+ else
283
+ sup = super_using_ancestors(Pry::Method.instance_resolution_order(owner), times)
284
+ end
285
+ Pry::Method.new(sup) if sup
286
+ end
287
+
288
+ # @return [Symbol, nil] The original name the method was defined under,
289
+ # before any aliasing, or `nil` if it can't be determined.
290
+ def original_name
291
+ return nil if source_type != :ruby
292
+
293
+ first_line = source.lines.first
294
+ return nil if first_line.strip !~ /^def /
295
+
296
+ if RUBY_VERSION =~ /^1\.9/ && RUBY_ENGINE == "ruby"
297
+ require 'ripper'
298
+
299
+ # Ripper is ok with an extraneous end, so we don't need to worry about
300
+ # whether it's a one-liner.
301
+ tree = Ripper::SexpBuilder.new(first_line + ";end").parse
302
+
303
+ name = tree.flatten(2).each do |lst|
304
+ break lst[1] if lst[0] == :@ident
305
+ end
306
+
307
+ name.is_a?(String) ? name : nil
308
+ else
309
+ require 'ruby_parser'
310
+
311
+ # RubyParser breaks if there's an extra end, so we'll just rescue
312
+ # and try again.
313
+ tree = begin
314
+ RubyParser.new.parse(first_line + ";end")
315
+ rescue Racc::ParseError
316
+ RubyParser.new.parse(first_line)
317
+ end
318
+
319
+ name = tree.each_cons(2) do |a, b|
320
+ break a if b.is_a?(Array) && b.first == :args
321
+ end
322
+
323
+ name.is_a?(Symbol) ? name.to_s : nil
324
+ end
325
+ end
326
+
327
+ # @return [Boolean] Was the method defined outside a source file?
328
+ def dynamically_defined?
329
+ !!(source_file and source_file =~ /(\(.*\))|<.*>/)
330
+ end
331
+
332
+ # @return [Boolean] Was the method defined within the Pry REPL?
333
+ def pry_method?
334
+ source_file == Pry.eval_path
335
+ end
336
+
337
+ # @return [Boolean] Is the method definitely an alias?
338
+ def alias?
339
+ name != original_name
340
+ end
341
+
342
+ # @return [Boolean]
343
+ def ==(obj)
344
+ if obj.is_a? Pry::Method
345
+ super
346
+ else
347
+ @method == obj
348
+ end
349
+ end
350
+
351
+ # @param [Class] klass
352
+ # @return [Boolean]
353
+ def is_a?(klass)
354
+ klass == Pry::Method or @method.is_a?(klass)
355
+ end
356
+ alias kind_of? is_a?
357
+
358
+ # @param [String, Symbol] method_name
359
+ # @return [Boolean]
360
+ def respond_to?(method_name)
361
+ super or @method.respond_to?(method_name)
362
+ end
363
+
364
+ # Delegate any unknown calls to the wrapped method.
365
+ def method_missing(method_name, *args, &block)
366
+ @method.send(method_name, *args, &block)
367
+ end
368
+
369
+ private
370
+ # @return [YARD::CodeObjects::MethodObject]
371
+ # @raise [CommandError] Raises when the method can't be found or `pry-doc` isn't installed.
372
+ def pry_doc_info
373
+ if Pry.config.has_pry_doc
374
+ Pry::MethodInfo.info_for(@method) or raise CommandError, "Cannot locate this method: #{name}."
375
+ else
376
+ raise CommandError, "Cannot locate this method: #{name}. Try `gem install pry-doc` to get access to Ruby Core documentation."
377
+ end
378
+ end
379
+
380
+ # @param [String] code
381
+ # @return [String]
382
+ def strip_comments_from_c_code(code)
383
+ code.sub(/\A\s*\/\*.*?\*\/\s*/m, '')
384
+ end
385
+
386
+ # @param [String] comment
387
+ # @return [String]
388
+ def strip_leading_hash_and_whitespace_from_ruby_comments(comment)
389
+ comment = comment.dup
390
+ comment.gsub!(/\A\#+?$/, '')
391
+ comment.gsub!(/^\s*#/, '')
392
+ strip_leading_whitespace(comment)
393
+ end
394
+
395
+ # @param [String] text
396
+ # @return [String]
397
+ def strip_leading_whitespace(text)
398
+ Pry::Helpers::CommandHelpers.unindent(text)
399
+ end
400
+
401
+ # @param [Class,Module] the ancestors to investigate
402
+ # @return [Method] the unwrapped super-method
403
+ def super_using_ancestors(ancestors, times=1)
404
+ next_owner = self.owner
405
+ times.times do
406
+ next_owner = ancestors[ancestors.index(next_owner) + 1]
407
+ return nil unless next_owner
408
+ end
409
+ next_owner.instance_method(name) rescue nil
410
+ end
411
+ end
412
+ end