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
@@ -20,29 +20,53 @@ class Pry
20
20
  def process(name)
21
21
  if module?(name)
22
22
  code_or_doc = process_module
23
- else method?
23
+ elsif method?
24
24
  code_or_doc = process_method
25
+ else
26
+ code_or_doc = process_alternatives
25
27
  end
26
28
 
27
29
  render_output(code_or_doc, opts)
28
30
  end
29
31
 
30
- def module_start_line(mod, candidate=0)
32
+ def process_alternatives
33
+ if args.empty? && internal_binding?(target)
34
+ mod = target_self.is_a?(Module) ? target_self : target_self.class
35
+ self.module_object = Pry::WrappedModule(mod)
36
+
37
+ process_module
38
+ else
39
+ process_method
40
+ end
41
+ end
42
+
43
+ def module_start_line(mod, candidate_rank=0)
31
44
  if opts.present?(:'base-one')
32
45
  1
33
46
  else
34
- mod.source_line_for_candidate(candidate)
47
+ mod.candidate(candidate_rank).line
35
48
  end
36
49
  end
37
50
 
38
51
  def use_line_numbers?
39
52
  opts.present?(:b) || opts.present?(:l)
40
53
  end
54
+
55
+ def attempt
56
+ rank = 0
57
+ begin
58
+ yield(rank)
59
+ rescue Pry::CommandError
60
+ raise if rank > (module_object.number_of_candidates - 1)
61
+ rank += 1
62
+ retry
63
+ end
64
+ end
41
65
  end
42
66
 
43
67
  Introspection = Pry::CommandSet.new do
44
68
 
45
- create_command "show-doc", "Show the comments above METH. Aliases: \?", :shellwords => false do
69
+ create_command "show-doc", "Show the documentation for a method or class. Aliases: \?", :shellwords => false do
46
70
  include ModuleIntrospectionHelpers
47
71
  include Helpers::DocumentationHelpers
48
72
  extend Helpers::BaseHelpers
@@ -51,7 +75,7 @@ class Pry
51
75
  Usage: show-doc [OPTIONS] [METH]
52
76
  Aliases: ?
53
77
 
54
- Show the comments above method METH. Tries instance methods first and then methods by default.
78
+ Show the documentation for a method or class. Tries instance methods first and then methods by default.
55
79
  e.g show-doc hello_method # docs for hello_method
56
80
  e.g show-doc Pry # docs for Pry class
57
81
  e.g show-doc Pry -a # docs for all definitions of Pry class (all monkey patches)
@@ -80,43 +104,36 @@ class Pry
80
104
  end
81
105
 
82
106
  def normal_module
83
- mod = module_object
84
-
85
- # source_file reveals the underlying .c file in case of core
86
- # classes on MRI. This is different to source_location, which
87
- # will return nil.
88
- if mod.yard_docs?
89
- file_name, line = mod.source_file, nil
107
+ doc = ""
108
+ if module_object.yard_docs?
109
+ file_name, line = module_object.yard_file, module_object.yard_line
110
+ doc << module_object.yard_doc
111
+ start_line = 1
90
112
  else
91
- file_name, line = mod.source_location
113
+ attempt do |rank|
114
+ file_name, line = module_object.candidate(rank).source_location
115
+ set_file_and_dir_locals(file_name)
116
+ doc << module_object.candidate(rank).doc
117
+ start_line = module_start_line(module_object, rank)
118
+ end
92
119
  end
93
120
 
94
- if mod.doc.empty?
95
- output.puts "No documentation found."
96
- ""
97
- else
98
- set_file_and_dir_locals(file_name) if !mod.yard_docs?
99
- doc = ""
100
- doc << mod.doc
121
+ doc = Code.new(doc, start_line, :text).
122
+ with_line_numbers(use_line_numbers?).to_s
101
123
 
102
- doc = Code.new(doc, module_start_line(mod), :text).
103
- with_line_numbers(use_line_numbers?).to_s
104
-
105
- doc.insert(0, "\n#{Pry::Helpers::Text.bold('From:')} #{file_name} @ line #{line ? line : "N/A"}:\n\n")
106
- end
124
+ doc.insert(0, "\n#{Pry::Helpers::Text.bold('From:')} #{file_name} @ line #{line ? line : "N/A"}:\n\n")
107
125
  end
108
126
 
109
127
  def all_modules
110
- mod = module_object
111
-
112
128
  doc = ""
113
- doc << "Found #{mod.number_of_candidates} candidates for `#{mod.name}` definition:\n"
114
- mod.number_of_candidates.times do |v|
129
+ doc << "Found #{module_object.number_of_candidates} candidates for `#{module_object.name}` definition:\n"
130
+ module_object.number_of_candidates.times do |v|
131
+ candidate = module_object.candidate(v)
115
132
  begin
116
- doc << "\nCandidate #{v+1}/#{mod.number_of_candidates}: #{mod.source_file_for_candidate(v)} @ #{mod.source_line_for_candidate(v)}:\n\n"
117
- dc = mod.doc_for_candidate(v)
118
- doc << (dc.empty? ? "No documentation found.\n" : dc)
133
+ doc << "\nCandidate #{v+1}/#{module_object.number_of_candidates}: #{candidate.file} @ #{candidate.line}:\n\n"
134
+ doc << candidate.doc
119
135
  rescue Pry::RescuableException
136
+ doc << "No documentation found.\n"
120
137
  next
121
138
  end
122
139
  end
@@ -124,14 +141,13 @@ class Pry
124
141
  end
125
142
 
126
143
  def process_method
127
- meth = method_object
128
- raise Pry::CommandError, "No documentation found." if meth.doc.nil? || meth.doc.empty?
144
+ raise Pry::CommandError, "No documentation found." if method_object.doc.nil? || method_object.doc.empty?
129
145
 
130
- doc = process_comment_markup(meth.doc, meth.source_type)
131
- output.puts make_header(meth, doc)
132
- output.puts "#{text.bold("Owner:")} #{meth.owner || "N/A"}"
133
- output.puts "#{text.bold("Visibility:")} #{meth.visibility}"
134
- output.puts "#{text.bold("Signature:")} #{meth.signature}"
146
+ doc = process_comment_markup(method_object.doc)
147
+ output.puts make_header(method_object, doc)
148
+ output.puts "#{text.bold("Owner:")} #{method_object.owner || "N/A"}"
149
+ output.puts "#{text.bold("Visibility:")} #{method_object.visibility}"
150
+ output.puts "#{text.bold("Signature:")} #{method_object.signature}"
135
151
  output.puts
136
152
 
137
153
  if use_line_numbers?
@@ -146,8 +162,8 @@ class Pry
146
162
  if opts.present?(:'base-one')
147
163
  1
148
164
  else
149
- if mod.source_line_for_candidate(candidate)
150
- mod.source_line_for_candidate(candidate) - mod.doc_for_candidate(candidate).lines.count
165
+ if mod.candidate(candidate).line
166
+ mod.candidate(candidate).line - mod.candidate(candidate).doc.lines.count
151
167
  else
152
168
  1
153
169
  end
@@ -196,13 +212,13 @@ class Pry
196
212
  include ModuleIntrospectionHelpers
197
213
  extend Helpers::BaseHelpers
198
214
 
199
- description "Show the source for METH or CLASS. Aliases: $, show-method"
215
+ description "Show the source for a method or class. Aliases: $, show-method"
200
216
 
201
217
  banner <<-BANNER
202
218
  Usage: show-source [OPTIONS] [METH|CLASS]
203
219
  Aliases: $, show-method
204
220
 
205
- Show the source for method METH or CLASS. Tries instance methods first and then methods by default.
221
+ Show the source for a method or class. Tries instance methods first and then methods by default.
206
222
 
207
223
  e.g: `show-source hello_method`
208
224
  e.g: `show-source -m hello_method`
@@ -250,11 +266,14 @@ class Pry
250
266
  end
251
267
 
252
268
  def normal_module
253
- mod = module_object
269
+ file_name = line = code = nil
270
+ attempt do |rank|
271
+ file_name, line = module_object.candidate(rank).source_location
272
+ set_file_and_dir_locals(file_name)
273
+ code = Code.from_module(module_object, module_start_line(module_object, rank), rank).
274
+ with_line_numbers(use_line_numbers?).to_s
275
+ end
254
276
 
255
- file_name, line = mod.source_location
256
- set_file_and_dir_locals(file_name)
257
- code = Code.from_module(mod, module_start_line(mod)).with_line_numbers(use_line_numbers?).to_s
258
277
  result = ""
259
278
  result << "\n#{Pry::Helpers::Text.bold('From:')} #{file_name} @ line #{line}:\n"
260
279
  result << "#{Pry::Helpers::Text.bold('Number of lines:')} #{code.lines.count}\n\n"
@@ -267,12 +286,15 @@ class Pry
267
286
  result = ""
268
287
  result << "Found #{mod.number_of_candidates} candidates for `#{mod.name}` definition:\n"
269
288
  mod.number_of_candidates.times do |v|
289
+ candidate = mod.candidate(v)
270
290
  begin
271
- code = Code.new(mod.source_for_candidate(v), module_start_line(mod, v)).with_line_numbers(use_line_numbers?).to_s
272
- result << "\nCandidate #{v+1}/#{mod.number_of_candidates}: #{mod.source_file_for_candidate(v)} @ line #{mod.source_line_for_candidate(v)}:\n"
291
+ result << "\nCandidate #{v+1}/#{mod.number_of_candidates}: #{candidate.file} @ line #{candidate.line}:\n"
292
+ code = Code.from_module(mod, module_start_line(mod, v), v).
293
+ with_line_numbers(use_line_numbers?).to_s
273
294
  result << "Number of lines: #{code.lines.count}\n\n"
274
295
  result << code
275
296
  rescue Pry::RescuableException
297
+ result << "\nNo code found.\n"
276
298
  next
277
299
  end
278
300
  end
@@ -341,12 +363,45 @@ class Pry
341
363
  Usage: ri [spec]
342
364
  e.g. ri Array#each
343
365
 
344
- Relies on the ri executable being available. See also: show-doc.
366
+ Relies on the rdoc gem being installed. See also: show-doc.
345
367
  BANNER
346
368
 
347
- def process
348
- run ".ri", *args
369
+ def process(spec)
370
+ # Lazily load RI
371
+ require 'rdoc/ri/driver'
372
+
373
+ unless defined? RDoc::RI::PryDriver
374
+
375
+ # Subclass RI so that it formats its output nicely, and uses `lesspipe`.
376
+ subclass = Class.new(RDoc::RI::Driver) # the hard way.
377
+
378
+ subclass.class_eval do
379
+ def page
380
+ Pry::Helpers::BaseHelpers.lesspipe {|less| yield less}
381
+ end
382
+
383
+ def formatter(io)
384
+ if @formatter_klass then
385
+ @formatter_klass.new
386
+ else
387
+ RDoc::Markup::ToAnsi.new
388
+ end
389
+ end
390
+ end
391
+
392
+ RDoc::RI.const_set :PryDriver, subclass # hook it up!
393
+ end
394
+
395
+ # Spin-up an RI insance.
396
+ ri = RDoc::RI::PryDriver.new :use_stdout => true, :interactive => false
397
+
398
+ begin
399
+ ri.display_names [spec] # Get the documentation (finally!)
400
+ rescue RDoc::RI::Driver::NotFoundError => e
401
+ output.puts "error: '#{e.name}' not found"
402
+ end
349
403
  end
404
+
350
405
  end
351
406
 
352
407
  end
@@ -35,7 +35,7 @@ class Pry
35
35
 
36
36
  opt.on :i, "ivars", "Show instance variables (in blue) and class variables (in bright blue)"
37
37
 
38
- opt.on :G, "grep", "Filter output by regular expression", :optional => false
38
+ opt.on :G, "grep", "Filter output by regular expression", :argument => true
39
39
  if jruby?
40
40
  opt.on :J, "all-java", "Show all the aliases for methods from java (default is to show only prettiest)"
41
41
  end
@@ -33,11 +33,6 @@ class Pry
33
33
  output.puts "Reloaded #{file_name}."
34
34
  end
35
35
  end
36
-
37
- command "req", "Require file(s) and expand their paths." do |*args|
38
- args.each { |file_name| load File.expand_path(file_name) }
39
- end
40
-
41
36
  end
42
37
  end
43
38
  end
@@ -0,0 +1,92 @@
1
+
2
+ class Pry
3
+ module DefaultCommands
4
+ Whereami = Pry::CommandSet.new do
5
+ create_command "whereami" do
6
+ description "Show code surrounding the current context."
7
+ group 'Context'
8
+ banner <<-BANNER
9
+ Usage: whereami [-q] [N]
10
+
11
+ Describe the current location. If you use `binding.pry` inside a
12
+ method then whereami will print out the source for that method.
13
+
14
+ If a number is passed, then N lines before and after the current line
15
+ will be shown instead of the method itself.
16
+
17
+ The `-q` flag can be used to suppress error messages in the case that
18
+ there's no code to show. This is used by pry in the default
19
+ before_session hook to show you when you arrive at a `binding.pry`.
20
+
21
+ When pry was started on an Object and there is no associated method,
22
+ whereami will instead output a brief description of the current
23
+ object.
24
+ BANNER
25
+
26
+ def setup
27
+ @method = Pry::Method.from_binding(target)
28
+ @file = target.eval('__FILE__')
29
+ @line = target.eval('__LINE__')
30
+ end
31
+
32
+ def options(opt)
33
+ opt.on :q, :quiet, "Don't display anything in case of an error"
34
+ end
35
+
36
+ def code
37
+ @code ||= if show_method?
38
+ Pry::Code.from_method(@method)
39
+ else
40
+ Pry::Code.from_file(@file).around(@line, window_size)
41
+ end
42
+ end
43
+
44
+ def location
45
+ "#{@file} @ line #{show_method? ? @method.source_line : @line} #{@method && @method.name_with_owner}"
46
+ end
47
+
48
+ def process
49
+ if opts.quiet? && (internal_binding?(target) || !code?)
50
+ return
51
+ elsif internal_binding?(target)
52
+ if target_self == TOPLEVEL_BINDING.eval("self")
53
+ output.puts "At the top level."
54
+ else
55
+ output.puts "Inside #{Pry.view_clip(target_self)}."
56
+ end
57
+ return
58
+ end
59
+
60
+ set_file_and_dir_locals(@file)
61
+
62
+ output.puts "\n#{text.bold('From:')} #{location}:\n\n"
63
+ output.puts code.with_line_numbers.with_marker(@line)
64
+ output.puts
65
+ end
66
+
67
+ private
68
+
69
+ def show_method?
70
+ args.empty? && @method && @method.source? && @method.source_range.count < 20 &&
71
+ # These checks are needed in case of an eval with a binding and file/line
72
+ # numbers set to outside the function. As in rails' use of ERB.
73
+ @method.source_file == @file && @method.source_range.include?(@line)
74
+ end
75
+
76
+ def code?
77
+ !!code
78
+ rescue MethodSource::SourceNotFoundError
79
+ false
80
+ end
81
+
82
+ def window_size
83
+ if args.empty?
84
+ Pry.config.default_window_size
85
+ else
86
+ args.first.to_i
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -70,7 +70,7 @@ class Pry
70
70
  end
71
71
 
72
72
  def use_ansi_codes?
73
- defined?(Win32::Console) || ENV['TERM'] && ENV['TERM'] != "dumb"
73
+ windows_ansi? || ENV['TERM'] && ENV['TERM'] != "dumb"
74
74
  end
75
75
 
76
76
  def colorize_code(code)
@@ -100,6 +100,11 @@ class Pry
100
100
  RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
101
101
  end
102
102
 
103
+ # are we able to use ansi on windows?
104
+ def windows_ansi?
105
+ defined?(Win32::Console) || ENV['ANSICON']
106
+ end
107
+
103
108
  # are we on Jruby platform?
104
109
  def jruby?
105
110
  RbConfig::CONFIG['ruby_install_name'] == 'jruby'
@@ -39,13 +39,17 @@ class Pry
39
39
  [file, line_num]
40
40
  end
41
41
 
42
+ def internal_binding?(target)
43
+ m = target.eval("__method__").to_s
44
+ # class_eval is here because of http://jira.codehaus.org/browse/JRUBY-6753
45
+ ["__binding__", "__pry__", "class_eval"].include?(m)
46
+ end
47
+
42
48
  def get_method_or_raise(name, target, opts={}, omit_help=false)
43
49
  meth = Pry::Method.from_str(name, target, opts)
44
50
 
45
51
  if name && !meth
46
52
  command_error("The method '#{name}' could not be found.", omit_help)
47
- elsif !meth
48
- command_error("No method name given, and context is not a method.", omit_help, NonMethodContextError)
49
53
  end
50
54
 
51
55
  (opts[:super] || 0).times do
@@ -56,6 +60,10 @@ class Pry
56
60
  end
57
61
  end
58
62
 
63
+ if !meth || (!name && internal_binding?(target))
64
+ command_error("No method name given, and context is not a method.", omit_help, NonMethodContextError)
65
+ end
66
+
59
67
  set_file_and_dir_locals(meth.source_file)
60
68
  meth
61
69
  end
@@ -69,7 +77,7 @@ class Pry
69
77
  header = "\n#{Pry::Helpers::Text.bold('From:')} #{meth.source_file} "
70
78
 
71
79
  if meth.source_type == :c
72
- header << "in Ruby Core (C Method):\n"
80
+ header << "(C Method):\n"
73
81
  else
74
82
  header << "@ line #{meth.source_line}:\n"
75
83
  end
@@ -107,7 +115,7 @@ class Pry
107
115
  # not to block the process from which they were launched (in this case, Pry).
108
116
  # For those editors, return the flag that produces the desired behavior.
109
117
  def blocking_flag_for_editor(block)
110
- case Pry.config.editor
118
+ case editor_name
111
119
  when /^emacsclient/
112
120
  '--no-wait' unless block
113
121
  when /^[gm]vim/
@@ -129,7 +137,7 @@ class Pry
129
137
  # special case for 1st line
130
138
  return file_name if line_number <= 1
131
139
 
132
- case Pry.config.editor
140
+ case editor_name
133
141
  when /^[gm]?vi/, /^emacs/, /^nano/, /^pico/, /^gedit/, /^kate/
134
142
  "+#{line_number} #{file_name}"
135
143
  when /^mate/, /^geany/
@@ -149,6 +157,20 @@ class Pry
149
157
  end
150
158
  end
151
159
 
160
+ # Get the name of the binary that Pry.config.editor points to.
161
+ #
162
+ # This is useful for deciding which flags we pass to the editor as
163
+ # we can just use the program's name and ignore any absolute paths.
164
+ #
165
+ # @example
166
+ # Pry.config.editor="/home/conrad/bin/textmate -w"
167
+ # editor_name
168
+ # # => textmate
169
+ #
170
+ def editor_name
171
+ File.basename(Pry.config.editor).split(" ").first
172
+ end
173
+
152
174
  # Remove any common leading whitespace from every line in `text`.
153
175
  #
154
176
  # This can be used to make a HEREDOC line up with the left margin, without
@@ -161,10 +183,7 @@ class Pry
161
183
  # "Ut enim ad minim veniam."
162
184
  # USAGE
163
185
  #
164
- # @param [String] The text from which to remove indentation
165
- # @return [String], The text with indentation stripped.
166
- #
167
- # @copyright Heavily based on textwrap.dedent from Python, which is:
186
+ # Heavily based on textwrap.dedent from Python, which is:
168
187
  # Copyright (C) 1999-2001 Gregory P. Ward.
169
188
  # Copyright (C) 2002, 2003 Python Software Foundation.
170
189
  # Written by Greg Ward <gward@python.net>
@@ -172,6 +191,8 @@ class Pry
172
191
  # Licensed under <http://docs.python.org/license.html>
173
192
  # From <http://hg.python.org/cpython/file/6b9f0a6efaeb/Lib/textwrap.py>
174
193
  #
194
+ # @param [String] text The text from which to remove indentation
195
+ # @return [String] The text with indentation stripped.
175
196
  def unindent(text)
176
197
  # Empty blank lines
177
198
  text = text.sub(/^[ \t]+$/, '')