pry 0.9.7.4-i386-mswin32 → 0.9.8-i386-mswin32

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 (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
data/lib/pry/indent.rb CHANGED
@@ -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
 
data/lib/pry/method.rb CHANGED
@@ -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
data/lib/pry/plugins.rb CHANGED
@@ -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
data/lib/pry/pry_class.rb CHANGED
@@ -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