pry 0.9.7.4-java → 0.9.8-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/.gitignore +2 -3
  2. data/CHANGELOG +43 -0
  3. data/README.markdown +3 -1
  4. data/Rakefile +51 -32
  5. data/bin/pry +2 -80
  6. data/lib/pry.rb +33 -26
  7. data/lib/pry/cli.rb +152 -0
  8. data/lib/pry/code.rb +351 -0
  9. data/lib/pry/command.rb +422 -0
  10. data/lib/pry/command_set.rb +259 -129
  11. data/lib/pry/commands.rb +0 -1
  12. data/lib/pry/config.rb +43 -9
  13. data/lib/pry/default_commands/context.rb +109 -92
  14. data/lib/pry/default_commands/documentation.rb +174 -63
  15. data/lib/pry/default_commands/easter_eggs.rb +26 -2
  16. data/lib/pry/default_commands/gems.rb +65 -37
  17. data/lib/pry/default_commands/input.rb +175 -243
  18. data/lib/pry/default_commands/introspection.rb +173 -112
  19. data/lib/pry/default_commands/ls.rb +96 -114
  20. data/lib/pry/default_commands/shell.rb +175 -70
  21. data/lib/pry/helpers/base_helpers.rb +7 -2
  22. data/lib/pry/helpers/command_helpers.rb +71 -77
  23. data/lib/pry/helpers/options_helpers.rb +10 -41
  24. data/lib/pry/helpers/text.rb +24 -4
  25. data/lib/pry/history.rb +55 -17
  26. data/lib/pry/history_array.rb +2 -0
  27. data/lib/pry/hooks.rb +252 -0
  28. data/lib/pry/indent.rb +9 -5
  29. data/lib/pry/method.rb +149 -50
  30. data/lib/pry/plugins.rb +12 -4
  31. data/lib/pry/pry_class.rb +69 -26
  32. data/lib/pry/pry_instance.rb +187 -115
  33. data/lib/pry/version.rb +1 -1
  34. data/lib/pry/wrapped_module.rb +73 -0
  35. data/man/pry.1 +195 -0
  36. data/man/pry.1.html +204 -0
  37. data/man/pry.1.ronn +141 -0
  38. data/pry.gemspec +29 -32
  39. data/test/helper.rb +32 -36
  40. data/test/test_cli.rb +78 -0
  41. data/test/test_code.rb +201 -0
  42. data/test/test_command.rb +327 -0
  43. data/test/test_command_integration.rb +512 -0
  44. data/test/test_command_set.rb +338 -12
  45. data/test/test_completion.rb +1 -1
  46. data/test/test_default_commands.rb +1 -2
  47. data/test/test_default_commands/test_context.rb +27 -5
  48. data/test/test_default_commands/test_documentation.rb +20 -8
  49. data/test/test_default_commands/test_input.rb +84 -45
  50. data/test/test_default_commands/test_introspection.rb +74 -17
  51. data/test/test_default_commands/test_ls.rb +9 -36
  52. data/test/test_default_commands/test_shell.rb +240 -13
  53. data/test/test_hooks.rb +490 -0
  54. data/test/test_indent.rb +2 -0
  55. data/test/test_method.rb +60 -0
  56. data/test/test_pry.rb +29 -904
  57. data/test/test_pry_defaults.rb +380 -0
  58. data/test/test_pry_history.rb +24 -24
  59. data/test/test_syntax_checking.rb +63 -0
  60. data/test/test_wrapped_module.rb +71 -0
  61. metadata +50 -39
  62. data/lib/pry/command_context.rb +0 -53
  63. data/lib/pry/command_processor.rb +0 -181
  64. data/lib/pry/extended_commands/user_command_api.rb +0 -65
  65. data/test/test_command_processor.rb +0 -176
@@ -43,7 +43,11 @@ class Pry
43
43
  # Collection of token types that should be ignored. Without this list
44
44
  # keywords such as "class" inside strings would cause the code to be
45
45
  # indented incorrectly.
46
- IGNORE_TOKENS = [:space, :content, :string, :delimiter, :method, :ident]
46
+ #
47
+ # :pre_constant and :preserved_constant are the CodeRay 0.9.8 and 1.0.0
48
+ # classifications of "true", "false", and "nil".
49
+ IGNORE_TOKENS = [:space, :content, :string, :delimiter, :method, :ident,
50
+ :constant, :pre_constant, :predefined_constant]
47
51
 
48
52
  # Tokens that indicate the end of a statement (i.e. that, if they appear
49
53
  # directly before an "if" indicates that that if applies to the same line,
@@ -199,11 +203,11 @@ class Pry
199
203
  end
200
204
 
201
205
  if defined?(Win32::Console)
202
- move_up = "\e[#{lines}F"
203
- move_down = "\e[#{lines}E"
206
+ move_up = "\e[#{lines}F"
207
+ move_down = "\e[#{lines}E"
204
208
  else
205
- move_up = "\e[#{lines}A\e[0G"
206
- move_down = "\e[#{lines}B\e[0G"
209
+ move_up = "\e[#{lines}A\e[0G"
210
+ move_down = "\e[#{lines}B\e[0G"
207
211
  end
208
212
  whitespace = ' ' * overhang
209
213
 
@@ -1,4 +1,17 @@
1
+ # -*- coding: utf-8 -*-
1
2
  class Pry
3
+ class << self
4
+ # If the given object is a `Pry::Method`, return it unaltered. If it's
5
+ # anything else, return it wrapped in a `Pry::Method` instance.
6
+ def Method(obj)
7
+ if obj.is_a? Pry::Method
8
+ obj
9
+ else
10
+ Pry::Method.new(obj)
11
+ end
12
+ end
13
+ end
14
+
2
15
  class Method
3
16
  include RbxMethod if Helpers::BaseHelpers.rbx?
4
17
 
@@ -48,7 +61,43 @@ class Pry
48
61
  if [:__script__, nil, :__binding__, :__binding_impl__].include?(meth_name)
49
62
  nil
50
63
  else
51
- new(b.eval("method(:#{meth_name})"))
64
+ method = begin
65
+ new(b.eval("method(#{meth_name.to_s.inspect})"))
66
+ rescue NameError, NoMethodError
67
+ Disowned.new(b.eval('self'), meth_name.to_s)
68
+ end
69
+
70
+ # it's possible in some cases that the method we find by this approach is a sub-method of
71
+ # the one we're currently in, consider:
72
+ #
73
+ # class A; def b; binding.pry; end; end
74
+ # class B < A; def b; super; end; end
75
+ #
76
+ # Given that we can normally find the source_range of methods, and that we know which
77
+ # __FILE__ and __LINE__ the binding is at, we can hope to disambiguate these cases.
78
+ #
79
+ # This obviously won't work if the source is unavaiable for some reason, or if both
80
+ # methods have the same __FILE__ and __LINE__, or if we're in rbx where b.eval('__LINE__')
81
+ # is broken.
82
+ #
83
+ guess = method
84
+
85
+ while guess
86
+ # needs rescue if this is a Disowned method or a C method or something...
87
+ # TODO: Fix up the exception handling so we don't need a bare rescue
88
+ if (guess.source_file && guess.source_range rescue false) &&
89
+ File.expand_path(guess.source_file) == File.expand_path(b.eval('__FILE__')) &&
90
+ guess.source_range.include?(b.eval('__LINE__'))
91
+ return guess
92
+ else
93
+ guess = guess.super
94
+ end
95
+ end
96
+
97
+ # Uhoh... none of the methods in the chain had the right __FILE__ and __LINE__
98
+ # This may be caused by rbx https://github.com/rubinius/rubinius/issues/953,
99
+ # or other unknown circumstances (TODO: we should warn the user when this happens)
100
+ method
52
101
  end
53
102
  end
54
103
 
@@ -128,7 +177,7 @@ class Pry
128
177
  end
129
178
 
130
179
  # Acts like send but ignores any methods defined below Object or Class in the
131
- # inheritance heirarchy.
180
+ # inheritance hierarchy.
132
181
  # This is required to introspect methods on objects like Net::HTTP::Get that
133
182
  # have overridden the `method` method.
134
183
  def safe_send(obj, method, *args, &block)
@@ -166,6 +215,27 @@ class Pry
166
215
  @method.name.to_s
167
216
  end
168
217
 
218
+ # Get the owner of the method as a Pry::Module
219
+ # @return [Pry::Module]
220
+ def wrapped_owner
221
+ @wrapped_owner ||= Pry::WrappedModule.new(owner)
222
+ end
223
+
224
+ # Is the method undefined? (aka `Disowned`)
225
+ # @return [Boolean] false
226
+ def undefined?
227
+ false
228
+ end
229
+
230
+ # Get the name of the method including the class on which it was defined.
231
+ # @example
232
+ # method(:puts).method_name
233
+ # => "Kernel.puts"
234
+ # @return [String]
235
+ def name_with_owner
236
+ "#{wrapped_owner.method_prefix}#{name}"
237
+ end
238
+
169
239
  # @return [String, nil] The source code of the method, or `nil` if it's unavailable.
170
240
  def source
171
241
  @source ||= case source_type
@@ -174,11 +244,11 @@ class Pry
174
244
  if info and info.source
175
245
  code = strip_comments_from_c_code(info.source)
176
246
  end
177
- when :rbx
178
- strip_leading_whitespace(core_code)
179
247
  when :ruby
180
- if pry_method?
181
- code = Pry.new(:input => StringIO.new(Pry.line_buffer[source_line..-1].join), :prompt => proc {""}, :hooks => {}).r
248
+ if Helpers::BaseHelpers.rbx? && core?
249
+ code = core_code
250
+ elsif pry_method?
251
+ code = Pry.new(:input => StringIO.new(Pry.line_buffer[source_line..-1].join), :prompt => proc {""}, :hooks => Pry::Hooks.new).r
182
252
  else
183
253
  code = @method.source
184
254
  end
@@ -194,10 +264,10 @@ class Pry
194
264
  when :c
195
265
  info = pry_doc_info
196
266
  info.docstring if info
197
- when :rbx
198
- strip_leading_hash_and_whitespace_from_ruby_comments(core_doc)
199
267
  when :ruby
200
- if pry_method?
268
+ if Helpers::BaseHelpers.rbx? && core?
269
+ strip_leading_hash_and_whitespace_from_ruby_comments(core_doc)
270
+ elsif pry_method?
201
271
  raise CommandError, "Can't view doc for a REPL-defined method."
202
272
  else
203
273
  strip_leading_hash_and_whitespace_from_ruby_comments(@method.comment)
@@ -206,14 +276,9 @@ class Pry
206
276
  end
207
277
 
208
278
  # @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.
279
+ # `:ruby` for Ruby methods or `:c` for methods written in C.
211
280
  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
281
+ source_location.nil? ? :c : :ruby
217
282
  end
218
283
 
219
284
  # @return [String, nil] The name of the file the method is defined in, or
@@ -235,6 +300,12 @@ class Pry
235
300
  source_location.nil? ? nil : source_location.last
236
301
  end
237
302
 
303
+ # @return [Range, nil] The range of lines in `source_file` which contain
304
+ # the method's definition, or `nil` if that information is unavailable.
305
+ def source_range
306
+ source_location.nil? ? nil : (source_line)...(source_line + source.lines.count)
307
+ end
308
+
238
309
  # @return [Symbol] The visibility of the method. May be `:public`,
239
310
  # `:protected`, or `:private`.
240
311
  def visibility
@@ -286,43 +357,11 @@ class Pry
286
357
  Pry::Method.new(sup) if sup
287
358
  end
288
359
 
289
- # @return [Symbol, nil] The original name the method was defined under,
360
+ # @return [String, nil] The original name the method was defined under,
290
361
  # before any aliasing, or `nil` if it can't be determined.
291
362
  def original_name
292
363
  return nil if source_type != :ruby
293
-
294
- first_line = source.lines.first
295
- return nil if first_line.strip !~ /^def /
296
-
297
- if RUBY_VERSION =~ /^1\.9/ && RUBY_ENGINE == "ruby"
298
- require 'ripper'
299
-
300
- # Ripper is ok with an extraneous end, so we don't need to worry about
301
- # whether it's a one-liner.
302
- tree = Ripper::SexpBuilder.new(first_line + ";end").parse
303
-
304
- name = tree.flatten(2).each do |lst|
305
- break lst[1] if lst[0] == :@ident
306
- end
307
-
308
- name.is_a?(String) ? name : nil
309
- else
310
- require 'ruby_parser'
311
-
312
- # RubyParser breaks if there's an extra end, so we'll just rescue
313
- # and try again.
314
- tree = begin
315
- RubyParser.new.parse(first_line + ";end")
316
- rescue Racc::ParseError
317
- RubyParser.new.parse(first_line)
318
- end
319
-
320
- name = tree.each_cons(2) do |a, b|
321
- break a if b.is_a?(Array) && b.first == :args
322
- end
323
-
324
- name.is_a?(Symbol) ? name.to_s : nil
325
- end
364
+ method_name_from_first_line(source.lines.first)
326
365
  end
327
366
 
328
367
  # @return [Boolean] Was the method defined outside a source file?
@@ -409,5 +448,65 @@ class Pry
409
448
  end
410
449
  next_owner.instance_method(name) rescue nil
411
450
  end
451
+
452
+ # @param [String] first_ln The first line of a method definition.
453
+ # @return [String, nil]
454
+ def method_name_from_first_line(first_ln)
455
+ return nil if first_ln.strip !~ /^def /
456
+
457
+ tokens = CodeRay.scan(first_ln, :ruby)
458
+ tokens = tokens.tokens.each_slice(2) if tokens.respond_to?(:tokens)
459
+ tokens.each_cons(2) do |t1, t2|
460
+ if t2.last == :method || t2.last == :ident && t1 == [".", :operator]
461
+ return t2.first
462
+ end
463
+ end
464
+
465
+ nil
466
+ end
467
+
468
+ # A Disowned Method is one that's been removed from the class on which it was defined.
469
+ #
470
+ # e.g.
471
+ # class C
472
+ # def foo
473
+ # C.send(:undefine_method, :foo)
474
+ # Pry::Method.from_binding(binding)
475
+ # end
476
+ # end
477
+ #
478
+ # In this case we assume that the "owner" is the singleton class of the receiver.
479
+ #
480
+ # This occurs mainly in Sinatra applications.
481
+ class Disowned < Method
482
+ attr_reader :receiver, :name
483
+
484
+ # Create a new Disowned method.
485
+ #
486
+ # @param [Object] receiver
487
+ # @param [String] method_name
488
+ def initialize(*args)
489
+ @receiver, @name = *args
490
+ end
491
+
492
+ # Is the method undefined? (aka `Disowned`)
493
+ # @return [Boolean] true
494
+ def undefined?
495
+ true
496
+ end
497
+
498
+ # Get the hypothesized owner of the method.
499
+ #
500
+ # @return [Object]
501
+ def owner
502
+ class << receiver; self; end
503
+ end
504
+
505
+ # Raise a more useful error message instead of trying to forward to nil.
506
+ def method_missing(meth_name, *args, &block)
507
+ raise "Cannot call '#{meth_name}' on an undef'd method." if method(:name).respond_to?(meth_name)
508
+ Object.instance_method(:method_missing).bind(self).call(meth_name, *args, &block)
509
+ end
510
+ end
412
511
  end
413
512
  end
@@ -9,7 +9,7 @@ class Pry
9
9
  end
10
10
 
11
11
  def method_missing(*args)
12
- $stderr.puts "Warning: The plugin '#{@name}' was not found! (no gem found)"
12
+ warn "Warning: The plugin '#{@name}' was not found! (no gem found)"
13
13
  end
14
14
  end
15
15
 
@@ -32,13 +32,21 @@ class Pry
32
32
  self.enabled = true
33
33
  end
34
34
 
35
+ # Load the Command line options defined by this plugin (if they exist)
36
+ def load_cli_options
37
+ cli_options_file = File.join(spec.full_gem_path, "lib/#{spec.name}/cli.rb")
38
+ require cli_options_file if File.exists?(cli_options_file)
39
+ end
35
40
  # Activate the plugin (require the gem - enables/loads the
36
- # plugin immediately at point of call, even if plugin is disabled)
41
+ # plugin immediately at point of call, even if plugin is
42
+ # disabled)
43
+ # Does not reload plugin if it's already active.
37
44
  def activate!
38
45
  begin
39
46
  require gem_name if !active?
40
- rescue LoadError
41
- $stderr.puts "Warning: The plugin '#{gem_name}' was not found! (gem found but could not be loaded)"
47
+ rescue LoadError => e
48
+ warn "Warning: The plugin '#{gem_name}' was not found! (gem found but could not be loaded)"
49
+ warn e
42
50
  end
43
51
  self.active = true
44
52
  self.enabled = true
@@ -73,6 +73,30 @@ class Pry
73
73
  end
74
74
  end
75
75
 
76
+ # Trap interrupts on jruby, and make them behave like MRI so we can
77
+ # catch them.
78
+ def self.load_traps
79
+ trap('INT'){ raise Interrupt }
80
+ end
81
+
82
+ # Do basic setup for initial session.
83
+ # Including: loading .pryrc, loading plugins, loading requires, and
84
+ # loading history.
85
+ def self.initial_session_setup
86
+
87
+ return if !initial_session?
88
+
89
+ # note these have to be loaded here rather than in pry_instance as
90
+ # we only want them loaded once per entire Pry lifetime.
91
+ load_rc if Pry.config.should_load_rc
92
+ load_plugins if Pry.config.should_load_plugins
93
+ load_requires if Pry.config.should_load_requires
94
+ load_history if Pry.config.history.should_load
95
+ load_traps if Pry.config.should_trap_interrupts
96
+
97
+ @initial_session = false
98
+ end
99
+
76
100
  # Start a Pry REPL.
77
101
  # This method also loads the files specified in `Pry::RC_FILES` the
78
102
  # first time it is invoked.
@@ -82,19 +106,34 @@ class Pry
82
106
  # @example
83
107
  # Pry.start(Object.new, :input => MyInput.new)
84
108
  def self.start(target=TOPLEVEL_BINDING, options={})
85
- if initial_session?
86
- # note these have to be loaded here rather than in pry_instance as
87
- # we only want them loaded once per entire Pry lifetime, not
88
- # multiple times per each new session (i.e in debugging)
89
- load_rc if Pry.config.should_load_rc
90
- load_plugins if Pry.config.plugins.enabled
91
- load_requires if Pry.config.should_load_requires
92
- load_history if Pry.config.history.should_load
93
-
94
- @initial_session = false
109
+ target = Pry.binding_for(target)
110
+ initial_session_setup
111
+
112
+ # create the Pry instance to manage the session
113
+ pry_instance = new(options)
114
+
115
+ # save backtrace
116
+ pry_instance.backtrace = caller
117
+
118
+ # if Pry was started via binding.pry, elide that from the backtrace.
119
+ pry_instance.backtrace.shift if pry_instance.backtrace.first =~ /pry.*core_extensions.*pry/
120
+
121
+ # yield the binding_stack to the hook for modification
122
+ pry_instance.exec_hook(
123
+ :when_started,
124
+ target,
125
+ options,
126
+ pry_instance
127
+ )
128
+
129
+ if !pry_instance.binding_stack.empty?
130
+ head = pry_instance.binding_stack.pop
131
+ else
132
+ head = target
95
133
  end
96
134
 
97
- new(options).repl(target)
135
+ # Enter the matrix
136
+ pry_instance.repl(head)
98
137
  end
99
138
 
100
139
  # An inspector that clips the output to `max_length` chars.
@@ -120,17 +159,12 @@ class Pry
120
159
 
121
160
  # Load Readline history if required.
122
161
  def self.load_history
123
- Pry.history.load(history_file) if File.exists?(history_file)
162
+ Pry.history.load
124
163
  end
125
164
 
126
165
  # Save new lines of Readline history if required.
127
166
  def self.save_history
128
- Pry.history.save(history_file)
129
- end
130
-
131
- # Get the full path of the history_path for pry.
132
- def self.history_file
133
- File.expand_path(Pry.config.history.file)
167
+ Pry.history.save
134
168
  end
135
169
 
136
170
  # @return [Boolean] Whether this is the first time a Pry session has
@@ -165,14 +199,19 @@ class Pry
165
199
 
166
200
  output = options[:show_output] ? options[:output] : StringIO.new
167
201
 
168
- Pry.new(:output => output, :input => StringIO.new(command_string), :commands => options[:commands], :prompt => proc {""}, :hooks => {}).rep(options[:context])
202
+ Pry.new(:output => output, :input => StringIO.new(command_string), :commands => options[:commands], :prompt => proc {""}, :hooks => Pry::Hooks.new).rep(options[:context])
169
203
  end
170
204
 
171
205
  def self.default_editor_for_platform
172
- if RUBY_PLATFORM =~ /mswin|mingw/
173
- ENV['VISUAL'] || ENV['EDITOR'] || "notepad"
206
+ return ENV['VISUAL'] if ENV['VISUAL'] and not ENV['VISUAL'].empty?
207
+ return ENV['EDITOR'] if ENV['EDITOR'] and not ENV['EDITOR'].empty?
208
+
209
+ if Helpers::BaseHelpers.windows?
210
+ 'notepad'
174
211
  else
175
- ENV['VISUAL'] || ENV['EDITOR'] || "nano"
212
+ %w(editor nano vi).detect do |editor|
213
+ system("which #{editor} > /dev/null 2>&1")
214
+ end
176
215
  end
177
216
  end
178
217
 
@@ -183,22 +222,26 @@ class Pry
183
222
  config.prompt = DEFAULT_PROMPT
184
223
  config.print = DEFAULT_PRINT
185
224
  config.exception_handler = DEFAULT_EXCEPTION_HANDLER
186
- config.exception_window_size = 5
187
225
  config.exception_whitelist = DEFAULT_EXCEPTION_WHITELIST
226
+ config.default_window_size = 5
188
227
  config.hooks = DEFAULT_HOOKS
189
228
  config.input_stack = []
190
- config.color = Pry::Helpers::BaseHelpers.use_ansi_codes?
229
+ config.color = Helpers::BaseHelpers.use_ansi_codes?
191
230
  config.pager = true
192
231
  config.system = DEFAULT_SYSTEM
193
232
  config.editor = default_editor_for_platform
194
233
  config.should_load_rc = true
234
+ config.should_trap_interrupts = Helpers::BaseHelpers.jruby?
195
235
  config.disable_auto_reload = false
196
236
  config.command_prefix = ""
197
237
  config.auto_indent = true
198
238
  config.correct_indent = true
239
+ config.collision_warning = false
240
+
241
+ config.gist ||= OpenStruct.new
242
+ config.gist.inspecter = proc(&:pretty_inspect)
199
243
 
200
- config.plugins ||= OpenStruct.new
201
- config.plugins.enabled = true
244
+ config.should_load_plugins = true
202
245
 
203
246
  config.requires ||= []
204
247
  config.should_load_requires = true