pry 0.9.9.6pre2-java → 0.9.10-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/CHANGELOG +41 -0
  2. data/CONTRIBUTORS +27 -26
  3. data/README.markdown +4 -4
  4. data/Rakefile +2 -2
  5. data/lib/pry.rb +25 -19
  6. data/lib/pry/cli.rb +31 -10
  7. data/lib/pry/code.rb +41 -83
  8. data/lib/pry/command.rb +87 -76
  9. data/lib/pry/command_set.rb +13 -20
  10. data/lib/pry/completion.rb +139 -121
  11. data/lib/pry/config.rb +4 -0
  12. data/lib/pry/core_extensions.rb +88 -31
  13. data/lib/pry/default_commands/cd.rb +31 -8
  14. data/lib/pry/default_commands/context.rb +4 -58
  15. data/lib/pry/default_commands/easter_eggs.rb +1 -1
  16. data/lib/pry/default_commands/editing.rb +21 -14
  17. data/lib/pry/default_commands/find_method.rb +5 -7
  18. data/lib/pry/default_commands/gist.rb +187 -0
  19. data/lib/pry/default_commands/hist.rb +6 -6
  20. data/lib/pry/default_commands/input_and_output.rb +73 -129
  21. data/lib/pry/default_commands/introspection.rb +107 -52
  22. data/lib/pry/default_commands/ls.rb +1 -1
  23. data/lib/pry/default_commands/misc.rb +0 -5
  24. data/lib/pry/default_commands/whereami.rb +92 -0
  25. data/lib/pry/helpers/base_helpers.rb +6 -1
  26. data/lib/pry/helpers/command_helpers.rb +30 -9
  27. data/lib/pry/helpers/documentation_helpers.rb +7 -7
  28. data/lib/pry/helpers/options_helpers.rb +1 -1
  29. data/lib/pry/helpers/text.rb +7 -9
  30. data/lib/pry/history.rb +15 -2
  31. data/lib/pry/hooks.rb +1 -1
  32. data/lib/pry/indent.rb +17 -10
  33. data/lib/pry/method.rb +35 -19
  34. data/lib/pry/module_candidate.rb +130 -0
  35. data/lib/pry/pry_class.rb +54 -22
  36. data/lib/pry/pry_instance.rb +71 -14
  37. data/lib/pry/repl_file_loader.rb +80 -0
  38. data/lib/pry/version.rb +1 -1
  39. data/lib/pry/wrapped_module.rb +121 -142
  40. data/pry.gemspec +13 -13
  41. data/test/candidate_helper1.rb +11 -0
  42. data/test/candidate_helper2.rb +8 -0
  43. data/test/helper.rb +16 -0
  44. data/test/test_code.rb +1 -1
  45. data/test/test_command.rb +364 -270
  46. data/test/test_command_integration.rb +235 -267
  47. data/test/test_completion.rb +36 -0
  48. data/test/test_control_d_handler.rb +45 -0
  49. data/test/test_default_commands/example.erb +5 -0
  50. data/test/test_default_commands/test_cd.rb +316 -11
  51. data/test/test_default_commands/test_context.rb +143 -192
  52. data/test/test_default_commands/test_documentation.rb +81 -14
  53. data/test/test_default_commands/test_find_method.rb +10 -2
  54. data/test/test_default_commands/test_input.rb +102 -111
  55. data/test/test_default_commands/test_introspection.rb +17 -12
  56. data/test/test_default_commands/test_ls.rb +8 -6
  57. data/test/test_default_commands/test_shell.rb +18 -15
  58. data/test/test_default_commands/test_show_source.rb +170 -44
  59. data/test/test_exception_whitelist.rb +6 -2
  60. data/test/test_hooks.rb +32 -0
  61. data/test/test_input_stack.rb +19 -16
  62. data/test/test_method.rb +0 -4
  63. data/test/test_prompt.rb +60 -0
  64. data/test/test_pry.rb +23 -31
  65. data/test/test_pry_defaults.rb +75 -57
  66. data/test/test_syntax_checking.rb +12 -11
  67. data/test/test_wrapped_module.rb +103 -0
  68. metadata +72 -26
@@ -4,14 +4,14 @@ class Pry
4
4
  # This class contains methods useful for extracting
5
5
  # documentation from methods and classes.
6
6
  module DocumentationHelpers
7
- def process_rdoc(comment, code_type)
7
+ def process_rdoc(comment)
8
8
  comment = comment.dup
9
- comment.gsub(/<code>(?:\s*\n)?(.*?)\s*<\/code>/m) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }.
9
+ comment.gsub(/<code>(?:\s*\n)?(.*?)\s*<\/code>/m) { Pry.color ? CodeRay.scan($1, :ruby).term : $1 }.
10
10
  gsub(/<em>(?:\s*\n)?(.*?)\s*<\/em>/m) { Pry.color ? "\e[1m#{$1}\e[0m": $1 }.
11
11
  gsub(/<i>(?:\s*\n)?(.*?)\s*<\/i>/m) { Pry.color ? "\e[1m#{$1}\e[0m" : $1 }.
12
12
  gsub(/\B\+(\w*?)\+\B/) { Pry.color ? "\e[32m#{$1}\e[0m": $1 }.
13
- gsub(/((?:^[ \t]+.+(?:\n+|\Z))+)/) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }.
14
- gsub(/`(?:\s*\n)?([^\e]*?)\s*`/) { "`#{Pry.color ? CodeRay.scan($1, code_type).term : $1}`" }
13
+ gsub(/((?:^[ \t]+.+(?:\n+|\Z))+)/) { Pry.color ? CodeRay.scan($1, :ruby).term : $1 }.
14
+ gsub(/`(?:\s*\n)?([^\e]*?)\s*`/) { "`#{Pry.color ? CodeRay.scan($1, :ruby).term : $1}`" }
15
15
  end
16
16
 
17
17
  def process_yardoc_tag(comment, tag)
@@ -31,13 +31,13 @@ class Pry
31
31
 
32
32
  def process_yardoc(comment)
33
33
  yard_tags = ["param", "return", "option", "yield", "attr", "attr_reader", "attr_writer",
34
- "deprecate", "example"]
34
+ "deprecate", "example", "raise"]
35
35
  (yard_tags - ["example"]).inject(comment) { |a, v| process_yardoc_tag(a, v) }.
36
36
  gsub(/^@(#{yard_tags.join("|")})/) { Pry.color ? "\e[33m#{$1}\e[0m": $1 }
37
37
  end
38
38
 
39
- def process_comment_markup(comment, code_type)
40
- process_yardoc process_rdoc(comment, code_type)
39
+ def process_comment_markup(comment)
40
+ process_yardoc process_rdoc(comment)
41
41
  end
42
42
 
43
43
  # @param [String] code
@@ -9,7 +9,7 @@ class Pry
9
9
  opt.on :M, "instance-methods", "Operate on instance methods."
10
10
  opt.on :m, :methods, "Operate on methods."
11
11
  opt.on :s, :super, "Select the 'super' method. Can be repeated to traverse the ancestors.", :as => :count
12
- opt.on :c, :context, "Select object context to run under.", true do |context|
12
+ opt.on :c, :context, "Select object context to run under.", :argument => true do |context|
13
13
  @method_target = Pry.binding_for(target.eval(context))
14
14
  end
15
15
  end
@@ -46,19 +46,18 @@ class Pry
46
46
  Pry.color ? "\e[1m#{text}\e[0m" : text.to_s
47
47
  end
48
48
 
49
- # Returns _text_ in the default foreground colour.
49
+ # Returns `text` in the default foreground colour.
50
50
  # Use this instead of "black" or "white" when you mean absence of colour.
51
51
  #
52
- # @param [String, #to_s]
53
- # @return [String] _text_
52
+ # @param [String, #to_s] text
53
+ # @return [String]
54
54
  def default(text)
55
55
  text.to_s
56
56
  end
57
57
  alias_method :bright_default, :bold
58
58
 
59
- # Executes _block_ with _Pry.color_ set to false.
60
- #
61
- # @param [Proc]
59
+ # Executes the block with `Pry.color` set to false.
60
+ # @yield
62
61
  # @return [void]
63
62
  def no_color &block
64
63
  boolean = Pry.config.color
@@ -68,9 +67,8 @@ class Pry
68
67
  Pry.config.color = boolean
69
68
  end
70
69
 
71
- # Executes _block_ with _Pry.config.pager_ set to false.
72
- #
73
- # @param [Proc]
70
+ # Executes the block with `Pry.config.pager` set to false.
71
+ # @yield
74
72
  # @return [void]
75
73
  def no_pager &block
76
74
  boolean = Pry.config.pager
@@ -4,9 +4,13 @@ class Pry
4
4
  class History
5
5
  attr_accessor :loader, :saver, :pusher, :clearer
6
6
 
7
+ # @return [Fixnum] Number of lines in history when Pry first loaded.
8
+ attr_reader :original_lines
9
+
7
10
  def initialize
8
11
  @history = []
9
12
  @saved_lines = 0
13
+ @original_lines = 0
10
14
  restore_default_behavior
11
15
  end
12
16
 
@@ -25,7 +29,7 @@ class Pry
25
29
  @pusher.call(line.chomp)
26
30
  @history << line.chomp
27
31
  end
28
- @saved_lines = @history.length
32
+ @saved_lines = @original_lines = @history.length
29
33
  end
30
34
 
31
35
  # Write this session's history using `History.saver`.
@@ -58,6 +62,15 @@ class Pry
58
62
  @saved_lines = 0
59
63
  end
60
64
 
65
+ # @return [Fixnum] The number of lines in history.
66
+ def history_line_count
67
+ @history.count
68
+ end
69
+
70
+ def session_line_count
71
+ @history.count - @original_lines
72
+ end
73
+
61
74
  # Return an Array containing all stored history.
62
75
  # @return [Array<String>] An Array containing all lines of history loaded
63
76
  # or entered by the user in the current session.
@@ -89,7 +102,7 @@ class Pry
89
102
  File.open(history_file, 'a') do |f|
90
103
  lines.each { |ln| f.puts ln }
91
104
  end
92
- rescue Errno::EACCES => error
105
+ rescue Errno::EACCES
93
106
  # We should probably create an option Pry.show_warnings?!?!?!
94
107
  warn 'Unable to write to your history file, history not saved'
95
108
  end
@@ -173,7 +173,7 @@ class Pry
173
173
 
174
174
  # Return a specific hook for a given event.
175
175
  # @param [Symbol] event_name The name of the event.
176
- # @param [Symbol[ hook_name The name of the hook
176
+ # @param [Symbol] hook_name The name of the hook
177
177
  # @return [#call] The requested hook.
178
178
  # @example
179
179
  # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" }
@@ -17,8 +17,11 @@ class Pry
17
17
  class Indent
18
18
  include Helpers::BaseHelpers
19
19
 
20
- # String containing the spaces to be inserted before the next line.
20
+ # @return [String] String containing the spaces to be inserted before the next line.
21
21
  attr_reader :indent_level
22
+
23
+ # @return [Array<String>] The stack of open tokens.
24
+ attr_reader :stack
22
25
 
23
26
  # The amount of spaces to insert for each indent level.
24
27
  SPACES = ' '
@@ -106,8 +109,7 @@ class Pry
106
109
  # @return [String] The indented version of +input+.
107
110
  #
108
111
  def indent(input)
109
- output = ''
110
- open_tokens = OPEN_TOKENS.keys
112
+ output = ''
111
113
  prefix = indent_level
112
114
 
113
115
  input.lines.each do |line|
@@ -234,8 +236,8 @@ class Pry
234
236
 
235
237
  # Given a string of Ruby code, use CodeRay to export the tokens.
236
238
  #
237
- # @param String The Ruby to lex.
238
- # @return [Array] An Array of pairs of [token_value, token_type]
239
+ # @param [String] string The Ruby to lex
240
+ # @return [Array] An Array of pairs of [token_value, token_type]
239
241
  def tokenize(string)
240
242
  tokens = CodeRay.scan(string, :ruby)
241
243
  tokens = tokens.tokens.each_slice(2) if tokens.respond_to?(:tokens) # Coderay 1.0.0
@@ -248,7 +250,7 @@ class Pry
248
250
  # normal strings (which can't be nested) we assume that CodeRay correctly pairs
249
251
  # open-and-close delimiters so we don't bother checking what they are.
250
252
  #
251
- # @param String The token (of type :delimiter)
253
+ # @param [String] token The token (of type :delimiter)
252
254
  def track_delimiter(token)
253
255
  case token
254
256
  when /^<<-(["'`]?)(.*)\\1/
@@ -297,7 +299,7 @@ class Pry
297
299
  cols = cols.to_i
298
300
  lines = cols != 0 ? (full_line.length / cols + 1) : 1
299
301
 
300
- if defined?(Win32::Console)
302
+ if Pry::Helpers::BaseHelpers.windows_ansi?
301
303
  move_up = "\e[#{lines}F"
302
304
  move_down = "\e[#{lines}E"
303
305
  else
@@ -320,9 +322,14 @@ class Pry
320
322
  Readline.respond_to?(:get_screen_size) && Readline.get_screen_size,
321
323
 
322
324
  # Otherwise try to use the environment (this may be out of date due
323
- # to window resizing, but it better than nothing).
324
- [ENV["ROWS"], ENV["COLUMNS"]]
325
- ].detect do |(rows, cols)|
325
+ # to window resizing, but it's better than nothing).
326
+ [ENV["ROWS"], ENV["COLUMNS"],
327
+
328
+ # If the user is running within ansicon, then use the screen size
329
+ # that it reports (same caveats apply as with ROWS and COLUMNS)
330
+ ENV['ANSICON'] =~ /\((.*)x(.*)\)/ && [$2, $1]
331
+ ]
332
+ ].detect do |(_, cols)|
326
333
  cols.to_i > 0
327
334
  end
328
335
  end
@@ -63,7 +63,7 @@ class Pry
63
63
  #
64
64
  def from_binding(b)
65
65
  meth_name = b.eval('__method__')
66
- if [:__script__, nil, :__binding__, :__binding_impl__].include?(meth_name)
66
+ if [:__script__, nil].include?(meth_name)
67
67
  nil
68
68
  else
69
69
  method = begin
@@ -210,7 +210,7 @@ class Pry
210
210
  # A new instance of `Pry::Method` wrapping the given `::Method`, `UnboundMethod`, or `Proc`.
211
211
  #
212
212
  # @param [::Method, UnboundMethod, Proc] method
213
- # @param [Hash] known_info, can be used to pre-cache expensive to compute stuff.
213
+ # @param [Hash] known_info Can be used to pre-cache expensive to compute stuff.
214
214
  # @return [Pry::Method]
215
215
  def initialize(method, known_info={})
216
216
  @method = method
@@ -253,17 +253,29 @@ class Pry
253
253
  code = strip_comments_from_c_code(info.source)
254
254
  end
255
255
  when :ruby
256
- if Helpers::BaseHelpers.rbx? && !pry_method?
257
- code = core_code
258
- elsif pry_method?
259
- code = Pry::Code.retrieve_complete_expression_from(Pry.line_buffer[source_line..-1])
260
- else
261
- code = @method.source
256
+ # clone of MethodSource.source_helper that knows to use our
257
+ # hacked version of source_location for rbx core methods, and
258
+ # our input buffer for methods defined in (pry)
259
+ file, line = *source_location
260
+ raise SourceNotFoundError, "Could not locate source for #{name_with_owner}!" unless file
261
+
262
+ begin
263
+ code = Pry::Code.from_file(file).expression_at(line)
264
+ rescue SyntaxError => e
265
+ raise MethodSource::SourceNotFoundError.new(e.message)
262
266
  end
263
267
  strip_leading_whitespace(code)
264
268
  end
265
269
  end
266
270
 
271
+ # Can we get the source code for this method?
272
+ # @return [Boolean]
273
+ def source?
274
+ !!source
275
+ rescue MethodSource::SourceNotFoundError
276
+ false
277
+ end
278
+
267
279
  # @return [String, nil] The documentation for the method, or `nil` if it's
268
280
  # unavailable.
269
281
  # @raise [CommandError] Raises when the method was defined in the REPL.
@@ -273,12 +285,10 @@ class Pry
273
285
  info = pry_doc_info
274
286
  info.docstring if info
275
287
  when :ruby
276
- if Helpers::BaseHelpers.rbx? && !pry_method?
277
- strip_leading_hash_and_whitespace_from_ruby_comments(core_doc)
288
+ if Helpers::BaseHelpers.rbx? && !pry_method?
289
+ strip_leading_hash_and_whitespace_from_ruby_comments(core_doc)
278
290
  elsif pry_method?
279
- # raise CommandError, "Can't view doc for a REPL-defined
280
- # method."
281
- strip_leading_hash_and_whitespace_from_ruby_comments(doc_for_pry_method)
291
+ strip_leading_hash_and_whitespace_from_ruby_comments(doc_for_pry_method)
282
292
  else
283
293
  strip_leading_hash_and_whitespace_from_ruby_comments(@method.comment)
284
294
  end
@@ -438,10 +448,10 @@ class Pry
438
448
 
439
449
  # FIXME: a very similar method to this exists on WrappedModule: extract_doc_for_candidate
440
450
  def doc_for_pry_method
441
- _, line = source_location
451
+ _, line_num = source_location
442
452
 
443
453
  buffer = ""
444
- Pry.line_buffer[0..(line - 1)].each do |line|
454
+ Pry.line_buffer[0..(line_num - 1)].each do |line|
445
455
  # Add any line that is a valid ruby comment,
446
456
  # but clear as soon as we hit a non comment line.
447
457
  if (line =~ /^\s*#/) || (line =~ /^\s*$/)
@@ -454,8 +464,8 @@ class Pry
454
464
  buffer
455
465
  end
456
466
 
457
- # @param [Class,Module] the ancestors to investigate
458
- # @return [Method] the unwrapped super-method
467
+ # @param [Class, Module] ancestors The ancestors to investigate
468
+ # @return [Method] The unwrapped super-method
459
469
  def super_using_ancestors(ancestors, times=1)
460
470
  next_owner = self.owner
461
471
  times.times do
@@ -504,8 +514,8 @@ class Pry
504
514
  #
505
515
  # @param [Object] receiver
506
516
  # @param [String] method_name
507
- def initialize(*args)
508
- @receiver, @name = *args
517
+ def initialize(receiver, method_name)
518
+ @receiver, @name = receiver, method_name
509
519
  end
510
520
 
511
521
  # Is the method undefined? (aka `Disowned`)
@@ -514,6 +524,12 @@ class Pry
514
524
  true
515
525
  end
516
526
 
527
+ # Can we get the source for this method?
528
+ # @return [Boolean] false
529
+ def source?
530
+ false
531
+ end
532
+
517
533
  # Get the hypothesized owner of the method.
518
534
  #
519
535
  # @return [Object]
@@ -0,0 +1,130 @@
1
+ require 'pry/helpers/documentation_helpers'
2
+ require 'forwardable'
3
+
4
+ class Pry
5
+ class WrappedModule
6
+
7
+ # This class represents a single candidate for a module/class definition.
8
+ # It provides access to the source, documentation, line and file
9
+ # for a monkeypatch (reopening) of a class/module.
10
+ class Candidate
11
+ extend Forwardable
12
+
13
+ # @return [String] The file where the module definition is located.
14
+ attr_reader :file
15
+
16
+ # @return [Fixnum] The line where the module definition is located.
17
+ attr_reader :line
18
+
19
+ # Methods to delegate to associated `Pry::WrappedModule instance`.
20
+ to_delegate = [:lines_for_file, :method_candidates, :name, :wrapped,
21
+ :yard_docs?, :number_of_candidates, :process_doc,
22
+ :strip_leading_whitespace]
23
+
24
+ def_delegators :@wrapper, *to_delegate
25
+ private(*to_delegate)
26
+
27
+ # @raise [Pry::CommandError] If `rank` is out of bounds.
28
+ # @param [Pry::WrappedModule] wrapper The associated
29
+ # `Pry::WrappedModule` instance that owns the candidates.
30
+ # @param [Fixnum] rank The rank of the candidate to
31
+ # retrieve. Passing 0 returns 'primary candidate' (the candidate with largest
32
+ # number of methods), passing 1 retrieves candidate with
33
+ # second largest number of methods, and so on, up to
34
+ # `Pry::WrappedModule#number_of_candidates() - 1`
35
+ def initialize(wrapper, rank)
36
+ @wrapper = wrapper
37
+
38
+ if number_of_candidates <= 0
39
+ raise CommandError, "Cannot find a definition for #{name} module!"
40
+ elsif rank > (number_of_candidates - 1)
41
+ raise CommandError, "No such module candidate. Allowed candidates range is from 0 to #{number_of_candidates - 1}"
42
+ end
43
+
44
+ @rank = rank
45
+ @file, @line = source_location
46
+ end
47
+
48
+ # @raise [Pry::CommandError] If source code cannot be found.
49
+ # @return [String] The source for the candidate, i.e the
50
+ # complete module/class definition.
51
+ def source
52
+ return @source if @source
53
+ raise CommandError, "Could not locate source for #{wrapped}!" if file.nil?
54
+
55
+ @source = strip_leading_whitespace(Pry::Code.from_file(file).expression_at(line, number_of_lines_in_first_chunk))
56
+ end
57
+
58
+ # @raise [Pry::CommandError] If documentation cannot be found.
59
+ # @return [String] The documentation for the candidate.
60
+ def doc
61
+ return @doc if @doc
62
+ raise CommandError, "Could not locate doc for #{wrapped}!" if file.nil?
63
+
64
+ @doc = process_doc(Pry::Code.from_file(file).comment_describing(line))
65
+ end
66
+
67
+ # @return [Array, nil] A `[String, Fixnum]` pair representing the
68
+ # source location (file and line) for the candidate or `nil`
69
+ # if no source location found.
70
+ def source_location
71
+ return @source_location if @source_location
72
+
73
+ mod_type_string = wrapped.class.to_s.downcase
74
+ file, line = first_method_source_location
75
+
76
+ return nil if !file.is_a?(String)
77
+
78
+ class_regexes = [/^\s*#{mod_type_string}\s*(\w*)(::)?#{wrapped.name.split(/::/).last}/,
79
+ /^\s*(::)?#{wrapped.name.split(/::/).last}\s*?=\s*?#{wrapped.class}/,
80
+ /^\s*(::)?#{wrapped.name.split(/::/).last}\.(class|instance)_eval/]
81
+
82
+ host_file_lines = lines_for_file(file)
83
+
84
+ search_lines = host_file_lines[0..(line - 2)]
85
+ idx = search_lines.rindex { |v| class_regexes.any? { |r| r =~ v } }
86
+
87
+ @source_location = [file, idx + 1]
88
+ rescue Pry::RescuableException
89
+ nil
90
+ end
91
+
92
+ private
93
+
94
+ # This method is used by `Candidate#source_location` as a
95
+ # starting point for the search for the candidate's definition.
96
+ # @return [Array] The source location of the base method used to
97
+ # calculate the source location of the candidate.
98
+ def first_method_source_location
99
+ @first_method_source_location ||= adjusted_source_location(method_candidates[@rank].first.source_location)
100
+ end
101
+
102
+ # @return [Array] The source location of the last method in this
103
+ # candidate's module definition.
104
+ def last_method_source_location
105
+ @end_method_source_location ||= adjusted_source_location(method_candidates[@rank].last.source_location)
106
+ end
107
+
108
+ # Return the number of lines between the start of the class definition
109
+ # and the start of the last method. We use this value so we can
110
+ # quickly grab these lines from the file (without having to
111
+ # check each intervening line for validity, which is expensive) speeding up source extraction.
112
+ # @return [Fixum] Number of lines.
113
+ def number_of_lines_in_first_chunk
114
+ end_method_line = last_method_source_location.last
115
+
116
+ end_method_line - line
117
+ end
118
+
119
+ def adjusted_source_location(sl)
120
+ file, line = sl
121
+
122
+ if file && RbxPath.is_core_path?(file)
123
+ file = RbxPath.convert_path_to_full(file)
124
+ end
125
+
126
+ [file, line]
127
+ end
128
+ end
129
+ end
130
+ end