pry 0.9.8.4 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG +26 -0
  3. data/README.markdown +3 -3
  4. data/lib/pry.rb +9 -1
  5. data/lib/pry/code.rb +93 -0
  6. data/lib/pry/command.rb +35 -22
  7. data/lib/pry/command_set.rb +97 -67
  8. data/lib/pry/config.rb +63 -10
  9. data/lib/pry/core_extensions.rb +24 -18
  10. data/lib/pry/default_commands/context.rb +72 -12
  11. data/lib/pry/default_commands/easter_eggs.rb +4 -0
  12. data/lib/pry/default_commands/editing.rb +43 -15
  13. data/lib/pry/default_commands/find_method.rb +171 -0
  14. data/lib/pry/default_commands/hist.rb +10 -6
  15. data/lib/pry/default_commands/introspection.rb +183 -30
  16. data/lib/pry/default_commands/ls.rb +77 -7
  17. data/lib/pry/default_commands/misc.rb +1 -0
  18. data/lib/pry/default_commands/navigating_pry.rb +1 -8
  19. data/lib/pry/helpers/base_helpers.rb +10 -2
  20. data/lib/pry/helpers/command_helpers.rb +23 -40
  21. data/lib/pry/helpers/documentation_helpers.rb +65 -0
  22. data/lib/pry/indent.rb +17 -4
  23. data/lib/pry/method.rb +61 -45
  24. data/lib/pry/pry_class.rb +9 -3
  25. data/lib/pry/pry_instance.rb +99 -65
  26. data/lib/pry/rbx_method.rb +2 -9
  27. data/lib/pry/version.rb +1 -1
  28. data/lib/pry/wrapped_module.rb +236 -1
  29. data/pry.gemspec +5 -5
  30. data/test/helper.rb +22 -0
  31. data/test/test_command.rb +29 -0
  32. data/test/test_command_integration.rb +193 -10
  33. data/test/test_command_set.rb +82 -17
  34. data/test/test_default_commands/test_cd.rb +16 -0
  35. data/test/test_default_commands/test_context.rb +61 -0
  36. data/test/test_default_commands/test_documentation.rb +163 -43
  37. data/test/test_default_commands/test_find_method.rb +42 -0
  38. data/test/test_default_commands/test_input.rb +32 -0
  39. data/test/test_default_commands/test_introspection.rb +50 -197
  40. data/test/test_default_commands/test_ls.rb +22 -0
  41. data/test/test_default_commands/test_show_source.rb +306 -0
  42. data/test/test_pry.rb +3 -3
  43. data/test/test_pry_defaults.rb +21 -0
  44. data/test/test_sticky_locals.rb +81 -1
  45. data/test/test_syntax_checking.rb +7 -6
  46. metadata +22 -14
@@ -1,6 +1,7 @@
1
1
  class Pry
2
2
  module DefaultCommands
3
3
  Misc = Pry::CommandSet.new do
4
+
4
5
  command "toggle-color", "Toggle syntax highlighting." do
5
6
  Pry.color = !Pry.color
6
7
  output.puts "Syntax highlighting #{Pry.color ? "on" : "off"}"
@@ -72,19 +72,13 @@ class Pry
72
72
 
73
73
  def process
74
74
  if _pry_.binding_stack.one?
75
- # when breaking out of top-level then behave like `exit-all`
76
- process_exit_all
75
+ _pry_.run_command "exit-all #{arg_string}"
77
76
  else
78
77
  # otherwise just pop a binding and return user supplied value
79
78
  process_pop_and_return
80
79
  end
81
80
  end
82
81
 
83
- def process_exit_all
84
- _pry_.binding_stack.clear
85
- throw(:breakout, target.eval(arg_string))
86
- end
87
-
88
82
  def process_pop_and_return
89
83
  popped_object = _pry_.binding_stack.pop.eval('self')
90
84
 
@@ -111,4 +105,3 @@ class Pry
111
105
  end
112
106
  end
113
107
  end
114
-
@@ -110,6 +110,14 @@ class Pry
110
110
  RbConfig::CONFIG['ruby_install_name'] == 'rbx'
111
111
  end
112
112
 
113
+ def mri_18?
114
+ RUBY_VERSION =~ /1.8/ && RbConfig::CONFIG['ruby_install_name'] == 'ruby'
115
+ end
116
+
117
+ def mri_19?
118
+ RUBY_VERSION =~ /1.9/ && RbConfig::CONFIG['ruby_install_name'] == 'ruby'
119
+ end
120
+
113
121
  # a simple pager for systems without `less`. A la windows.
114
122
  def simple_pager(text, output=output())
115
123
  text_array = text.lines.to_a
@@ -138,7 +146,7 @@ class Pry
138
146
  # Sys.
139
147
  $stdout
140
148
  end
141
-
149
+
142
150
  if text.lines.count < page_size || !Pry.pager
143
151
  out.puts text
144
152
  return
@@ -151,7 +159,7 @@ class Pry
151
159
  lesspipe { |less| less.puts text }
152
160
  end
153
161
  rescue Errno::ENOENT
154
- simple_pager(text, output)
162
+ simple_pager(text, out)
155
163
  rescue Errno::EPIPE
156
164
  end
157
165
 
@@ -77,48 +77,13 @@ class Pry
77
77
  header << "#{Pry::Helpers::Text.bold("Number of lines:")} #{content.each_line.count.to_s}\n"
78
78
  end
79
79
 
80
- def process_rdoc(comment, code_type)
81
- comment = comment.dup
82
- comment.gsub(/<code>(?:\s*\n)?(.*?)\s*<\/code>/m) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }.
83
- gsub(/<em>(?:\s*\n)?(.*?)\s*<\/em>/m) { Pry.color ? "\e[1m#{$1}\e[0m": $1 }.
84
- gsub(/<i>(?:\s*\n)?(.*?)\s*<\/i>/m) { Pry.color ? "\e[1m#{$1}\e[0m" : $1 }.
85
- gsub(/\B\+(\w*?)\+\B/) { Pry.color ? "\e[32m#{$1}\e[0m": $1 }.
86
- gsub(/((?:^[ \t]+.+(?:\n+|\Z))+)/) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }.
87
- gsub(/`(?:\s*\n)?(.*?)\s*`/) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }
88
- end
89
-
90
- def process_yardoc_tag(comment, tag)
91
- in_tag_block = nil
92
- comment.lines.map do |v|
93
- if in_tag_block && v !~ /^\S/
94
- Pry::Helpers::Text.strip_color Pry::Helpers::Text.strip_color(v)
95
- elsif in_tag_block
96
- in_tag_block = false
97
- v
98
- else
99
- in_tag_block = true if v =~ /^@#{tag}/
100
- v
101
- end
102
- end.join
103
- end
104
-
105
- def process_yardoc(comment)
106
- yard_tags = ["param", "return", "option", "yield", "attr", "attr_reader", "attr_writer",
107
- "deprecate", "example"]
108
- (yard_tags - ["example"]).inject(comment) { |a, v| process_yardoc_tag(a, v) }.
109
- gsub(/^@(#{yard_tags.join("|")})/) { Pry.color ? "\e[33m#{$1}\e[0m": $1 }
110
- end
111
-
112
- def process_comment_markup(comment, code_type)
113
- process_yardoc process_rdoc(comment, code_type)
114
- end
115
-
116
- def invoke_editor(file, line)
117
- raise CommandError, "Please set Pry.config.editor or export $EDITOR" unless Pry.config.editor
80
+ def invoke_editor(file, line, reloading)
81
+ raise CommandError, "Please set Pry.config.editor or export $VISUAL or $EDITOR" unless Pry.config.editor
118
82
  if Pry.config.editor.respond_to?(:call)
119
- editor_invocation = Pry.config.editor.call(file, line)
83
+ args = [file, line, reloading][0...(Pry.config.editor.arity)]
84
+ editor_invocation = Pry.config.editor.call(*args)
120
85
  else
121
- editor_invocation = "#{Pry.config.editor} #{start_line_syntax_for_editor(file, line)}"
86
+ editor_invocation = "#{Pry.config.editor} #{blocking_flag_for_editor(reloading)} #{start_line_syntax_for_editor(file, line)}"
122
87
  end
123
88
  return nil unless editor_invocation
124
89
 
@@ -138,6 +103,22 @@ class Pry
138
103
  end
139
104
  end
140
105
 
106
+ # Some editors that run outside the terminal allow you to control whether or
107
+ # not to block the process from which they were launched (in this case, Pry).
108
+ # For those editors, return the flag that produces the desired behavior.
109
+ def blocking_flag_for_editor(block)
110
+ case Pry.config.editor
111
+ when /^emacsclient/
112
+ '--no-wait' unless block
113
+ when /^[gm]vim/
114
+ '--nofork' if block
115
+ when /^jedit/
116
+ '-wait' if block
117
+ when /^mate/, /^subl/
118
+ '-w' if block
119
+ end
120
+ end
121
+
141
122
  # Return the syntax for a given editor for starting the editor
142
123
  # and moving to a particular line within that file
143
124
  def start_line_syntax_for_editor(file_name, line_number)
@@ -153,6 +134,8 @@ class Pry
153
134
  "+#{line_number} #{file_name}"
154
135
  when /^mate/, /^geany/
155
136
  "-l #{line_number} #{file_name}"
137
+ when /^subl/
138
+ "#{file_name}:#{line_number}"
156
139
  when /^uedit32/
157
140
  "#{file_name}/#{line_number}"
158
141
  when /^jedit/
@@ -0,0 +1,65 @@
1
+ class Pry
2
+ module Helpers
3
+
4
+ # This class contains methods useful for extracting
5
+ # documentation from methods and classes.
6
+ module DocumentationHelpers
7
+ def process_rdoc(comment, code_type)
8
+ comment = comment.dup
9
+ comment.gsub(/<code>(?:\s*\n)?(.*?)\s*<\/code>/m) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }.
10
+ gsub(/<em>(?:\s*\n)?(.*?)\s*<\/em>/m) { Pry.color ? "\e[1m#{$1}\e[0m": $1 }.
11
+ gsub(/<i>(?:\s*\n)?(.*?)\s*<\/i>/m) { Pry.color ? "\e[1m#{$1}\e[0m" : $1 }.
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)?(.*?)\s*`/) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }
15
+ end
16
+
17
+ def process_yardoc_tag(comment, tag)
18
+ in_tag_block = nil
19
+ comment.lines.map do |v|
20
+ if in_tag_block && v !~ /^\S/
21
+ Pry::Helpers::Text.strip_color Pry::Helpers::Text.strip_color(v)
22
+ elsif in_tag_block
23
+ in_tag_block = false
24
+ v
25
+ else
26
+ in_tag_block = true if v =~ /^@#{tag}/
27
+ v
28
+ end
29
+ end.join
30
+ end
31
+
32
+ def process_yardoc(comment)
33
+ yard_tags = ["param", "return", "option", "yield", "attr", "attr_reader", "attr_writer",
34
+ "deprecate", "example"]
35
+ (yard_tags - ["example"]).inject(comment) { |a, v| process_yardoc_tag(a, v) }.
36
+ gsub(/^@(#{yard_tags.join("|")})/) { Pry.color ? "\e[33m#{$1}\e[0m": $1 }
37
+ end
38
+
39
+ def process_comment_markup(comment, code_type)
40
+ process_yardoc process_rdoc(comment, code_type)
41
+ end
42
+
43
+ # @param [String] code
44
+ # @return [String]
45
+ def strip_comments_from_c_code(code)
46
+ code.sub(/\A\s*\/\*.*?\*\/\s*/m, '')
47
+ end
48
+
49
+ # @param [String] comment
50
+ # @return [String]
51
+ def strip_leading_hash_and_whitespace_from_ruby_comments(comment)
52
+ comment = comment.dup
53
+ comment.gsub!(/\A\#+?$/, '')
54
+ comment.gsub!(/^\s*#/, '')
55
+ strip_leading_whitespace(comment)
56
+ end
57
+
58
+ # @param [String] text
59
+ # @return [String]
60
+ def strip_leading_whitespace(text)
61
+ Pry::Helpers::CommandHelpers.unindent(text)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,6 +1,14 @@
1
1
  require 'coderay'
2
2
 
3
3
  class Pry
4
+ begin
5
+ require 'io/console'
6
+ rescue LoadError
7
+ IO_CONSOLE_AVAILABLE = false
8
+ else
9
+ IO_CONSOLE_AVAILABLE = true
10
+ end
11
+
4
12
  ##
5
13
  # Pry::Indent is a class that can be used to indent a number of lines
6
14
  # containing Ruby code similar as to how IRB does it (but better). The class
@@ -187,12 +195,17 @@ class Pry
187
195
  # Return a string which, when printed, will rewrite the previous line with
188
196
  # the correct indentation. Mostly useful for fixing 'end'.
189
197
  #
190
- # @param [String] full_line The full line of input, including the prompt.
198
+ # @param [String] prompt The user's prompt
199
+ # @param [String] code The code the user just typed in.
191
200
  # @param [Fixnum] overhang (0) The number of chars to erase afterwards (i.e.,
192
201
  # the difference in length between the old line and the new one).
193
202
  # @return [String]
194
- def correct_indentation(full_line, overhang=0)
195
- if Readline.respond_to?(:get_screen_size)
203
+ def correct_indentation(prompt, code, overhang=0)
204
+ full_line = prompt + code
205
+ if IO_CONSOLE_AVAILABLE && $stdout.tty?
206
+ _, cols = $stdout.winsize
207
+ lines = full_line.length / cols + 1
208
+ elsif Readline.respond_to?(:get_screen_size)
196
209
  _, cols = Readline.get_screen_size
197
210
  lines = full_line.length / cols + 1
198
211
  elsif ENV['COLUMNS'] && ENV['COLUMNS'] != ''
@@ -211,7 +224,7 @@ class Pry
211
224
  end
212
225
  whitespace = ' ' * overhang
213
226
 
214
- "#{move_up}#{full_line}#{whitespace}#{move_down}"
227
+ "#{move_up}#{prompt}#{CodeRay.scan(code, :ruby).term}#{whitespace}#{move_down}"
215
228
  end
216
229
  end
217
230
  end
@@ -1,4 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
+ require 'pry/helpers/documentation_helpers'
3
+
2
4
  class Pry
3
5
  class << self
4
6
  # If the given object is a `Pry::Method`, return it unaltered. If it's
@@ -12,8 +14,11 @@ class Pry
12
14
  end
13
15
  end
14
16
 
17
+ # This class wraps the normal `Method` and `UnboundMethod` classes
18
+ # to provide extra functionality useful to Pry.
15
19
  class Method
16
20
  include RbxMethod if Helpers::BaseHelpers.rbx?
21
+ include Helpers::DocumentationHelpers
17
22
 
18
23
  class << self
19
24
  # Given a string representing a method name and optionally a binding to
@@ -62,7 +67,7 @@ class Pry
62
67
  nil
63
68
  else
64
69
  method = begin
65
- new(b.eval("method(#{meth_name.to_s.inspect})"))
70
+ new(b.eval("Object.instance_method(:method).bind(self).call(#{meth_name.to_s.inspect})"))
66
71
  rescue NameError, NoMethodError
67
72
  Disowned.new(b.eval('self'), meth_name.to_s)
68
73
  end
@@ -126,16 +131,18 @@ class Pry
126
131
 
127
132
  # Get all of the instance methods of a `Class` or `Module`
128
133
  # @param [Class,Module] klass
134
+ # @param [Boolean] include_super Whether to include methods from ancestors.
129
135
  # @return [Array[Pry::Method]]
130
- def all_from_class(klass)
131
- all_from_common(klass, :instance_method)
136
+ def all_from_class(klass, include_super=true)
137
+ all_from_common(klass, :instance_method, include_super)
132
138
  end
133
139
 
134
140
  # Get all of the methods on an `Object`
135
141
  # @param [Object] obj
142
+ # @param [Boolean] include_super Whether to include methods from ancestors.
136
143
  # @return [Array[Pry::Method]]
137
- def all_from_obj(obj)
138
- all_from_common(obj, :method)
144
+ def all_from_obj(obj, include_super=true)
145
+ all_from_common(obj, :method, include_super)
139
146
  end
140
147
 
141
148
  # Get every `Class` and `Module`, in order, that will be checked when looking
@@ -168,9 +175,9 @@ class Pry
168
175
  # If method_type is :method, obj can be any `Object`
169
176
  #
170
177
  # N.B. we pre-cache the visibility here to avoid O(N²) behaviour in "ls".
171
- def all_from_common(obj, method_type)
178
+ def all_from_common(obj, method_type, include_super=true)
172
179
  %w(public protected private).map do |visibility|
173
- safe_send(obj, :"#{visibility}_#{method_type}s").map do |method_name|
180
+ safe_send(obj, :"#{visibility}_#{method_type}s", include_super).map do |method_name|
174
181
  new(safe_send(obj, method_type, method_name), :visibility => visibility.to_sym)
175
182
  end
176
183
  end.flatten(1)
@@ -183,6 +190,7 @@ class Pry
183
190
  def safe_send(obj, method, *args, &block)
184
191
  (Module === obj ? Module : Object).instance_method(method).bind(obj).call(*args, &block)
185
192
  end
193
+ public :safe_send
186
194
 
187
195
  # Get the singleton classes of superclasses that could define methods on
188
196
  # the given class object, and any modules they include.
@@ -239,21 +247,21 @@ class Pry
239
247
  # @return [String, nil] The source code of the method, or `nil` if it's unavailable.
240
248
  def source
241
249
  @source ||= case source_type
242
- when :c
243
- info = pry_doc_info
244
- if info and info.source
245
- code = strip_comments_from_c_code(info.source)
246
- end
247
- when :ruby
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
252
- else
253
- code = @method.source
254
- end
255
- strip_leading_whitespace(code)
256
- end
250
+ when :c
251
+ info = pry_doc_info
252
+ if info and info.source
253
+ code = strip_comments_from_c_code(info.source)
254
+ end
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
262
+ end
263
+ strip_leading_whitespace(code)
264
+ end
257
265
  end
258
266
 
259
267
  # @return [String, nil] The documentation for the method, or `nil` if it's
@@ -265,10 +273,12 @@ class Pry
265
273
  info = pry_doc_info
266
274
  info.docstring if info
267
275
  when :ruby
268
- if Helpers::BaseHelpers.rbx? && core?
269
- strip_leading_hash_and_whitespace_from_ruby_comments(core_doc)
276
+ if Helpers::BaseHelpers.rbx? && !pry_method?
277
+ strip_leading_hash_and_whitespace_from_ruby_comments(core_doc)
270
278
  elsif pry_method?
271
- raise CommandError, "Can't view doc for a REPL-defined 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)
272
282
  else
273
283
  strip_leading_hash_and_whitespace_from_ruby_comments(@method.comment)
274
284
  end
@@ -281,6 +291,15 @@ class Pry
281
291
  source_location.nil? ? :c : :ruby
282
292
  end
283
293
 
294
+ def source_location
295
+ if @method.source_location && Helpers::BaseHelpers.rbx?
296
+ file, line = @method.source_location
297
+ [RbxPath.convert_path_to_full(file), line]
298
+ else
299
+ @method.source_location
300
+ end
301
+ end
302
+
284
303
  # @return [String, nil] The name of the file the method is defined in, or
285
304
  # `nil` if the filename is unavailable.
286
305
  def source_file
@@ -303,7 +322,7 @@ class Pry
303
322
  # @return [Range, nil] The range of lines in `source_file` which contain
304
323
  # the method's definition, or `nil` if that information is unavailable.
305
324
  def source_range
306
- source_location.nil? ? nil : (source_line)...(source_line + source.lines.count)
325
+ source_location.nil? ? nil : (source_line)..(source_line + source.lines.count - 1)
307
326
  end
308
327
 
309
328
  # @return [Symbol] The visibility of the method. May be `:public`,
@@ -382,7 +401,7 @@ class Pry
382
401
  # @return [Boolean]
383
402
  def ==(obj)
384
403
  if obj.is_a? Pry::Method
385
- super
404
+ obj == @method
386
405
  else
387
406
  @method == obj
388
407
  end
@@ -411,31 +430,28 @@ class Pry
411
430
  # @raise [CommandError] Raises when the method can't be found or `pry-doc` isn't installed.
412
431
  def pry_doc_info
413
432
  if Pry.config.has_pry_doc
414
- Pry::MethodInfo.info_for(@method) or raise CommandError, "Cannot locate this method: #{name}."
433
+ Pry::MethodInfo.info_for(@method) or raise CommandError, "Cannot locate this method: #{name}. (source_location returns nil)"
415
434
  else
416
435
  raise CommandError, "Cannot locate this method: #{name}. Try `gem install pry-doc` to get access to Ruby Core documentation."
417
436
  end
418
437
  end
419
438
 
420
- # @param [String] code
421
- # @return [String]
422
- def strip_comments_from_c_code(code)
423
- code.sub(/\A\s*\/\*.*?\*\/\s*/m, '')
424
- end
439
+ # FIXME: a very similar method to this exists on WrappedModule: extract_doc_for_candidate
440
+ def doc_for_pry_method
441
+ _, line = source_location
425
442
 
426
- # @param [String] comment
427
- # @return [String]
428
- def strip_leading_hash_and_whitespace_from_ruby_comments(comment)
429
- comment = comment.dup
430
- comment.gsub!(/\A\#+?$/, '')
431
- comment.gsub!(/^\s*#/, '')
432
- strip_leading_whitespace(comment)
433
- end
443
+ buffer = ""
444
+ Pry.line_buffer[0..(line - 1)].each do |line|
445
+ # Add any line that is a valid ruby comment,
446
+ # but clear as soon as we hit a non comment line.
447
+ if (line =~ /^\s*#/) || (line =~ /^\s*$/)
448
+ buffer << line.lstrip
449
+ else
450
+ buffer.replace("")
451
+ end
452
+ end
434
453
 
435
- # @param [String] text
436
- # @return [String]
437
- def strip_leading_whitespace(text)
438
- Pry::Helpers::CommandHelpers.unindent(text)
454
+ buffer
439
455
  end
440
456
 
441
457
  # @param [Class,Module] the ancestors to investigate