pry 0.9.12.2 → 0.14.2

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 (237) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1141 -0
  3. data/LICENSE +2 -2
  4. data/README.md +466 -0
  5. data/bin/pry +4 -7
  6. data/lib/pry/basic_object.rb +10 -0
  7. data/lib/pry/block_command.rb +22 -0
  8. data/lib/pry/class_command.rb +194 -0
  9. data/lib/pry/cli.rb +97 -92
  10. data/lib/pry/code/code_file.rb +114 -0
  11. data/lib/pry/code/code_range.rb +7 -4
  12. data/lib/pry/code/loc.rb +27 -14
  13. data/lib/pry/code.rb +62 -90
  14. data/lib/pry/code_object.rb +83 -39
  15. data/lib/pry/color_printer.rb +66 -0
  16. data/lib/pry/command.rb +202 -371
  17. data/lib/pry/command_set.rb +151 -133
  18. data/lib/pry/command_state.rb +31 -0
  19. data/lib/pry/commands/amend_line.rb +86 -82
  20. data/lib/pry/commands/bang.rb +18 -14
  21. data/lib/pry/commands/bang_pry.rb +15 -11
  22. data/lib/pry/commands/cat/abstract_formatter.rb +23 -18
  23. data/lib/pry/commands/cat/exception_formatter.rb +85 -73
  24. data/lib/pry/commands/cat/file_formatter.rb +56 -63
  25. data/lib/pry/commands/cat/input_expression_formatter.rb +35 -30
  26. data/lib/pry/commands/cat.rb +64 -47
  27. data/lib/pry/commands/cd.rb +42 -26
  28. data/lib/pry/commands/change_inspector.rb +34 -0
  29. data/lib/pry/commands/change_prompt.rb +51 -0
  30. data/lib/pry/commands/clear_screen.rb +20 -0
  31. data/lib/pry/commands/code_collector.rb +148 -131
  32. data/lib/pry/commands/disable_pry.rb +23 -19
  33. data/lib/pry/commands/easter_eggs.rb +23 -34
  34. data/lib/pry/commands/edit/exception_patcher.rb +21 -17
  35. data/lib/pry/commands/edit/file_and_line_locator.rb +33 -24
  36. data/lib/pry/commands/edit.rb +183 -167
  37. data/lib/pry/commands/exit.rb +40 -35
  38. data/lib/pry/commands/exit_all.rb +24 -20
  39. data/lib/pry/commands/exit_program.rb +20 -17
  40. data/lib/pry/commands/find_method.rb +167 -167
  41. data/lib/pry/commands/fix_indent.rb +16 -12
  42. data/lib/pry/commands/help.rb +140 -133
  43. data/lib/pry/commands/hist.rb +153 -132
  44. data/lib/pry/commands/import_set.rb +20 -15
  45. data/lib/pry/commands/jump_to.rb +25 -21
  46. data/lib/pry/commands/list_inspectors.rb +42 -0
  47. data/lib/pry/commands/ls/constants.rb +75 -0
  48. data/lib/pry/commands/ls/formatter.rb +55 -0
  49. data/lib/pry/commands/ls/globals.rb +50 -0
  50. data/lib/pry/commands/ls/grep.rb +23 -0
  51. data/lib/pry/commands/ls/instance_vars.rb +40 -0
  52. data/lib/pry/commands/ls/interrogatable.rb +24 -0
  53. data/lib/pry/commands/ls/jruby_hacks.rb +55 -0
  54. data/lib/pry/commands/ls/local_names.rb +37 -0
  55. data/lib/pry/commands/ls/local_vars.rb +47 -0
  56. data/lib/pry/commands/ls/ls_entity.rb +65 -0
  57. data/lib/pry/commands/ls/methods.rb +55 -0
  58. data/lib/pry/commands/ls/methods_helper.rb +50 -0
  59. data/lib/pry/commands/ls/self_methods.rb +34 -0
  60. data/lib/pry/commands/ls.rb +100 -303
  61. data/lib/pry/commands/nesting.rb +21 -17
  62. data/lib/pry/commands/play.rb +93 -49
  63. data/lib/pry/commands/pry_backtrace.rb +22 -18
  64. data/lib/pry/commands/pry_version.rb +15 -11
  65. data/lib/pry/commands/raise_up.rb +33 -27
  66. data/lib/pry/commands/reload_code.rb +57 -48
  67. data/lib/pry/commands/reset.rb +16 -12
  68. data/lib/pry/commands/ri.rb +57 -38
  69. data/lib/pry/commands/save_file.rb +45 -43
  70. data/lib/pry/commands/shell_command.rb +66 -34
  71. data/lib/pry/commands/shell_mode.rb +22 -20
  72. data/lib/pry/commands/show_doc.rb +80 -65
  73. data/lib/pry/commands/show_info.rb +193 -159
  74. data/lib/pry/commands/show_input.rb +16 -11
  75. data/lib/pry/commands/show_source.rb +113 -33
  76. data/lib/pry/commands/stat.rb +35 -31
  77. data/lib/pry/commands/switch_to.rb +21 -15
  78. data/lib/pry/commands/toggle_color.rb +21 -13
  79. data/lib/pry/commands/watch_expression/expression.rb +43 -0
  80. data/lib/pry/commands/watch_expression.rb +110 -0
  81. data/lib/pry/commands/whereami.rb +157 -134
  82. data/lib/pry/commands/wtf.rb +78 -40
  83. data/lib/pry/config/attributable.rb +22 -0
  84. data/lib/pry/config/lazy_value.rb +29 -0
  85. data/lib/pry/config/memoized_value.rb +34 -0
  86. data/lib/pry/config/value.rb +24 -0
  87. data/lib/pry/config.rb +290 -220
  88. data/lib/pry/control_d_handler.rb +28 -0
  89. data/lib/pry/core_extensions.rb +50 -27
  90. data/lib/pry/editor.rb +130 -102
  91. data/lib/pry/env.rb +18 -0
  92. data/lib/pry/exception_handler.rb +43 -0
  93. data/lib/pry/exceptions.rb +73 -0
  94. data/lib/pry/forwardable.rb +27 -0
  95. data/lib/pry/helpers/base_helpers.rb +22 -151
  96. data/lib/pry/helpers/command_helpers.rb +55 -63
  97. data/lib/pry/helpers/documentation_helpers.rb +21 -13
  98. data/lib/pry/helpers/options_helpers.rb +15 -8
  99. data/lib/pry/helpers/platform.rb +55 -0
  100. data/lib/pry/helpers/table.rb +44 -32
  101. data/lib/pry/helpers/text.rb +96 -86
  102. data/lib/pry/helpers.rb +3 -0
  103. data/lib/pry/history.rb +101 -70
  104. data/lib/pry/hooks.rb +67 -137
  105. data/lib/pry/indent.rb +79 -73
  106. data/lib/pry/input_completer.rb +283 -0
  107. data/lib/pry/input_lock.rb +129 -0
  108. data/lib/pry/inspector.rb +39 -0
  109. data/lib/pry/last_exception.rb +61 -0
  110. data/lib/pry/method/disowned.rb +19 -5
  111. data/lib/pry/{commands/edit/method_patcher.rb → method/patcher.rb} +51 -42
  112. data/lib/pry/method/weird_method_locator.rb +80 -44
  113. data/lib/pry/method.rb +225 -176
  114. data/lib/pry/object_path.rb +91 -0
  115. data/lib/pry/output.rb +136 -0
  116. data/lib/pry/pager.rb +227 -68
  117. data/lib/pry/prompt.rb +214 -0
  118. data/lib/pry/pry_class.rb +216 -289
  119. data/lib/pry/pry_instance.rb +438 -500
  120. data/lib/pry/repl.rb +256 -0
  121. data/lib/pry/repl_file_loader.rb +34 -35
  122. data/lib/pry/ring.rb +89 -0
  123. data/lib/pry/slop/LICENSE +20 -0
  124. data/lib/pry/slop/commands.rb +190 -0
  125. data/lib/pry/slop/option.rb +210 -0
  126. data/lib/pry/slop.rb +672 -0
  127. data/lib/pry/syntax_highlighter.rb +26 -0
  128. data/lib/pry/system_command_handler.rb +17 -0
  129. data/lib/pry/testable/evalable.rb +24 -0
  130. data/lib/pry/testable/mockable.rb +22 -0
  131. data/lib/pry/testable/pry_tester.rb +88 -0
  132. data/lib/pry/testable/utility.rb +34 -0
  133. data/lib/pry/testable/variables.rb +52 -0
  134. data/lib/pry/testable.rb +68 -0
  135. data/lib/pry/version.rb +3 -1
  136. data/lib/pry/warning.rb +20 -0
  137. data/lib/pry/{module_candidate.rb → wrapped_module/candidate.rb} +36 -43
  138. data/lib/pry/wrapped_module.rb +102 -103
  139. data/lib/pry.rb +135 -261
  140. metadata +94 -283
  141. data/.document +0 -2
  142. data/.gitignore +0 -16
  143. data/.travis.yml +0 -21
  144. data/.yardopts +0 -1
  145. data/CHANGELOG +0 -534
  146. data/CONTRIBUTORS +0 -55
  147. data/Gemfile +0 -9
  148. data/Guardfile +0 -62
  149. data/README.markdown +0 -400
  150. data/Rakefile +0 -140
  151. data/TODO +0 -117
  152. data/lib/pry/commands/disabled_commands.rb +0 -2
  153. data/lib/pry/commands/gem_cd.rb +0 -26
  154. data/lib/pry/commands/gem_install.rb +0 -29
  155. data/lib/pry/commands/gem_list.rb +0 -33
  156. data/lib/pry/commands/gem_open.rb +0 -29
  157. data/lib/pry/commands/gist.rb +0 -102
  158. data/lib/pry/commands/install_command.rb +0 -51
  159. data/lib/pry/commands/simple_prompt.rb +0 -22
  160. data/lib/pry/commands.rb +0 -6
  161. data/lib/pry/completion.rb +0 -304
  162. data/lib/pry/custom_completions.rb +0 -6
  163. data/lib/pry/history_array.rb +0 -116
  164. data/lib/pry/plugins.rb +0 -103
  165. data/lib/pry/rbx_method.rb +0 -13
  166. data/lib/pry/rbx_path.rb +0 -22
  167. data/lib/pry/rubygem.rb +0 -74
  168. data/lib/pry/terminal.rb +0 -78
  169. data/lib/pry/test/helper.rb +0 -185
  170. data/man/pry.1 +0 -195
  171. data/man/pry.1.html +0 -204
  172. data/man/pry.1.ronn +0 -141
  173. data/pry.gemspec +0 -30
  174. data/spec/Procfile +0 -3
  175. data/spec/cli_spec.rb +0 -78
  176. data/spec/code_object_spec.rb +0 -277
  177. data/spec/code_spec.rb +0 -219
  178. data/spec/command_helpers_spec.rb +0 -29
  179. data/spec/command_integration_spec.rb +0 -644
  180. data/spec/command_set_spec.rb +0 -627
  181. data/spec/command_spec.rb +0 -821
  182. data/spec/commands/amend_line_spec.rb +0 -247
  183. data/spec/commands/bang_spec.rb +0 -19
  184. data/spec/commands/cat_spec.rb +0 -164
  185. data/spec/commands/cd_spec.rb +0 -250
  186. data/spec/commands/disable_pry_spec.rb +0 -25
  187. data/spec/commands/edit_spec.rb +0 -727
  188. data/spec/commands/exit_all_spec.rb +0 -34
  189. data/spec/commands/exit_program_spec.rb +0 -19
  190. data/spec/commands/exit_spec.rb +0 -34
  191. data/spec/commands/find_method_spec.rb +0 -70
  192. data/spec/commands/gem_list_spec.rb +0 -26
  193. data/spec/commands/gist_spec.rb +0 -79
  194. data/spec/commands/help_spec.rb +0 -56
  195. data/spec/commands/hist_spec.rb +0 -181
  196. data/spec/commands/jump_to_spec.rb +0 -15
  197. data/spec/commands/ls_spec.rb +0 -181
  198. data/spec/commands/play_spec.rb +0 -140
  199. data/spec/commands/raise_up_spec.rb +0 -56
  200. data/spec/commands/save_file_spec.rb +0 -177
  201. data/spec/commands/show_doc_spec.rb +0 -510
  202. data/spec/commands/show_input_spec.rb +0 -17
  203. data/spec/commands/show_source_spec.rb +0 -782
  204. data/spec/commands/whereami_spec.rb +0 -203
  205. data/spec/completion_spec.rb +0 -239
  206. data/spec/control_d_handler_spec.rb +0 -58
  207. data/spec/documentation_helper_spec.rb +0 -73
  208. data/spec/editor_spec.rb +0 -79
  209. data/spec/exception_whitelist_spec.rb +0 -21
  210. data/spec/fixtures/candidate_helper1.rb +0 -11
  211. data/spec/fixtures/candidate_helper2.rb +0 -8
  212. data/spec/fixtures/example.erb +0 -5
  213. data/spec/fixtures/example_nesting.rb +0 -33
  214. data/spec/fixtures/show_source_doc_examples.rb +0 -15
  215. data/spec/fixtures/testrc +0 -2
  216. data/spec/fixtures/testrcbad +0 -2
  217. data/spec/fixtures/whereami_helper.rb +0 -6
  218. data/spec/helper.rb +0 -34
  219. data/spec/helpers/bacon.rb +0 -86
  220. data/spec/helpers/mock_pry.rb +0 -43
  221. data/spec/helpers/table_spec.rb +0 -105
  222. data/spec/history_array_spec.rb +0 -67
  223. data/spec/hooks_spec.rb +0 -522
  224. data/spec/indent_spec.rb +0 -301
  225. data/spec/input_stack_spec.rb +0 -90
  226. data/spec/method_spec.rb +0 -482
  227. data/spec/prompt_spec.rb +0 -60
  228. data/spec/pry_defaults_spec.rb +0 -419
  229. data/spec/pry_history_spec.rb +0 -99
  230. data/spec/pry_output_spec.rb +0 -95
  231. data/spec/pry_spec.rb +0 -504
  232. data/spec/run_command_spec.rb +0 -25
  233. data/spec/sticky_locals_spec.rb +0 -157
  234. data/spec/syntax_checking_spec.rb +0 -81
  235. data/spec/wrapped_module_spec.rb +0 -261
  236. data/wiki/Customizing-pry.md +0 -397
  237. data/wiki/Home.md +0 -4
@@ -0,0 +1,283 @@
1
+ # frozen_string_literal: true
2
+
3
+ # taken from irb
4
+ # Implements tab completion for Readline in Pry
5
+ class Pry
6
+ class InputCompleter
7
+ NUMERIC_REGEXP = /^(-?(0[dbo])?[0-9_]+(\.[0-9_]+)?([eE]-?[0-9]+)?)\.([^.]*)$/.freeze
8
+ ARRAY_REGEXP = /^([^\]]*\])\.([^.]*)$/.freeze
9
+ SYMBOL_REGEXP = /^(:[^:.]*)$/.freeze
10
+ SYMBOL_METHOD_CALL_REGEXP = /^(:[^:.]+)\.([^.]*)$/.freeze
11
+ REGEX_REGEXP = %r{^(/[^/]*/)\.([^.]*)$}.freeze
12
+ PROC_OR_HASH_REGEXP = /^([^\}]*\})\.([^.]*)$/.freeze
13
+ TOPLEVEL_LOOKUP_REGEXP = /^::([A-Z][^:\.\(]*)$/.freeze
14
+ CONSTANT_REGEXP = /^([A-Z][A-Za-z0-9]*)$/.freeze
15
+ CONSTANT_OR_METHOD_REGEXP = /^([A-Z].*)::([^:.]*)$/.freeze
16
+ HEX_REGEXP = /^(-?0x[0-9a-fA-F_]+)\.([^.]*)$/.freeze
17
+ GLOBALVARIABLE_REGEXP = /^(\$[^.]*)$/.freeze
18
+ VARIABLE_REGEXP = /^([^."].*)\.([^.]*)$/.freeze
19
+
20
+ RESERVED_WORDS = %w[
21
+ BEGIN END
22
+ alias and
23
+ begin break
24
+ case class
25
+ def defined do
26
+ else elsif end ensure
27
+ false for
28
+ if in
29
+ module
30
+ next nil not
31
+ or
32
+ redo rescue retry return
33
+ self super
34
+ then true
35
+ undef unless until
36
+ when while
37
+ yield
38
+ ].freeze
39
+
40
+ WORD_ESCAPE_STR = " \t\n\"\\'`><=;|&{(".freeze
41
+
42
+ def initialize(input, pry = nil)
43
+ @pry = pry
44
+ @input = input
45
+ if @input.respond_to?(:basic_word_break_characters=)
46
+ @input.basic_word_break_characters = WORD_ESCAPE_STR
47
+ end
48
+
49
+ return unless @input.respond_to?(:completion_append_character=)
50
+
51
+ @input.completion_append_character = nil
52
+ end
53
+
54
+ # Return a new completion proc for use by Readline.
55
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
56
+ def call(str, options = {})
57
+ custom_completions = options[:custom_completions] || []
58
+ # if there are multiple contexts e.g. cd 1/2/3
59
+ # get new target for 1/2 and find candidates for 3
60
+ path, input = build_path(str)
61
+
62
+ if path.call.empty?
63
+ target = options[:target]
64
+ else
65
+ # Assume the user is tab-completing the 'cd' command
66
+ begin
67
+ target = Pry::ObjectPath.new(path.call, @pry.binding_stack).resolve.last
68
+ # but if that doesn't work, assume they're doing division with no spaces
69
+ rescue Pry::CommandError
70
+ target = options[:target]
71
+ end
72
+ end
73
+
74
+ begin
75
+ bind = target
76
+ # Complete stdlib symbols
77
+ case input
78
+ when REGEX_REGEXP # Regexp
79
+ receiver = Regexp.last_match(1)
80
+ message = Regexp.quote(Regexp.last_match(2))
81
+ candidates = Regexp.instance_methods.collect(&:to_s)
82
+ select_message(path, receiver, message, candidates)
83
+ when ARRAY_REGEXP # Array
84
+ receiver = Regexp.last_match(1)
85
+ message = Regexp.quote(Regexp.last_match(2))
86
+ candidates = Array.instance_methods.collect(&:to_s)
87
+ select_message(path, receiver, message, candidates)
88
+ when PROC_OR_HASH_REGEXP # Proc or Hash
89
+ receiver = Regexp.last_match(1)
90
+ message = Regexp.quote(Regexp.last_match(2))
91
+ candidates = Proc.instance_methods.collect(&:to_s)
92
+ candidates |= Hash.instance_methods.collect(&:to_s)
93
+ select_message(path, receiver, message, candidates)
94
+ when SYMBOL_REGEXP # Symbol
95
+ if Symbol.respond_to?(:all_symbols)
96
+ sym = Regexp.quote(Regexp.last_match(1))
97
+ candidates = Symbol.all_symbols.collect { |s| ":" + s.id2name }
98
+ candidates.grep(/^#{sym}/)
99
+ else
100
+ []
101
+ end
102
+ when TOPLEVEL_LOOKUP_REGEXP # Absolute Constant or class methods
103
+ receiver = Regexp.last_match(1)
104
+ candidates = Object.constants.collect(&:to_s)
105
+ candidates.grep(/^#{receiver}/).collect { |e| "::" + e }
106
+ when CONSTANT_REGEXP # Constant
107
+ message = Regexp.last_match(1)
108
+ begin
109
+ context = target.eval("self")
110
+ context = context.class unless context.respond_to? :constants
111
+ candidates = context.constants.collect(&:to_s)
112
+ rescue StandardError
113
+ candidates = []
114
+ end
115
+ candidates = candidates.grep(/^#{message}/).collect(&path)
116
+ when CONSTANT_OR_METHOD_REGEXP # Constant or class methods
117
+ receiver = Regexp.last_match(1)
118
+ message = Regexp.quote(Regexp.last_match(2))
119
+ begin
120
+ candidates = eval( # rubocop:disable Security/Eval
121
+ "#{receiver}.constants.collect(&:to_s)", bind, __FILE__, __LINE__
122
+ )
123
+ candidates |= eval( # rubocop:disable Security/Eval
124
+ "#{receiver}.methods.collect(&:to_s)", bind, __FILE__, __LINE__
125
+ )
126
+ rescue Pry::RescuableException
127
+ candidates = []
128
+ end
129
+ candidates.grep(/^#{message}/).collect { |e| receiver + "::" + e }
130
+ when SYMBOL_METHOD_CALL_REGEXP # method call on a Symbol
131
+ receiver = Regexp.last_match(1)
132
+ message = Regexp.quote(Regexp.last_match(2))
133
+ candidates = Symbol.instance_methods.collect(&:to_s)
134
+ select_message(path, receiver, message, candidates)
135
+ when NUMERIC_REGEXP
136
+ # Numeric
137
+ receiver = Regexp.last_match(1)
138
+ message = Regexp.quote(Regexp.last_match(5))
139
+ begin
140
+ # rubocop:disable Security/Eval
141
+ candidates = eval(receiver, bind).methods.collect(&:to_s)
142
+ # rubocop:enable Security/Eval
143
+ rescue Pry::RescuableException
144
+ candidates = []
145
+ end
146
+ select_message(path, receiver, message, candidates)
147
+ when HEX_REGEXP
148
+ # Numeric(0xFFFF)
149
+ receiver = Regexp.last_match(1)
150
+ message = Regexp.quote(Regexp.last_match(2))
151
+ begin
152
+ # rubocop:disable Security/Eval
153
+ candidates = eval(receiver, bind).methods.collect(&:to_s)
154
+ # rubocop:enable Security/Eval
155
+ rescue Pry::RescuableException
156
+ candidates = []
157
+ end
158
+ select_message(path, receiver, message, candidates)
159
+ when GLOBALVARIABLE_REGEXP # global
160
+ regmessage = Regexp.new(Regexp.quote(Regexp.last_match(1)))
161
+ candidates = global_variables.collect(&:to_s).grep(regmessage)
162
+ when VARIABLE_REGEXP # variable
163
+ receiver = Regexp.last_match(1)
164
+ message = Regexp.quote(Regexp.last_match(2))
165
+
166
+ gv = eval("global_variables", bind, __FILE__, __LINE__).collect(&:to_s)
167
+ lv = eval("local_variables", bind, __FILE__, __LINE__).collect(&:to_s)
168
+ cv = eval("self.class.constants", bind, __FILE__, __LINE__).collect(&:to_s)
169
+
170
+ if (gv | lv | cv).include?(receiver) || /^[A-Z]/ =~ receiver && /\./ !~ receiver
171
+ # foo.func and foo is local var. OR
172
+ # Foo::Bar.func
173
+ begin
174
+ candidates = eval( # rubocop:disable Security/Eval
175
+ "#{receiver}.methods", bind, __FILE__, __LINE__
176
+ ).collect(&:to_s)
177
+ rescue Pry::RescuableException
178
+ candidates = []
179
+ end
180
+ else
181
+ # func1.func2
182
+ require 'set'
183
+ candidates = Set.new
184
+ to_ignore = ignored_modules
185
+ ObjectSpace.each_object(Module) do |m|
186
+ next if begin
187
+ to_ignore.include?(m)
188
+ rescue StandardError
189
+ true
190
+ end
191
+
192
+ # jruby doesn't always provide #instance_methods() on each
193
+ # object.
194
+ if m.respond_to?(:instance_methods)
195
+ candidates.merge m.instance_methods(false).collect(&:to_s)
196
+ end
197
+ end
198
+ end
199
+ select_message(path, receiver, message, candidates.sort)
200
+ when /^\.([^.]*)$/
201
+ # Unknown(maybe String)
202
+ receiver = ""
203
+ message = Regexp.quote(Regexp.last_match(1))
204
+ candidates = String.instance_methods(true).collect(&:to_s)
205
+ select_message(path, receiver, message, candidates)
206
+ else
207
+ candidates = eval(
208
+ "methods | private_methods | local_variables | " \
209
+ "self.class.constants | instance_variables",
210
+ bind, __FILE__, __LINE__ - 2
211
+ ).collect(&:to_s)
212
+
213
+ if eval("respond_to?(:class_variables)", bind, __FILE__, __LINE__)
214
+ candidates += eval(
215
+ "class_variables", bind, __FILE__, __LINE__
216
+ ).collect(&:to_s)
217
+ end
218
+ candidates =
219
+ (candidates | RESERVED_WORDS | custom_completions)
220
+ .grep(/^#{Regexp.quote(input)}/)
221
+ candidates.collect(&path)
222
+ end
223
+ rescue Pry::RescuableException
224
+ []
225
+ end
226
+ end
227
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
228
+
229
+ def select_message(path, receiver, message, candidates)
230
+ candidates.grep(/^#{message}/).collect do |e|
231
+ next unless e =~ /^[a-zA-Z_]/
232
+
233
+ path.call(receiver + "." + e)
234
+ end.compact
235
+ end
236
+
237
+ # build_path seperates the input into two parts: path and input.
238
+ # input is the partial string that should be completed
239
+ # path is a proc that takes an input and builds a full path.
240
+ def build_path(input)
241
+ # check to see if the input is a regex
242
+ return proc { |i| i.to_s }, input if input[%r{/\.}]
243
+
244
+ trailing_slash = input.end_with?('/')
245
+ contexts = input.chomp('/').split(%r{/})
246
+ input = contexts[-1]
247
+ path = proc do |i|
248
+ p = contexts[0..-2].push(i).join('/')
249
+ p += '/' if trailing_slash && !i.nil?
250
+ p
251
+ end
252
+ [path, input]
253
+ end
254
+
255
+ def ignored_modules
256
+ # We could cache the result, but IRB is not loaded by default.
257
+ # And this is very fast anyway.
258
+ # By using this approach, we avoid Module#name calls, which are
259
+ # relatively slow when there are a lot of anonymous modules defined.
260
+ s = Set.new
261
+
262
+ scanner = lambda do |m|
263
+ next if s.include?(m) # IRB::ExtendCommandBundle::EXCB recurses.
264
+
265
+ s << m
266
+ m.constants(false).each do |c|
267
+ value = m.const_get(c)
268
+ scanner.call(value) if value.is_a?(Module)
269
+ end
270
+ end
271
+
272
+ # FIXME: Add Pry here as well?
273
+ %i[IRB SLex RubyLex RubyToken].each do |module_name|
274
+ next unless Object.const_defined?(module_name)
275
+
276
+ scanner.call(Object.const_get(module_name))
277
+ end
278
+
279
+ s.delete(IRB::Context) if defined?(IRB::Context)
280
+ s
281
+ end
282
+ end
283
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
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 # rubocop:disable Lint/InheritException
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
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
+ yield
62
+ ensure
63
+ @mutex.synchronize do
64
+ # We are releasing any desire to have the input ownership by removing
65
+ # ourselves from the list.
66
+ @owners.delete(Thread.current)
67
+
68
+ # We need to wake up the thread at the end of the @owners list, but
69
+ # sadly Ruby doesn't allow us to choose which one we wake up, so we wake
70
+ # them all up.
71
+ @cond.broadcast
72
+ end
73
+ end
74
+
75
+ def with_ownership(&block)
76
+ # If we are in a nested with_ownership() call (nested pry context), we do nothing.
77
+ nested = @mutex.synchronize { @owners.include?(Thread.current) }
78
+ nested ? yield : __with_ownership(&block)
79
+ end
80
+
81
+ def enter_interruptible_region
82
+ @mutex.synchronize do
83
+ # We patiently wait until we are the owner. This may happen as another
84
+ # thread calls with_ownership() because of a binding.pry happening in
85
+ # another thread.
86
+ @cond.wait(@mutex) until @owners.last == Thread.current
87
+
88
+ # We are the legitimate owner of the input. We mark ourselves as
89
+ # interruptible, so other threads can send us an Interrupt exception
90
+ # while we are blocking from reading the input.
91
+ @interruptible = true
92
+ end
93
+ end
94
+
95
+ def leave_interruptible_region
96
+ @mutex.synchronize do
97
+ # We check if we are still the owner, because we could have received an
98
+ # Interrupt right after the following @cond.broadcast, making us retry.
99
+ @interruptible = false if @owners.last == Thread.current
100
+ @cond.broadcast
101
+ end
102
+ rescue Interrupt
103
+ # We need to guard against a spurious interrupt delivered while we are
104
+ # trying to acquire the lock (the rescue block is no longer in our scope).
105
+ retry
106
+ end
107
+
108
+ def interruptible_region
109
+ enter_interruptible_region
110
+
111
+ # XXX Note that there is a chance that we get the interrupt right after
112
+ # the readline call succeeded, but we'll never know, and we will retry the
113
+ # call, discarding that piece of input.
114
+ yield
115
+ rescue Interrupt
116
+ # We were asked to back off. The one requesting the interrupt will be
117
+ # waiting on the conditional for the interruptible flag to change to false.
118
+ # Note that there can be some inefficiency, as we could immediately
119
+ # succeed in enter_interruptible_region(), even before the one requesting
120
+ # the ownership has the chance to register itself as an owner.
121
+ # To mitigate the issue, we sleep a little bit.
122
+ leave_interruptible_region
123
+ sleep 0.01
124
+ retry
125
+ ensure
126
+ leave_interruptible_region
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Pry
4
+ class Inspector
5
+ MAP = {
6
+ "default" => {
7
+ value: Pry.config.print,
8
+ description: <<-DESCRIPTION.each_line.map(&:lstrip!)
9
+ The default Pry inspector. It has paging and color support, and uses
10
+ pretty_inspect when printing an object.
11
+ DESCRIPTION
12
+ },
13
+
14
+ "simple" => {
15
+ value: proc do |output, value|
16
+ begin
17
+ output.puts value.inspect
18
+ rescue RescuableException
19
+ output.puts "unknown"
20
+ end
21
+ end,
22
+ description: <<-DESCRIPTION.each_line.map(&:lstrip)
23
+ A simple inspector that uses #puts and #inspect when printing an
24
+ object. It has no pager, color, or pretty_inspect support.
25
+ DESCRIPTION
26
+ },
27
+
28
+ "clipped" => {
29
+ value: proc do |output, value|
30
+ output.puts Pry.view_clip(value, id: true)
31
+ end,
32
+ description: <<-DESCRIPTION.each_line.map(&:lstrip)
33
+ The clipped inspector has the same features as the 'simple' inspector
34
+ but prints large objects as a smaller string.
35
+ DESCRIPTION
36
+ }
37
+ }.freeze
38
+ end
39
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # {Pry::LastException} is a proxy class who wraps an Exception object for
5
+ # {Pry#last_exception}. it extends the exception object with methods that
6
+ # help pry commands be useful.
7
+ #
8
+ # the original exception object is not modified and method calls are forwarded
9
+ # to the wrapped exception object.
10
+ #
11
+ class Pry
12
+ class LastException < BasicObject
13
+ attr_accessor :bt_index
14
+
15
+ def initialize(exception)
16
+ @exception = exception
17
+ @bt_index = 0
18
+ @file, @line = bt_source_location_for(0)
19
+ end
20
+
21
+ def method_missing(name, *args, &block)
22
+ if @exception.respond_to?(name)
23
+ @exception.public_send(name, *args, &block)
24
+ else
25
+ super
26
+ end
27
+ end
28
+
29
+ def respond_to_missing?(name, include_all = false)
30
+ @exception.respond_to?(name, include_all)
31
+ end
32
+
33
+ #
34
+ # @return [String]
35
+ # returns the path to a file for the current backtrace. see {#bt_index}.
36
+ #
37
+ attr_reader :file
38
+
39
+ #
40
+ # @return [Fixnum]
41
+ # returns the line for the current backtrace. see {#bt_index}.
42
+ #
43
+ attr_reader :line
44
+
45
+ # @return [Exception]
46
+ # returns the wrapped exception
47
+ #
48
+ def wrapped_exception
49
+ @exception
50
+ end
51
+
52
+ def bt_source_location_for(index)
53
+ backtrace[index] =~ /(.*):(\d+)/
54
+ [::Regexp.last_match(1), ::Regexp.last_match(2).to_i]
55
+ end
56
+
57
+ def inc_bt_index
58
+ @bt_index = (@bt_index + 1) % backtrace.size
59
+ end
60
+ end
61
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Pry
2
4
  class Method
3
5
  # A Disowned Method is one that's been removed from the class on which it was defined.
@@ -20,8 +22,10 @@ class Pry
20
22
  #
21
23
  # @param [Object] receiver
22
24
  # @param [String] method_name
23
- def initialize(receiver, method_name, binding=nil)
24
- @receiver, @name = receiver, method_name
25
+ def initialize(receiver, method_name)
26
+ @receiver = receiver
27
+ @name = method_name
28
+ @method = nil
25
29
  end
26
30
 
27
31
  # Is the method undefined? (aka `Disowned`)
@@ -44,9 +48,19 @@ class Pry
44
48
  end
45
49
 
46
50
  # Raise a more useful error message instead of trying to forward to nil.
47
- def method_missing(meth_name, *args, &block)
48
- raise "Cannot call '#{meth_name}' on an undef'd method." if method(:name).respond_to?(meth_name)
49
- Object.instance_method(:method_missing).bind(self).call(meth_name, *args, &block)
51
+ # rubocop:disable Style/MethodMissingSuper
52
+ def method_missing(method_name, *args, &block)
53
+ if method(:name).respond_to?(method_name)
54
+ raise "Cannot call '#{method_name}' on an undef'd method."
55
+ end
56
+
57
+ method = Object.instance_method(:method_missing).bind(self)
58
+ method.call(method_name, *args, &block)
59
+ end
60
+ # rubocop:enable Style/MethodMissingSuper
61
+
62
+ def respond_to_missing?(method_name, include_private = false)
63
+ !method(:name).respond_to?(method_name) || super
50
64
  end
51
65
  end
52
66
  end