pry 0.9.12.6-i386-mingw32 → 0.10.0-i386-mingw32

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 (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +702 -0
  3. data/LICENSE +2 -2
  4. data/{README.markdown → README.md} +37 -31
  5. data/lib/pry.rb +38 -151
  6. data/lib/pry/cli.rb +35 -17
  7. data/lib/pry/code.rb +19 -63
  8. data/lib/pry/code/code_file.rb +103 -0
  9. data/lib/pry/code/code_range.rb +2 -1
  10. data/lib/pry/code/loc.rb +2 -2
  11. data/lib/pry/code_object.rb +40 -21
  12. data/lib/pry/color_printer.rb +55 -0
  13. data/lib/pry/command.rb +12 -9
  14. data/lib/pry/command_set.rb +81 -38
  15. data/lib/pry/commands.rb +1 -1
  16. data/lib/pry/commands/amend_line.rb +2 -2
  17. data/lib/pry/commands/bang.rb +1 -1
  18. data/lib/pry/commands/cat.rb +11 -2
  19. data/lib/pry/commands/cat/exception_formatter.rb +6 -7
  20. data/lib/pry/commands/cat/file_formatter.rb +15 -32
  21. data/lib/pry/commands/cat/input_expression_formatter.rb +1 -1
  22. data/lib/pry/commands/cd.rb +14 -3
  23. data/lib/pry/commands/change_inspector.rb +27 -0
  24. data/lib/pry/commands/change_prompt.rb +26 -0
  25. data/lib/pry/commands/code_collector.rb +4 -4
  26. data/lib/pry/commands/easter_eggs.rb +3 -3
  27. data/lib/pry/commands/edit.rb +10 -22
  28. data/lib/pry/commands/edit/exception_patcher.rb +2 -2
  29. data/lib/pry/commands/edit/file_and_line_locator.rb +0 -2
  30. data/lib/pry/commands/exit_program.rb +0 -1
  31. data/lib/pry/commands/find_method.rb +16 -22
  32. data/lib/pry/commands/gem_install.rb +5 -2
  33. data/lib/pry/commands/gem_open.rb +1 -1
  34. data/lib/pry/commands/gist.rb +10 -11
  35. data/lib/pry/commands/help.rb +14 -14
  36. data/lib/pry/commands/hist.rb +27 -8
  37. data/lib/pry/commands/install_command.rb +14 -12
  38. data/lib/pry/commands/list_inspectors.rb +35 -0
  39. data/lib/pry/commands/list_prompts.rb +35 -0
  40. data/lib/pry/commands/ls.rb +72 -296
  41. data/lib/pry/commands/ls/constants.rb +47 -0
  42. data/lib/pry/commands/ls/formatter.rb +49 -0
  43. data/lib/pry/commands/ls/globals.rb +48 -0
  44. data/lib/pry/commands/ls/grep.rb +21 -0
  45. data/lib/pry/commands/ls/instance_vars.rb +39 -0
  46. data/lib/pry/commands/ls/interrogatable.rb +18 -0
  47. data/lib/pry/commands/ls/jruby_hacks.rb +49 -0
  48. data/lib/pry/commands/ls/local_names.rb +35 -0
  49. data/lib/pry/commands/ls/local_vars.rb +39 -0
  50. data/lib/pry/commands/ls/ls_entity.rb +70 -0
  51. data/lib/pry/commands/ls/methods.rb +57 -0
  52. data/lib/pry/commands/ls/methods_helper.rb +46 -0
  53. data/lib/pry/commands/ls/self_methods.rb +32 -0
  54. data/lib/pry/commands/play.rb +44 -10
  55. data/lib/pry/commands/pry_backtrace.rb +1 -2
  56. data/lib/pry/commands/raise_up.rb +2 -2
  57. data/lib/pry/commands/reload_code.rb +16 -19
  58. data/lib/pry/commands/ri.rb +7 -3
  59. data/lib/pry/commands/shell_command.rb +18 -13
  60. data/lib/pry/commands/shell_mode.rb +2 -4
  61. data/lib/pry/commands/show_doc.rb +5 -0
  62. data/lib/pry/commands/show_info.rb +8 -13
  63. data/lib/pry/commands/show_source.rb +15 -3
  64. data/lib/pry/commands/simple_prompt.rb +1 -1
  65. data/lib/pry/commands/toggle_color.rb +8 -4
  66. data/lib/pry/commands/watch_expression.rb +105 -0
  67. data/lib/pry/commands/watch_expression/expression.rb +38 -0
  68. data/lib/pry/commands/whereami.rb +18 -10
  69. data/lib/pry/commands/wtf.rb +3 -3
  70. data/lib/pry/config.rb +20 -254
  71. data/lib/pry/config/behavior.rb +139 -0
  72. data/lib/pry/config/convenience.rb +26 -0
  73. data/lib/pry/config/default.rb +165 -0
  74. data/lib/pry/core_extensions.rb +31 -21
  75. data/lib/pry/editor.rb +107 -103
  76. data/lib/pry/exceptions.rb +77 -0
  77. data/lib/pry/helpers/base_helpers.rb +22 -109
  78. data/lib/pry/helpers/command_helpers.rb +10 -8
  79. data/lib/pry/helpers/documentation_helpers.rb +1 -2
  80. data/lib/pry/helpers/text.rb +4 -5
  81. data/lib/pry/history.rb +46 -45
  82. data/lib/pry/history_array.rb +6 -1
  83. data/lib/pry/hooks.rb +9 -29
  84. data/lib/pry/indent.rb +6 -6
  85. data/lib/pry/input_completer.rb +242 -0
  86. data/lib/pry/input_lock.rb +132 -0
  87. data/lib/pry/inspector.rb +27 -0
  88. data/lib/pry/last_exception.rb +61 -0
  89. data/lib/pry/method.rb +82 -87
  90. data/lib/pry/{commands/edit/method_patcher.rb → method/patcher.rb} +41 -38
  91. data/lib/pry/module_candidate.rb +4 -14
  92. data/lib/pry/object_path.rb +82 -0
  93. data/lib/pry/output.rb +50 -0
  94. data/lib/pry/pager.rb +193 -48
  95. data/lib/pry/plugins.rb +1 -1
  96. data/lib/pry/prompt.rb +26 -0
  97. data/lib/pry/pry_class.rb +149 -230
  98. data/lib/pry/pry_instance.rb +302 -413
  99. data/lib/pry/rbx_path.rb +1 -1
  100. data/lib/pry/repl.rb +202 -0
  101. data/lib/pry/repl_file_loader.rb +20 -26
  102. data/lib/pry/rubygem.rb +13 -5
  103. data/lib/pry/terminal.rb +2 -1
  104. data/lib/pry/test/helper.rb +26 -41
  105. data/lib/pry/version.rb +1 -1
  106. data/lib/pry/wrapped_module.rb +45 -59
  107. metadata +62 -225
  108. data/.document +0 -2
  109. data/.gitignore +0 -16
  110. data/.travis.yml +0 -25
  111. data/.yardopts +0 -1
  112. data/CHANGELOG +0 -534
  113. data/CONTRIBUTORS +0 -55
  114. data/Gemfile +0 -12
  115. data/Rakefile +0 -140
  116. data/TODO +0 -117
  117. data/lib/pry/completion.rb +0 -321
  118. data/lib/pry/custom_completions.rb +0 -6
  119. data/lib/pry/rbx_method.rb +0 -13
  120. data/man/pry.1 +0 -195
  121. data/man/pry.1.html +0 -204
  122. data/man/pry.1.ronn +0 -141
  123. data/pry.gemspec +0 -29
  124. data/spec/Procfile +0 -3
  125. data/spec/cli_spec.rb +0 -78
  126. data/spec/code_object_spec.rb +0 -277
  127. data/spec/code_spec.rb +0 -219
  128. data/spec/command_helpers_spec.rb +0 -29
  129. data/spec/command_integration_spec.rb +0 -644
  130. data/spec/command_set_spec.rb +0 -627
  131. data/spec/command_spec.rb +0 -821
  132. data/spec/commands/amend_line_spec.rb +0 -247
  133. data/spec/commands/bang_spec.rb +0 -19
  134. data/spec/commands/cat_spec.rb +0 -164
  135. data/spec/commands/cd_spec.rb +0 -250
  136. data/spec/commands/disable_pry_spec.rb +0 -25
  137. data/spec/commands/edit_spec.rb +0 -727
  138. data/spec/commands/exit_all_spec.rb +0 -34
  139. data/spec/commands/exit_program_spec.rb +0 -19
  140. data/spec/commands/exit_spec.rb +0 -34
  141. data/spec/commands/find_method_spec.rb +0 -70
  142. data/spec/commands/gem_list_spec.rb +0 -26
  143. data/spec/commands/gist_spec.rb +0 -79
  144. data/spec/commands/help_spec.rb +0 -56
  145. data/spec/commands/hist_spec.rb +0 -181
  146. data/spec/commands/jump_to_spec.rb +0 -15
  147. data/spec/commands/ls_spec.rb +0 -181
  148. data/spec/commands/play_spec.rb +0 -140
  149. data/spec/commands/raise_up_spec.rb +0 -56
  150. data/spec/commands/save_file_spec.rb +0 -177
  151. data/spec/commands/show_doc_spec.rb +0 -510
  152. data/spec/commands/show_input_spec.rb +0 -17
  153. data/spec/commands/show_source_spec.rb +0 -782
  154. data/spec/commands/whereami_spec.rb +0 -203
  155. data/spec/completion_spec.rb +0 -241
  156. data/spec/control_d_handler_spec.rb +0 -58
  157. data/spec/documentation_helper_spec.rb +0 -73
  158. data/spec/editor_spec.rb +0 -79
  159. data/spec/exception_whitelist_spec.rb +0 -21
  160. data/spec/fixtures/candidate_helper1.rb +0 -11
  161. data/spec/fixtures/candidate_helper2.rb +0 -8
  162. data/spec/fixtures/example.erb +0 -5
  163. data/spec/fixtures/example_nesting.rb +0 -33
  164. data/spec/fixtures/show_source_doc_examples.rb +0 -15
  165. data/spec/fixtures/testrc +0 -2
  166. data/spec/fixtures/testrcbad +0 -2
  167. data/spec/fixtures/whereami_helper.rb +0 -6
  168. data/spec/helper.rb +0 -34
  169. data/spec/helpers/bacon.rb +0 -86
  170. data/spec/helpers/mock_pry.rb +0 -43
  171. data/spec/helpers/table_spec.rb +0 -105
  172. data/spec/history_array_spec.rb +0 -67
  173. data/spec/hooks_spec.rb +0 -522
  174. data/spec/indent_spec.rb +0 -301
  175. data/spec/input_stack_spec.rb +0 -90
  176. data/spec/method_spec.rb +0 -482
  177. data/spec/prompt_spec.rb +0 -60
  178. data/spec/pry_defaults_spec.rb +0 -419
  179. data/spec/pry_history_spec.rb +0 -99
  180. data/spec/pry_output_spec.rb +0 -95
  181. data/spec/pry_spec.rb +0 -515
  182. data/spec/run_command_spec.rb +0 -25
  183. data/spec/sticky_locals_spec.rb +0 -157
  184. data/spec/syntax_checking_spec.rb +0 -81
  185. data/spec/wrapped_module_spec.rb +0 -261
  186. data/wiki/Customizing-pry.md +0 -397
  187. data/wiki/Home.md +0 -4
@@ -1,6 +1,6 @@
1
1
  class Pry
2
2
  # A history array is an array to which you can only add elements. Older
3
- # entries are removed progressively, so that the aray never contains more than
3
+ # entries are removed progressively, so that the array never contains more than
4
4
  # N elements.
5
5
  #
6
6
  # History arrays are used by Pry to store the output of the last commands.
@@ -89,6 +89,11 @@ class Pry
89
89
  ((@count - size)...@count).map { |n| @hash[n] }
90
90
  end
91
91
 
92
+ # Returns [Hash] copy of the internal @hash history
93
+ def to_h
94
+ @hash.dup
95
+ end
96
+
92
97
  def pop!
93
98
  @hash.delete @count - 1
94
99
  @count -= 1
@@ -18,11 +18,11 @@ class Pry
18
18
  # @param [Hash] hash The hash to convert to `Pry::Hooks`.
19
19
  # @return [Pry::Hooks] The resulting `Pry::Hooks` instance.
20
20
  def self.from_hash(hash)
21
+ return hash if hash.instance_of?(self)
21
22
  instance = new
22
23
  hash.each do |k, v|
23
24
  instance.add_hook(k, nil, v)
24
25
  end
25
-
26
26
  instance
27
27
  end
28
28
 
@@ -49,22 +49,6 @@ class Pry
49
49
  @errors ||= []
50
50
  end
51
51
 
52
- # FIXME:
53
- # This is a hack to alert people of the new API.
54
- def [](event_name)
55
- warn "`Pry.hooks[]` is deprecated! Please use the new `Pry::Hooks` API! http://rubydoc.info/github/pry/pry/master/Pry/Hooks"
56
-
57
- get_hook(event_name, nil)
58
- end
59
-
60
- # FIXME:
61
- # This is a hack to alert people of the new API.
62
- def []=(event_name, callable)
63
- warn "`Pry.hooks[]=` is deprecated! Please use the new `Pry::Hooks` API! http://rubydoc.info/github/pry/pry/master/Pry/Hooks"
64
-
65
- add_hook(event_name, nil, callable)
66
- end
67
-
68
52
  # Destructively merge the contents of two `Pry:Hooks` instances.
69
53
  # @param [Pry::Hooks] other The `Pry::Hooks` instance to merge
70
54
  # @return [Pry:Hooks] Returns the receiver.
@@ -146,18 +130,14 @@ class Pry
146
130
  def exec_hook(event_name, *args, &block)
147
131
  @hooks[event_name] ||= []
148
132
 
149
- # silence warnings to get rid of 1.8's "warning: multiple values
150
- # for a block parameter" warnings
151
- Pry::Helpers::BaseHelpers.silence_warnings do
152
- @hooks[event_name].map do |hook_name, callable|
153
- begin
154
- callable.call(*args, &block)
155
- rescue RescuableException => e
156
- errors << e
157
- e
158
- end
159
- end.last
160
- end
133
+ @hooks[event_name].map do |hook_name, callable|
134
+ begin
135
+ callable.call(*args, &block)
136
+ rescue RescuableException => e
137
+ errors << e
138
+ e
139
+ end
140
+ end.last
161
141
  end
162
142
 
163
143
  # Return the number of hook functions registered for the `event_name` event.
@@ -94,8 +94,8 @@ class Pry
94
94
  indent = new
95
95
  lines = str.split("\n")
96
96
  n = line_number - 1
97
- to_indent = lines[0...n] + (lines[n] || "").split("def").first(1)
98
- indent.indent(to_indent.join("\n") + "\n")
97
+ to_indent = lines[0...n] << (lines[n] || "").split("def").first(1)
98
+ indent.indent(to_indent.join("\n") << "\n")
99
99
  indent.module_nesting
100
100
  end
101
101
 
@@ -320,7 +320,7 @@ class Pry
320
320
  # [ ["class", "Foo"], ["module", "Bar::Baz"], ["class <<", "self"] ]
321
321
  #
322
322
  # A nil value in the @module_nesting array happens in two places: either
323
- # when @awaiting_token is true and we're still waiting for the string to
323
+ # when @awaiting_class is true and we're still waiting for the string to
324
324
  # fill that space, or when a parse was rejected.
325
325
  #
326
326
  # At the moment this function is quite restricted about what formats it will
@@ -341,7 +341,7 @@ class Pry
341
341
  @module_nesting.last[1] = token if kind == :class
342
342
  @awaiting_class = false
343
343
  else
344
- # leave @nesting[-1][
344
+ # leave @module_nesting[-1]
345
345
  @awaiting_class = false
346
346
  end
347
347
  end
@@ -384,13 +384,13 @@ class Pry
384
384
  # @return [String]
385
385
  def correct_indentation(prompt, code, overhang=0)
386
386
  prompt = prompt.delete("\001\002")
387
- full_line = prompt + code
387
+ line_to_measure = Pry::Helpers::Text.strip_color(prompt) << code
388
388
  whitespace = ' ' * overhang
389
389
 
390
390
  _, cols = Terminal.screen_size
391
391
 
392
392
  cols = cols.to_i
393
- lines = cols != 0 ? (full_line.length / cols + 1) : 1
393
+ lines = (cols != 0 ? (line_to_measure.length / cols + 1) : 1).to_i
394
394
 
395
395
  if Pry::Helpers::BaseHelpers.windows_ansi?
396
396
  move_up = "\e[#{lines}F"
@@ -0,0 +1,242 @@
1
+ # taken from irb
2
+ # Implements tab completion for Readline in Pry
3
+ class Pry::InputCompleter
4
+ NUMERIC_REGEXP = /^(-?(0[dbo])?[0-9_]+(\.[0-9_]+)?([eE]-?[0-9]+)?)\.([^.]*)$/
5
+ ARRAY_REGEXP = /^([^\]]*\])\.([^.]*)$/
6
+ SYMBOL_REGEXP = /^(:[^:.]*)$/
7
+ SYMBOL_METHOD_CALL_REGEXP = /^(:[^:.]+)\.([^.]*)$/
8
+ REGEX_REGEXP = /^(\/[^\/]*\/)\.([^.]*)$/
9
+ PROC_OR_HASH_REGEXP = /^([^\}]*\})\.([^.]*)$/
10
+ TOPLEVEL_LOOKUP_REGEXP = /^::([A-Z][^:\.\(]*)$/
11
+ CONSTANT_REGEXP = /^([A-Z][A-Za-z0-9]*)$/
12
+ CONSTANT_OR_METHOD_REGEXP = /^([A-Z].*)::([^:.]*)$/
13
+ HEX_REGEXP = /^(-?0x[0-9a-fA-F_]+)\.([^.]*)$/
14
+ GLOBALVARIABLE_REGEXP = /^(\$[^.]*)$/
15
+ VARIABLE_REGEXP = /^([^."].*)\.([^.]*)$/
16
+
17
+ ReservedWords = [
18
+ "BEGIN", "END",
19
+ "alias", "and",
20
+ "begin", "break",
21
+ "case", "class",
22
+ "def", "defined", "do",
23
+ "else", "elsif", "end", "ensure",
24
+ "false", "for",
25
+ "if", "in",
26
+ "module",
27
+ "next", "nil", "not",
28
+ "or",
29
+ "redo", "rescue", "retry", "return",
30
+ "self", "super",
31
+ "then", "true",
32
+ "undef", "unless", "until",
33
+ "when", "while",
34
+ "yield" ]
35
+
36
+ Operators = [
37
+ "%", "&", "*", "**", "+", "-", "/",
38
+ "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
39
+ "[]", "[]=", "^", "!", "!=", "!~"
40
+ ]
41
+
42
+ WORD_ESCAPE_STR = " \t\n\"\\'`><=;|&{("
43
+
44
+ def initialize(input, pry = nil)
45
+ @pry = pry
46
+ @input = input
47
+ @input.basic_word_break_characters = WORD_ESCAPE_STR if @input.respond_to?(:basic_word_break_characters=)
48
+ @input.completion_append_character = nil if @input.respond_to?(:completion_append_character=)
49
+ end
50
+
51
+ #
52
+ # Return a new completion proc for use by Readline.
53
+ #
54
+ def call(str, options = {})
55
+ custom_completions = options[:custom_completions] || []
56
+ # if there are multiple contexts e.g. cd 1/2/3
57
+ # get new target for 1/2 and find candidates for 3
58
+ path, input = build_path(str)
59
+
60
+ if path.call.empty?
61
+ target = options[:target]
62
+ else
63
+ # Assume the user is tab-completing the 'cd' command
64
+ begin
65
+ target = Pry::ObjectPath.new(path.call, @pry.binding_stack).resolve.last
66
+ # but if that doesn't work, assume they're doing division with no spaces
67
+ rescue Pry::CommandError
68
+ target = options[:target]
69
+ end
70
+ end
71
+
72
+ begin
73
+ bind = target
74
+ # Complete stdlib symbols
75
+ case input
76
+ when REGEX_REGEXP # Regexp
77
+ receiver = $1
78
+ message = Regexp.quote($2)
79
+ candidates = Regexp.instance_methods.collect(&:to_s)
80
+ select_message(path, receiver, message, candidates)
81
+ when ARRAY_REGEXP # Array
82
+ receiver = $1
83
+ message = Regexp.quote($2)
84
+ candidates = Array.instance_methods.collect(&:to_s)
85
+ select_message(path, receiver, message, candidates)
86
+ when PROC_OR_HASH_REGEXP # Proc or Hash
87
+ receiver = $1
88
+ message = Regexp.quote($2)
89
+ candidates = Proc.instance_methods.collect(&:to_s)
90
+ candidates |= Hash.instance_methods.collect(&:to_s)
91
+ select_message(path, receiver, message, candidates)
92
+ when SYMBOL_REGEXP # Symbol
93
+ if Symbol.respond_to?(:all_symbols)
94
+ sym = Regexp.quote($1)
95
+ candidates = Symbol.all_symbols.collect{|s| ":" << s.id2name}
96
+ candidates.grep(/^#{sym}/)
97
+ else
98
+ []
99
+ end
100
+ when TOPLEVEL_LOOKUP_REGEXP # Absolute Constant or class methods
101
+ receiver = $1
102
+ candidates = Object.constants.collect(&:to_s)
103
+ candidates.grep(/^#{receiver}/).collect{|e| "::" << e}
104
+ when CONSTANT_REGEXP # Constant
105
+ message = $1
106
+ begin
107
+ context = target.eval("self")
108
+ context = context.class unless context.respond_to? :constants
109
+ candidates = context.constants.collect(&:to_s)
110
+ rescue
111
+ candidates = []
112
+ end
113
+ candidates = candidates.grep(/^#{message}/).collect(&path)
114
+ when CONSTANT_OR_METHOD_REGEXP # Constant or class methods
115
+ receiver = $1
116
+ message = Regexp.quote($2)
117
+ begin
118
+ candidates = eval("#{receiver}.constants.collect(&:to_s)", bind)
119
+ candidates |= eval("#{receiver}.methods.collect(&:to_s)", bind)
120
+ rescue Pry::RescuableException
121
+ candidates = []
122
+ end
123
+ candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e}
124
+ when SYMBOL_METHOD_CALL_REGEXP # method call on a Symbol
125
+ receiver = $1
126
+ message = Regexp.quote($2)
127
+ candidates = Symbol.instance_methods.collect(&:to_s)
128
+ select_message(path, receiver, message, candidates)
129
+ when NUMERIC_REGEXP
130
+ # Numeric
131
+ receiver = $1
132
+ message = Regexp.quote($5)
133
+ begin
134
+ candidates = eval(receiver, bind).methods.collect(&:to_s)
135
+ rescue Pry::RescuableException
136
+ candidates = []
137
+ end
138
+ select_message(path, receiver, message, candidates)
139
+ when HEX_REGEXP
140
+ # Numeric(0xFFFF)
141
+ receiver = $1
142
+ message = Regexp.quote($2)
143
+ begin
144
+ candidates = eval(receiver, bind).methods.collect(&:to_s)
145
+ rescue Pry::RescuableException
146
+ candidates = []
147
+ end
148
+ select_message(path, receiver, message, candidates)
149
+ when GLOBALVARIABLE_REGEXP # global
150
+ regmessage = Regexp.new(Regexp.quote($1))
151
+ candidates = global_variables.collect(&:to_s).grep(regmessage)
152
+ when VARIABLE_REGEXP # variable
153
+ receiver = $1
154
+ message = Regexp.quote($2)
155
+
156
+ gv = eval("global_variables", bind).collect(&:to_s)
157
+ lv = eval("local_variables", bind).collect(&:to_s)
158
+ cv = eval("self.class.constants", bind).collect(&:to_s)
159
+
160
+ if (gv | lv | cv).include?(receiver) or /^[A-Z]/ =~ receiver && /\./ !~ receiver
161
+ # foo.func and foo is local var. OR
162
+ # Foo::Bar.func
163
+ begin
164
+ candidates = eval("#{receiver}.methods", bind).collect(&:to_s)
165
+ rescue Pry::RescuableException
166
+ candidates = []
167
+ end
168
+ else
169
+ # func1.func2
170
+ candidates = []
171
+ ObjectSpace.each_object(Module){|m|
172
+ begin
173
+ name = m.name.to_s
174
+ rescue Pry::RescuableException
175
+ name = ""
176
+ end
177
+ next if name != "IRB::Context" and
178
+ /^(IRB|SLex|RubyLex|RubyToken)/ =~ name
179
+
180
+ # jruby doesn't always provide #instance_methods() on each
181
+ # object.
182
+ if m.respond_to?(:instance_methods)
183
+ candidates.concat m.instance_methods(false).collect(&:to_s)
184
+ end
185
+ }
186
+ candidates.sort!
187
+ candidates.uniq!
188
+ end
189
+ select_message(path, receiver, message, candidates)
190
+ when /^\.([^.]*)$/
191
+ # Unknown(maybe String)
192
+ receiver = ""
193
+ message = Regexp.quote($1)
194
+ candidates = String.instance_methods(true).collect(&:to_s)
195
+ select_message(path, receiver, message, candidates)
196
+ else
197
+ candidates = eval(
198
+ "methods | private_methods | local_variables | " \
199
+ "self.class.constants | instance_variables",
200
+ bind
201
+ ).collect(&:to_s)
202
+
203
+ if eval("respond_to?(:class_variables)", bind)
204
+ candidates += eval("class_variables", bind).collect(&:to_s)
205
+ end
206
+ candidates = (candidates|ReservedWords|custom_completions).grep(/^#{Regexp.quote(input)}/)
207
+ candidates.collect(&path)
208
+ end
209
+ rescue Pry::RescuableException
210
+ []
211
+ end
212
+ end
213
+
214
+ def select_message(path, receiver, message, candidates)
215
+ candidates.grep(/^#{message}/).collect { |e|
216
+ case e
217
+ when /^[a-zA-Z_]/
218
+ path.call(receiver + "." << e)
219
+ when /^[0-9]/
220
+ when *Operators
221
+ #receiver + " " << e
222
+ end
223
+ }.compact
224
+ end
225
+
226
+ # build_path seperates the input into two parts: path and input.
227
+ # input is the partial string that should be completed
228
+ # path is a proc that takes an input and builds a full path.
229
+ def build_path(input)
230
+ # check to see if the input is a regex
231
+ return proc {|i| i.to_s }, input if input[/\/\./]
232
+ trailing_slash = input.end_with?('/')
233
+ contexts = input.chomp('/').split(/\//)
234
+ input = contexts[-1]
235
+ path = proc do |i|
236
+ p = contexts[0..-2].push(i).join('/')
237
+ p += '/' if trailing_slash && !i.nil?
238
+ p
239
+ end
240
+ return path, input
241
+ end
242
+ end
@@ -0,0 +1,132 @@
1
+ require 'thread'
2
+
3
+ class Pry
4
+ # There is one InputLock per input (such as STDIN) as two REPLs on the same
5
+ # input makes things delirious. InputLock serializes accesses to the input so
6
+ # that threads to not conflict with each other. The latest thread to request
7
+ # ownership of the input wins.
8
+ class InputLock
9
+ class Interrupt < Exception; end
10
+
11
+ class << self
12
+ attr_accessor :input_locks
13
+ attr_accessor :global_lock
14
+ end
15
+
16
+ self.input_locks = {}
17
+ self.global_lock = Mutex.new
18
+
19
+ def self.for(input)
20
+ # XXX This method leaks memory, as we never unregister an input once we
21
+ # are done with it. Fortunately, the leak is tiny (or so we hope). In
22
+ # usual scenarios, we would leak the StringIO that is passed to be
23
+ # evaluated from the command line.
24
+ global_lock.synchronize do
25
+ input_locks[input] ||= Pry::InputLock.new
26
+ end
27
+ end
28
+
29
+ def initialize
30
+ @mutex = Mutex.new
31
+ @cond = ConditionVariable.new
32
+ @owners = []
33
+ @interruptible = false
34
+ end
35
+
36
+ # Adds ourselves to the ownership list. The last one in the list may access
37
+ # the input through interruptible_region().
38
+ def __with_ownership(&block)
39
+ @mutex.synchronize do
40
+ # Three cases:
41
+ # 1) There are no owners, in this case we are good to go.
42
+ # 2) The current owner of the input is not reading the input (it might
43
+ # just be evaluating some ruby that the user typed).
44
+ # The current owner will figure out that it cannot go back to reading
45
+ # the input since we are adding ourselves to the @owners list, which
46
+ # in turns makes us the current owner.
47
+ # 3) The owner of the input is in the interruptible region, reading from
48
+ # the input. It's safe to send an Interrupt exception to interrupt
49
+ # the owner. It will then proceed like in case 2).
50
+ # We wait until the owner sets the interruptible flag back
51
+ # to false, meaning that he's out of the interruptible region.
52
+ # Note that the owner may receive multiple interrupts since, but that
53
+ # should be okay (and trying to avoid it is futile anyway).
54
+ while @interruptible
55
+ @owners.last.raise Interrupt
56
+ @cond.wait(@mutex)
57
+ end
58
+ @owners << Thread.current
59
+ end
60
+
61
+ block.call
62
+
63
+ ensure
64
+ @mutex.synchronize do
65
+ # We are releasing any desire to have the input ownership by removing
66
+ # ourselves from the list.
67
+ @owners.delete(Thread.current)
68
+
69
+ # We need to wake up the thread at the end of the @owners list, but
70
+ # sadly Ruby doesn't allow us to choose which one we wake up, so we wake
71
+ # them all up.
72
+ @cond.broadcast
73
+ end
74
+ end
75
+
76
+ def with_ownership(&block)
77
+ # If we are in a nested with_ownership() call (nested pry context), we do nothing.
78
+ nested = @mutex.synchronize { @owners.include?(Thread.current) }
79
+ nested ? block.call : __with_ownership(&block)
80
+ end
81
+
82
+ def enter_interruptible_region
83
+ @mutex.synchronize do
84
+ # We patiently wait until we are the owner. This may happen as another
85
+ # thread calls with_ownership() because of a binding.pry happening in
86
+ # another thread.
87
+ @cond.wait(@mutex) until @owners.last == Thread.current
88
+
89
+ # We are the legitimate owner of the input. We mark ourselves as
90
+ # interruptible, so other threads can send us an Interrupt exception
91
+ # while we are blocking from reading the input.
92
+ @interruptible = true
93
+ end
94
+ end
95
+
96
+ def leave_interruptible_region
97
+ @mutex.synchronize do
98
+ # We check if we are still the owner, because we could have received an
99
+ # Interrupt right after the following @cond.broadcast, making us retry.
100
+ @interruptible = false if @owners.last == Thread.current
101
+ @cond.broadcast
102
+ end
103
+ rescue Interrupt
104
+ # We need to guard against a spurious interrupt delivered while we are
105
+ # trying to acquire the lock (the rescue block is no longer in our scope).
106
+ retry
107
+ end
108
+
109
+ def interruptible_region(&block)
110
+ enter_interruptible_region
111
+
112
+ # XXX Note that there is a chance that we get the interrupt right after
113
+ # the readline call succeeded, but we'll never know, and we will retry the
114
+ # call, discarding that piece of input.
115
+ block.call
116
+
117
+ rescue Interrupt
118
+ # We were asked to back off. The one requesting the interrupt will be
119
+ # waiting on the conditional for the interruptible flag to change to false.
120
+ # Note that there can be some inefficiency, as we could immediately
121
+ # succeed in enter_interruptible_region(), even before the one requesting
122
+ # the ownership has the chance to register itself as an owner.
123
+ # To mitigate the issue, we sleep a little bit.
124
+ leave_interruptible_region
125
+ sleep 0.01
126
+ retry
127
+
128
+ ensure
129
+ leave_interruptible_region
130
+ end
131
+ end
132
+ end