super-smart-mod 0.0.1

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 (143) hide show
  1. checksums.yaml +7 -0
  2. data/pry-0.16.0/CHANGELOG.md +1211 -0
  3. data/pry-0.16.0/LICENSE +25 -0
  4. data/pry-0.16.0/README.md +469 -0
  5. data/pry-0.16.0/bin/pry +13 -0
  6. data/pry-0.16.0/lib/pry/basic_object.rb +10 -0
  7. data/pry-0.16.0/lib/pry/block_command.rb +22 -0
  8. data/pry-0.16.0/lib/pry/class_command.rb +194 -0
  9. data/pry-0.16.0/lib/pry/cli.rb +211 -0
  10. data/pry-0.16.0/lib/pry/code/code_file.rb +114 -0
  11. data/pry-0.16.0/lib/pry/code/code_range.rb +73 -0
  12. data/pry-0.16.0/lib/pry/code/loc.rb +105 -0
  13. data/pry-0.16.0/lib/pry/code.rb +357 -0
  14. data/pry-0.16.0/lib/pry/code_object.rb +197 -0
  15. data/pry-0.16.0/lib/pry/color_printer.rb +66 -0
  16. data/pry-0.16.0/lib/pry/command.rb +520 -0
  17. data/pry-0.16.0/lib/pry/command_set.rb +418 -0
  18. data/pry-0.16.0/lib/pry/command_state.rb +36 -0
  19. data/pry-0.16.0/lib/pry/commands/amend_line.rb +103 -0
  20. data/pry-0.16.0/lib/pry/commands/bang.rb +24 -0
  21. data/pry-0.16.0/lib/pry/commands/bang_pry.rb +21 -0
  22. data/pry-0.16.0/lib/pry/commands/cat/abstract_formatter.rb +32 -0
  23. data/pry-0.16.0/lib/pry/commands/cat/exception_formatter.rb +90 -0
  24. data/pry-0.16.0/lib/pry/commands/cat/file_formatter.rb +77 -0
  25. data/pry-0.16.0/lib/pry/commands/cat/input_expression_formatter.rb +48 -0
  26. data/pry-0.16.0/lib/pry/commands/cat.rb +70 -0
  27. data/pry-0.16.0/lib/pry/commands/cd.rb +48 -0
  28. data/pry-0.16.0/lib/pry/commands/change_inspector.rb +34 -0
  29. data/pry-0.16.0/lib/pry/commands/change_prompt.rb +51 -0
  30. data/pry-0.16.0/lib/pry/commands/clear_screen.rb +20 -0
  31. data/pry-0.16.0/lib/pry/commands/code_collector.rb +182 -0
  32. data/pry-0.16.0/lib/pry/commands/disable_pry.rb +31 -0
  33. data/pry-0.16.0/lib/pry/commands/easter_eggs.rb +101 -0
  34. data/pry-0.16.0/lib/pry/commands/edit/exception_patcher.rb +29 -0
  35. data/pry-0.16.0/lib/pry/commands/edit/file_and_line_locator.rb +47 -0
  36. data/pry-0.16.0/lib/pry/commands/edit.rb +225 -0
  37. data/pry-0.16.0/lib/pry/commands/exit.rb +47 -0
  38. data/pry-0.16.0/lib/pry/commands/exit_all.rb +33 -0
  39. data/pry-0.16.0/lib/pry/commands/exit_program.rb +27 -0
  40. data/pry-0.16.0/lib/pry/commands/find_method.rb +199 -0
  41. data/pry-0.16.0/lib/pry/commands/fix_indent.rb +23 -0
  42. data/pry-0.16.0/lib/pry/commands/help.rb +171 -0
  43. data/pry-0.16.0/lib/pry/commands/hist.rb +182 -0
  44. data/pry-0.16.0/lib/pry/commands/import_set.rb +27 -0
  45. data/pry-0.16.0/lib/pry/commands/jump_to.rb +33 -0
  46. data/pry-0.16.0/lib/pry/commands/list_inspectors.rb +42 -0
  47. data/pry-0.16.0/lib/pry/commands/ls/config.rb +54 -0
  48. data/pry-0.16.0/lib/pry/commands/ls/constants.rb +75 -0
  49. data/pry-0.16.0/lib/pry/commands/ls/formatter.rb +55 -0
  50. data/pry-0.16.0/lib/pry/commands/ls/globals.rb +50 -0
  51. data/pry-0.16.0/lib/pry/commands/ls/grep.rb +23 -0
  52. data/pry-0.16.0/lib/pry/commands/ls/instance_vars.rb +40 -0
  53. data/pry-0.16.0/lib/pry/commands/ls/interrogatable.rb +24 -0
  54. data/pry-0.16.0/lib/pry/commands/ls/jruby_hacks.rb +55 -0
  55. data/pry-0.16.0/lib/pry/commands/ls/local_names.rb +37 -0
  56. data/pry-0.16.0/lib/pry/commands/ls/local_vars.rb +47 -0
  57. data/pry-0.16.0/lib/pry/commands/ls/ls_entity.rb +65 -0
  58. data/pry-0.16.0/lib/pry/commands/ls/methods.rb +55 -0
  59. data/pry-0.16.0/lib/pry/commands/ls/methods_helper.rb +50 -0
  60. data/pry-0.16.0/lib/pry/commands/ls/self_methods.rb +34 -0
  61. data/pry-0.16.0/lib/pry/commands/ls.rb +114 -0
  62. data/pry-0.16.0/lib/pry/commands/nesting.rb +29 -0
  63. data/pry-0.16.0/lib/pry/commands/play.rb +113 -0
  64. data/pry-0.16.0/lib/pry/commands/pry_backtrace.rb +30 -0
  65. data/pry-0.16.0/lib/pry/commands/pry_version.rb +21 -0
  66. data/pry-0.16.0/lib/pry/commands/raise_up.rb +38 -0
  67. data/pry-0.16.0/lib/pry/commands/reload_code.rb +74 -0
  68. data/pry-0.16.0/lib/pry/commands/reset.rb +22 -0
  69. data/pry-0.16.0/lib/pry/commands/ri.rb +75 -0
  70. data/pry-0.16.0/lib/pry/commands/save_file.rb +63 -0
  71. data/pry-0.16.0/lib/pry/commands/shell_command.rb +75 -0
  72. data/pry-0.16.0/lib/pry/commands/shell_mode.rb +30 -0
  73. data/pry-0.16.0/lib/pry/commands/show_doc.rb +84 -0
  74. data/pry-0.16.0/lib/pry/commands/show_info.rb +234 -0
  75. data/pry-0.16.0/lib/pry/commands/show_input.rb +22 -0
  76. data/pry-0.16.0/lib/pry/commands/show_source.rb +57 -0
  77. data/pry-0.16.0/lib/pry/commands/stat.rb +44 -0
  78. data/pry-0.16.0/lib/pry/commands/switch_to.rb +29 -0
  79. data/pry-0.16.0/lib/pry/commands/toggle_color.rb +28 -0
  80. data/pry-0.16.0/lib/pry/commands/watch_expression/expression.rb +43 -0
  81. data/pry-0.16.0/lib/pry/commands/watch_expression.rb +108 -0
  82. data/pry-0.16.0/lib/pry/commands/whereami.rb +205 -0
  83. data/pry-0.16.0/lib/pry/commands/wtf.rb +95 -0
  84. data/pry-0.16.0/lib/pry/config/attributable.rb +22 -0
  85. data/pry-0.16.0/lib/pry/config/lazy_value.rb +29 -0
  86. data/pry-0.16.0/lib/pry/config/memoized_value.rb +34 -0
  87. data/pry-0.16.0/lib/pry/config/value.rb +24 -0
  88. data/pry-0.16.0/lib/pry/config.rb +321 -0
  89. data/pry-0.16.0/lib/pry/control_d_handler.rb +28 -0
  90. data/pry-0.16.0/lib/pry/core_extensions.rb +144 -0
  91. data/pry-0.16.0/lib/pry/editor.rb +157 -0
  92. data/pry-0.16.0/lib/pry/env.rb +18 -0
  93. data/pry-0.16.0/lib/pry/exception_handler.rb +48 -0
  94. data/pry-0.16.0/lib/pry/exceptions.rb +73 -0
  95. data/pry-0.16.0/lib/pry/forwardable.rb +27 -0
  96. data/pry-0.16.0/lib/pry/helpers/base_helpers.rb +71 -0
  97. data/pry-0.16.0/lib/pry/helpers/command_helpers.rb +146 -0
  98. data/pry-0.16.0/lib/pry/helpers/documentation_helpers.rb +84 -0
  99. data/pry-0.16.0/lib/pry/helpers/options_helpers.rb +34 -0
  100. data/pry-0.16.0/lib/pry/helpers/platform.rb +55 -0
  101. data/pry-0.16.0/lib/pry/helpers/table.rb +121 -0
  102. data/pry-0.16.0/lib/pry/helpers/text.rb +118 -0
  103. data/pry-0.16.0/lib/pry/helpers.rb +8 -0
  104. data/pry-0.16.0/lib/pry/history.rb +153 -0
  105. data/pry-0.16.0/lib/pry/hooks.rb +180 -0
  106. data/pry-0.16.0/lib/pry/indent.rb +414 -0
  107. data/pry-0.16.0/lib/pry/input/simple_stdio.rb +13 -0
  108. data/pry-0.16.0/lib/pry/input_completer.rb +283 -0
  109. data/pry-0.16.0/lib/pry/input_lock.rb +129 -0
  110. data/pry-0.16.0/lib/pry/inspector.rb +39 -0
  111. data/pry-0.16.0/lib/pry/last_exception.rb +61 -0
  112. data/pry-0.16.0/lib/pry/method/disowned.rb +67 -0
  113. data/pry-0.16.0/lib/pry/method/patcher.rb +131 -0
  114. data/pry-0.16.0/lib/pry/method/weird_method_locator.rb +222 -0
  115. data/pry-0.16.0/lib/pry/method.rb +599 -0
  116. data/pry-0.16.0/lib/pry/object_path.rb +91 -0
  117. data/pry-0.16.0/lib/pry/output.rb +136 -0
  118. data/pry-0.16.0/lib/pry/pager.rb +249 -0
  119. data/pry-0.16.0/lib/pry/prompt.rb +214 -0
  120. data/pry-0.16.0/lib/pry/pry_class.rb +371 -0
  121. data/pry-0.16.0/lib/pry/pry_instance.rb +663 -0
  122. data/pry-0.16.0/lib/pry/repl.rb +326 -0
  123. data/pry-0.16.0/lib/pry/repl_file_loader.rb +79 -0
  124. data/pry-0.16.0/lib/pry/ring.rb +89 -0
  125. data/pry-0.16.0/lib/pry/slop/LICENSE +20 -0
  126. data/pry-0.16.0/lib/pry/slop/commands.rb +190 -0
  127. data/pry-0.16.0/lib/pry/slop/option.rb +210 -0
  128. data/pry-0.16.0/lib/pry/slop.rb +672 -0
  129. data/pry-0.16.0/lib/pry/syntax_highlighter.rb +26 -0
  130. data/pry-0.16.0/lib/pry/system_command_handler.rb +17 -0
  131. data/pry-0.16.0/lib/pry/testable/evalable.rb +24 -0
  132. data/pry-0.16.0/lib/pry/testable/mockable.rb +22 -0
  133. data/pry-0.16.0/lib/pry/testable/pry_tester.rb +88 -0
  134. data/pry-0.16.0/lib/pry/testable/utility.rb +34 -0
  135. data/pry-0.16.0/lib/pry/testable/variables.rb +52 -0
  136. data/pry-0.16.0/lib/pry/testable.rb +68 -0
  137. data/pry-0.16.0/lib/pry/version.rb +5 -0
  138. data/pry-0.16.0/lib/pry/warning.rb +20 -0
  139. data/pry-0.16.0/lib/pry/wrapped_module/candidate.rb +145 -0
  140. data/pry-0.16.0/lib/pry/wrapped_module.rb +382 -0
  141. data/pry-0.16.0/lib/pry.rb +148 -0
  142. data/super-smart-mod.gemspec +12 -0
  143. metadata +182 -0
@@ -0,0 +1,599 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'method_source'
4
+
5
+ class Pry
6
+ class << self
7
+ # If the given object is a `Pry::Method`, return it unaltered. If it's
8
+ # anything else, return it wrapped in a `Pry::Method` instance.
9
+ def Method(obj)
10
+ if obj.is_a? Pry::Method
11
+ obj
12
+ else
13
+ Pry::Method.new(obj)
14
+ end
15
+ end
16
+ end
17
+
18
+ # This class wraps the normal `Method` and `UnboundMethod` classes
19
+ # to provide extra functionality useful to Pry.
20
+ class Method # rubocop:disable Metrics/ClassLength
21
+ extend Helpers::BaseHelpers
22
+ extend Forwardable
23
+
24
+ include Helpers::BaseHelpers
25
+ include Helpers::DocumentationHelpers
26
+ include CodeObject::Helpers
27
+
28
+ class << self
29
+ # Given a string representing a method name and optionally a binding to
30
+ # search in, find and return the requested method wrapped in a
31
+ # `Pry::Method` instance.
32
+ #
33
+ # @param [String] name The name of the method to retrieve.
34
+ # @param [Binding] target The context in which to search for the method.
35
+ # @param [Hash] options
36
+ # @option options [Boolean] :instance Look for an instance method if
37
+ # `name` doesn't contain any context.
38
+ # @option options [Boolean] :methods Look for a bound/singleton method if
39
+ # `name` doesn't contain any context.
40
+ # @return [Pry::Method, nil] A `Pry::Method` instance containing the
41
+ # requested method, or `nil` if name is `nil` or no method could be
42
+ # located matching the parameters.
43
+ def from_str(name, target = TOPLEVEL_BINDING, options = {})
44
+ if name.nil?
45
+ nil
46
+ elsif name.to_s =~ /(.+)\#(\S+)\Z/
47
+ context = Regexp.last_match(1)
48
+ meth_name = Regexp.last_match(2)
49
+ from_module(target.eval(context), meth_name, target)
50
+ elsif name.to_s =~ /(.+)(\[\])\Z/
51
+ context = Regexp.last_match(1)
52
+ meth_name = Regexp.last_match(2)
53
+ from_obj(target.eval(context), meth_name, target)
54
+ elsif name.to_s =~ /(.+)(\.|::)(\S+)\Z/
55
+ context = Regexp.last_match(1)
56
+ meth_name = Regexp.last_match(3)
57
+ from_obj(target.eval(context), meth_name, target)
58
+ elsif options[:instance]
59
+ from_module(target.eval("self"), name, target)
60
+ elsif options[:methods]
61
+ from_obj(target.eval("self"), name, target)
62
+ else
63
+ from_str(name, target, instance: true) ||
64
+ from_str(name, target, methods: true)
65
+ end
66
+ rescue Pry::RescuableException
67
+ nil
68
+ end
69
+
70
+ # Given a `Binding`, try to extract the `::Method` it originated from and
71
+ # use it to instantiate a `Pry::Method`. Return `nil` if this isn't
72
+ # possible.
73
+ #
74
+ # @param [Binding] binding
75
+ # @return [Pry::Method, nil]
76
+ #
77
+ def from_binding(binding)
78
+ meth_name = binding.eval('::Kernel.__method__')
79
+ if [:__script__, nil].include?(meth_name)
80
+ nil
81
+ else
82
+ method =
83
+ begin
84
+ if Object === binding.eval('self') # rubocop:disable Style/CaseEquality
85
+ new(
86
+ Kernel.instance_method(:method)
87
+ .bind(binding.eval("self"))
88
+ .call(meth_name)
89
+ )
90
+ else
91
+ str = 'class << self; self; end' \
92
+ '.instance_method(::Kernel.__method__).bind(self)'
93
+ new(binding.eval(str))
94
+ end
95
+ rescue NameError, NoMethodError # rubocop:disable Lint/ShadowedException
96
+ Disowned.new(binding.eval('self'), meth_name.to_s)
97
+ end
98
+
99
+ if WeirdMethodLocator.weird_method?(method, binding)
100
+ WeirdMethodLocator.new(method, binding).find_method || method
101
+ else
102
+ method
103
+ end
104
+ end
105
+ end
106
+
107
+ # In order to support 2.0 Refinements we need to look up methods
108
+ # inside the relevant Binding.
109
+ # @param [Object] obj The owner/receiver of the method.
110
+ # @param [Symbol] method_name The name of the method.
111
+ # @param [Symbol] method_type The type of method: :method or :instance_method
112
+ # @param [Binding] target The binding where the method is looked up.
113
+ # @return [Method, UnboundMethod] The 'refined' method object.
114
+ def lookup_method_via_binding(
115
+ obj, method_name, method_type, target = TOPLEVEL_BINDING
116
+ )
117
+ Pry.current[:obj] = obj
118
+ Pry.current[:name] = method_name
119
+ receiver = obj.is_a?(Module) ? "Module" : "Kernel"
120
+ target.eval(
121
+ "::#{receiver}.instance_method(:#{method_type})" \
122
+ ".bind(Pry.current[:obj]).call(Pry.current[:name])"
123
+ )
124
+ ensure
125
+ Pry.current[:obj] = Pry.current[:name] = nil
126
+ end
127
+
128
+ # Given a `Class` or `Module` and the name of a method, try to
129
+ # instantiate a `Pry::Method` containing the instance method of
130
+ # that name. Return `nil` if no such method exists.
131
+ #
132
+ # @param [Class, Module] klass
133
+ # @param [String] name
134
+ # @param [Binding] target The binding where the method is looked up.
135
+ # @return [Pry::Method, nil]
136
+ def from_class(klass, name, target = TOPLEVEL_BINDING)
137
+ new(lookup_method_via_binding(klass, name, :instance_method, target))
138
+ rescue StandardError
139
+ nil
140
+ end
141
+ alias from_module from_class
142
+
143
+ # Given an object and the name of a method, try to instantiate
144
+ # a `Pry::Method` containing the method of that name bound to
145
+ # that object. Return `nil` if no such method exists.
146
+ #
147
+ # @param [Object] obj
148
+ # @param [String] name
149
+ # @param [Binding] target The binding where the method is looked up.
150
+ # @return [Pry::Method, nil]
151
+ def from_obj(obj, name, target = TOPLEVEL_BINDING)
152
+ new(lookup_method_via_binding(obj, name, :method, target))
153
+ rescue StandardError
154
+ nil
155
+ end
156
+
157
+ # Get all of the instance methods of a `Class` or `Module`
158
+ # @param [Class,Module] klass
159
+ # @param [Boolean] include_super Whether to include methods from ancestors.
160
+ # @return [Array[Pry::Method]]
161
+ def all_from_class(klass, include_super = true)
162
+ %w[public protected private].flat_map do |visibility|
163
+ safe_send(
164
+ klass, :"#{visibility}_instance_methods", include_super
165
+ ).map do |method_name|
166
+ new(
167
+ safe_send(klass, :instance_method, method_name),
168
+ visibility: visibility.to_sym
169
+ )
170
+ end
171
+ end
172
+ end
173
+
174
+ #
175
+ # Get all of the methods on an `Object`
176
+ #
177
+ # @param [Object] obj
178
+ #
179
+ # @param [Boolean] include_super
180
+ # indicates whether or not to include methods from ancestors.
181
+ #
182
+ # @return [Array[Pry::Method]]
183
+ #
184
+ def all_from_obj(obj, include_super = true)
185
+ all_from_class(singleton_class_of(obj), include_super)
186
+ end
187
+
188
+ # Get every `Class` and `Module`, in order, that will be checked when looking
189
+ # for an instance method to call on this object.
190
+ # @param [Object] obj
191
+ # @return [Array[Class, Module]]
192
+ def resolution_order(obj)
193
+ if Class === obj # rubocop:disable Style/CaseEquality
194
+ singleton_class_resolution_order(obj) + instance_resolution_order(Class)
195
+ else
196
+ klass = begin
197
+ singleton_class_of(obj)
198
+ rescue StandardError
199
+ obj.class
200
+ end
201
+ instance_resolution_order(klass)
202
+ end
203
+ end
204
+
205
+ # Get every `Class` and `Module`, in order, that will be checked when looking
206
+ # for methods on instances of the given `Class` or `Module`.
207
+ # This does not treat singleton classes of classes specially.
208
+ # @param [Class, Module] klass
209
+ # @return [Array[Class, Module]]
210
+ def instance_resolution_order(klass)
211
+ # include klass in case it is a singleton class,
212
+ ([klass] + Pry::Method.safe_send(klass, :ancestors)).uniq
213
+ end
214
+
215
+ def method_definition?(name, definition_line)
216
+ singleton_method_definition?(name, definition_line) ||
217
+ instance_method_definition?(name, definition_line)
218
+ end
219
+
220
+ def singleton_method_definition?(name, definition_line)
221
+ regexp =
222
+ /^define_singleton_method\(?\s*[:\"\']#{Regexp.escape(name)}|
223
+ ^def\s*self\.#{Regexp.escape(name)}/x
224
+ regexp =~ definition_line.strip
225
+ end
226
+
227
+ def instance_method_definition?(name, definition_line)
228
+ regexp =
229
+ /^define_method\(?\s*[:\"\']#{Regexp.escape(name)}|
230
+ ^def\s*#{Regexp.escape(name)}/x
231
+ regexp =~ definition_line.strip
232
+ end
233
+
234
+ # Get the singleton classes of superclasses that could define methods on
235
+ # the given class object, and any modules they include.
236
+ # If a module is included at multiple points in the ancestry, only
237
+ # the lowest copy will be returned.
238
+ def singleton_class_resolution_order(klass)
239
+ ancestors = Pry::Method.safe_send(klass, :ancestors)
240
+ resolution_order = ancestors.grep(Class).flat_map do |anc|
241
+ [singleton_class_of(anc), *singleton_class_of(anc).included_modules]
242
+ end
243
+
244
+ resolution_order.reverse.uniq.reverse - Class.included_modules
245
+ end
246
+
247
+ def singleton_class_of(obj)
248
+ class << obj; self; end
249
+ rescue TypeError # can't define singleton. Fixnum, Symbol, Float, ...
250
+ obj.class
251
+ end
252
+ end
253
+
254
+ # Workaround for https://github.com/pry/pry/pull/2086
255
+ def_delegators :@method, :owner, :parameters, :receiver
256
+
257
+ # A new instance of `Pry::Method` wrapping the given `::Method`,
258
+ # `UnboundMethod`, or `Proc`.
259
+ #
260
+ # @param [::Method, UnboundMethod, Proc] method
261
+ # @param [Hash] known_info Can be used to pre-cache expensive to compute stuff.
262
+ # @return [Pry::Method]
263
+ def initialize(method, known_info = {})
264
+ @method = method
265
+ @visibility = known_info[:visibility]
266
+ end
267
+
268
+ # Get the name of the method as a String, regardless of the underlying
269
+ # Method#name type.
270
+ #
271
+ # @return [String]
272
+ def name
273
+ @method.name.to_s
274
+ end
275
+
276
+ # Get the owner of the method as a Pry::Module
277
+ # @return [Pry::Module]
278
+ def wrapped_owner
279
+ @wrapped_owner ||= Pry::WrappedModule.new(owner)
280
+ end
281
+
282
+ # Get underlying object wrapped by this Pry::Method instance
283
+ # @return [Method, UnboundMethod, Proc]
284
+ def wrapped
285
+ @method
286
+ end
287
+
288
+ # Is the method undefined? (aka `Disowned`)
289
+ # @return [Boolean] false
290
+ def undefined?
291
+ false
292
+ end
293
+
294
+ # Get the name of the method including the class on which it was defined.
295
+ # @example
296
+ # method(:puts).method_name
297
+ # => "Kernel.puts"
298
+ # @return [String]
299
+ def name_with_owner
300
+ "#{wrapped_owner.method_prefix}#{name}"
301
+ end
302
+
303
+ # @return [String, nil] The source code of the method, or `nil` if it's unavailable.
304
+ def source
305
+ @source ||= case source_type
306
+ when :c
307
+ c_source
308
+ when :ruby
309
+ ruby_source
310
+ end
311
+ end
312
+
313
+ # Update the live copy of the method's source.
314
+ def redefine(source)
315
+ Patcher.new(self).patch_in_ram source
316
+ Pry::Method(owner.instance_method(name))
317
+ end
318
+
319
+ # Can we get the source code for this method?
320
+ # @return [Boolean]
321
+ def source?
322
+ !!source
323
+ rescue MethodSource::SourceNotFoundError
324
+ false
325
+ end
326
+
327
+ # @return [String, nil] The documentation for the method, or `nil` if it's
328
+ # unavailable.
329
+ def doc
330
+ @doc ||=
331
+ case source_type
332
+ when :c
333
+ info = pry_doc_info
334
+ info.docstring if info
335
+ when :ruby
336
+ get_comment_content(comment)
337
+ end
338
+ end
339
+
340
+ # @return [Symbol] The source type of the method. The options are
341
+ # `:ruby` for Ruby methods or `:c` for methods written in C.
342
+ def source_type
343
+ source_location.nil? ? :c : :ruby
344
+ end
345
+
346
+ # @return [String, nil] The name of the file the method is defined in, or
347
+ # `nil` if the filename is unavailable.
348
+ def source_file
349
+ if source_location.nil?
350
+ if source_type == :c
351
+ info = pry_doc_info
352
+ info.file if info
353
+ end
354
+ else
355
+ source_location.first
356
+ end
357
+ end
358
+
359
+ # @return [Fixnum, nil] The line of code in `source_file` which begins
360
+ # the method's definition, or `nil` if that information is unavailable.
361
+ def source_line
362
+ source_location.nil? ? nil : source_location[1]
363
+ end
364
+
365
+ # @return [Range, nil] The range of lines in `source_file` which contain
366
+ # the method's definition, or `nil` if that information is unavailable.
367
+ def source_range
368
+ source_location.nil? ? nil : (source_line)..(source_line + source.lines.count - 1)
369
+ end
370
+
371
+ # @return [Symbol] The visibility of the method. May be `:public`,
372
+ # `:protected`, or `:private`.
373
+ def visibility
374
+ @visibility ||=
375
+ if owner.public_instance_methods.any? { |m| m.to_s == name }
376
+ :public
377
+ elsif owner.protected_instance_methods.any? { |m| m.to_s == name }
378
+ :protected
379
+ elsif owner.private_instance_methods.any? { |m| m.to_s == name }
380
+ :private
381
+ else
382
+ :none
383
+ end
384
+ end
385
+
386
+ # @return [String] A representation of the method's signature, including its
387
+ # name and parameters. Optional and "rest" parameters are marked with `*`
388
+ # and block parameters with `&`. Keyword arguments are shown with `:`
389
+ # If the parameter names are unavailable, they're given numbered names instead.
390
+ # Paraphrased from `awesome_print` gem.
391
+ def signature
392
+ if respond_to?(:parameters)
393
+ args = parameters.inject([]) do |args_array, (arg_type, name)|
394
+ name ||= (arg_type == :block ? 'block' : "arg#{args_array.size + 1}")
395
+ args_array.push(
396
+ case arg_type
397
+ when :req then name.to_s
398
+ when :opt then "#{name}=?"
399
+ when :rest then "*#{name}"
400
+ when :block then "&#{name}"
401
+ when :key then "#{name}:?"
402
+ when :keyreq then "#{name}:"
403
+ else '?'
404
+ end
405
+ )
406
+ end
407
+ else
408
+ args = (1..arity.abs).map { |i| "arg#{i}" }
409
+ args[-1] = "*#{args[-1]}" if arity < 0
410
+ end
411
+
412
+ "#{name}(#{args.join(', ')})"
413
+ end
414
+
415
+ # @return [Pry::Method, nil] The wrapped method that is called when you
416
+ # use "super" in the body of this method.
417
+ def super(times = 1)
418
+ if @method.is_a?(UnboundMethod)
419
+ sup = super_using_ancestors(Pry::Method.instance_resolution_order(owner), times)
420
+ else
421
+ sup = super_using_ancestors(Pry::Method.resolution_order(receiver), times)
422
+ sup &&= sup.bind(receiver)
423
+ end
424
+ Pry::Method.new(sup) if sup
425
+ end
426
+
427
+ # @return [String, nil] The original name the method was defined under,
428
+ # before any aliasing, or `nil` if it can't be determined.
429
+ def original_name
430
+ return nil if source_type != :ruby
431
+
432
+ method_name_from_first_line(source.lines.first)
433
+ end
434
+
435
+ # @return [Boolean] Was the method defined outside a source file?
436
+ def dynamically_defined?
437
+ !!(source_file && source_file =~ /(\(.*\))|<.*>/)
438
+ end
439
+
440
+ # @return [Boolean] Whether the method is unbound.
441
+ def unbound_method?
442
+ is_a?(::UnboundMethod)
443
+ end
444
+
445
+ # @return [Boolean] Whether the method is bound.
446
+ def bound_method?
447
+ is_a?(::Method)
448
+ end
449
+
450
+ # @return [Boolean] Whether the method is a singleton method.
451
+ def singleton_method?
452
+ wrapped_owner.singleton_class?
453
+ end
454
+
455
+ # @return [Boolean] Was the method defined within the Pry REPL?
456
+ def pry_method?
457
+ source_file == Pry.eval_path
458
+ end
459
+
460
+ # @return [Array<String>] All known aliases for the method.
461
+ def aliases
462
+ owner = @method.owner
463
+ # Avoid using `to_sym` on {Method#name}, which returns a `String`, because
464
+ # it won't be garbage collected.
465
+ name = @method.name
466
+
467
+ all_methods_to_compare = owner.instance_methods | owner.private_instance_methods
468
+ alias_list = all_methods_to_compare.combination(2).select do |pair|
469
+ pair.include?(name) &&
470
+ owner.instance_method(pair.first) == owner.instance_method(pair.last)
471
+ end.flatten
472
+ alias_list.delete(name)
473
+
474
+ alias_list.map(&:to_s)
475
+ end
476
+
477
+ # @return [Boolean] Is the method definitely an alias?
478
+ def alias?
479
+ name != original_name
480
+ end
481
+
482
+ # @return [Boolean]
483
+ def ==(other)
484
+ return other == @method if other.is_a?(Pry::Method)
485
+
486
+ @method == other
487
+ end
488
+
489
+ # @param [Class] klass
490
+ # @return [Boolean]
491
+ def is_a?(klass)
492
+ (klass == Pry::Method) || @method.is_a?(klass)
493
+ end
494
+ alias kind_of? is_a?
495
+
496
+ # @param [String, Symbol] method_name
497
+ # @return [Boolean]
498
+ def respond_to?(method_name, include_all = false)
499
+ super || @method.respond_to?(method_name, include_all)
500
+ end
501
+
502
+ # Delegate any unknown calls to the wrapped method.
503
+ def method_missing(method_name, *args, &block)
504
+ if @method.respond_to?(method_name)
505
+ @method.__send__(method_name, *args, &block)
506
+ else
507
+ super
508
+ end
509
+ end
510
+
511
+ def respond_to_missing?(method_name, include_private = false)
512
+ @method.respond_to?(method_name) || super
513
+ end
514
+
515
+ def comment
516
+ Pry::Code.from_file(source_file).comment_describing(source_line)
517
+ end
518
+
519
+ private
520
+
521
+ # @return [YARD::CodeObjects::MethodObject]
522
+ # @raise [CommandError] when the method can't be found or `pry-doc` isn't installed.
523
+ def pry_doc_info
524
+ if defined?(PryDoc)
525
+ Pry::MethodInfo.info_for(@method) ||
526
+ raise(
527
+ CommandError,
528
+ "Cannot locate this method: #{name}. (source_location returns nil)"
529
+ )
530
+ else
531
+ fail_msg = "Cannot locate this method: #{name}."
532
+ if Helpers::Platform.mri?
533
+ fail_msg += " Run `gem install pry-doc` to install" \
534
+ " Ruby Core documentation," \
535
+ " and `require 'pry-doc'` to load it.\n"
536
+ end
537
+ raise CommandError, fail_msg
538
+ end
539
+ end
540
+
541
+ # @param [Class, Module] ancestors The ancestors to investigate
542
+ # @return [Method] The unwrapped super-method
543
+ def super_using_ancestors(ancestors, times = 1)
544
+ next_owner = owner
545
+ times.times do
546
+ i = ancestors.index(next_owner) + 1
547
+ while ancestors[i] &&
548
+ !(ancestors[i].method_defined?(name) ||
549
+ ancestors[i].private_method_defined?(name))
550
+ i += 1
551
+ end
552
+ (next_owner = ancestors[i]) || (return nil)
553
+ end
554
+
555
+ begin
556
+ safe_send(next_owner, :instance_method, name)
557
+ rescue StandardError
558
+ nil
559
+ end
560
+ end
561
+
562
+ # @param [String] first_ln The first line of a method definition.
563
+ # @return [String, nil]
564
+ def method_name_from_first_line(first_ln)
565
+ return nil if first_ln.strip !~ /^def /
566
+
567
+ tokens = SyntaxHighlighter.tokenize(first_ln).each_slice(2)
568
+ tokens.each_cons(2) do |t1, t2|
569
+ if t2.last == :method || t2.last == :ident && t1 == [".", :operator]
570
+ return t2.first
571
+ end
572
+ end
573
+
574
+ nil
575
+ end
576
+
577
+ def c_source
578
+ info = pry_doc_info
579
+ strip_comments_from_c_code(info.source) if info && info.source
580
+ end
581
+
582
+ def ruby_source
583
+ # Clone of `MethodSource.source_helper` that knows to use our
584
+ # hacked version of `source_location` for our input buffer for methods
585
+ # defined in `(pry)`.
586
+ file, line = *source_location
587
+ unless file
588
+ raise SourceNotFoundError, "Could not locate source for #{name_with_owner}!"
589
+ end
590
+
591
+ begin
592
+ code = Pry::Code.from_file(file).expression_at(line)
593
+ rescue SyntaxError => e
594
+ raise MethodSource::SourceNotFoundError, e.message
595
+ end
596
+ strip_leading_whitespace(code)
597
+ end
598
+ end
599
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'strscan'
4
+
5
+ class Pry
6
+ # `ObjectPath` implements the resolution of "object paths", which are strings
7
+ # that are similar to filesystem paths but meant for traversing Ruby objects.
8
+ # Examples of valid object paths include:
9
+ #
10
+ # x
11
+ # @foo/@bar
12
+ # "string"/upcase
13
+ # Pry/Method
14
+ #
15
+ # Object paths are mostly relevant in the context of the `cd` command.
16
+ # @see https://github.com/pry/pry/wiki/State-navigation
17
+ class ObjectPath
18
+ SPECIAL_TERMS = ["", "::", ".", ".."].freeze
19
+
20
+ # @param [String] path_string The object path expressed as a string.
21
+ # @param [Array<Binding>] current_stack The current state of the binding
22
+ # stack.
23
+ def initialize(path_string, current_stack)
24
+ @path_string = path_string
25
+ @current_stack = current_stack
26
+ end
27
+
28
+ # @return [Array<Binding>] a new stack resulting from applying the given
29
+ # path to the current stack.
30
+ def resolve
31
+ scanner = StringScanner.new(@path_string.strip)
32
+ stack = @current_stack.dup
33
+
34
+ loop do
35
+ begin
36
+ next_segment = ""
37
+
38
+ loop do
39
+ # Scan for as long as we don't see a slash
40
+ next_segment += scanner.scan(%r{[^/]*})
41
+
42
+ if complete?(next_segment) || scanner.eos?
43
+ scanner.getch # consume the slash
44
+ break
45
+ else
46
+ next_segment += scanner.getch # append the slash
47
+ end
48
+ end
49
+
50
+ case next_segment.chomp
51
+ when ""
52
+ stack = [stack.first]
53
+ when "::"
54
+ stack.push(TOPLEVEL_BINDING)
55
+ when "."
56
+ next
57
+ when ".."
58
+ stack.pop unless stack.size == 1
59
+ else
60
+ stack.push(Pry.binding_for(stack.last.eval(next_segment)))
61
+ end
62
+ rescue RescuableException => e
63
+ return handle_failure(next_segment, e)
64
+ end
65
+
66
+ break if scanner.eos?
67
+ end
68
+
69
+ stack
70
+ end
71
+
72
+ private
73
+
74
+ def complete?(segment)
75
+ SPECIAL_TERMS.include?(segment) || Pry::Code.complete_expression?(segment)
76
+ end
77
+
78
+ def handle_failure(context, err)
79
+ msg = [
80
+ "Bad object path: #{@path_string.inspect}",
81
+ "Failed trying to resolve: #{context.inspect}",
82
+ "Exception: #{err.inspect}"
83
+ ].join("\n")
84
+
85
+ command_error = CommandError.new(msg)
86
+ command_error.set_backtrace(err.backtrace)
87
+
88
+ raise command_error
89
+ end
90
+ end
91
+ end