pry 0.9.6.2 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +6 -0
  2. data/CHANGELOG +19 -1
  3. data/CONTRIBUTORS +22 -16
  4. data/Rakefile +12 -6
  5. data/bin/pry +15 -12
  6. data/lib/pry.rb +39 -28
  7. data/lib/pry/command_context.rb +1 -0
  8. data/lib/pry/command_processor.rb +9 -2
  9. data/lib/pry/command_set.rb +7 -0
  10. data/lib/pry/config.rb +8 -0
  11. data/lib/pry/default_commands/basic.rb +7 -10
  12. data/lib/pry/default_commands/context.rb +36 -26
  13. data/lib/pry/default_commands/documentation.rb +31 -123
  14. data/lib/pry/default_commands/gems.rb +9 -4
  15. data/lib/pry/default_commands/input.rb +21 -11
  16. data/lib/pry/default_commands/introspection.rb +79 -88
  17. data/lib/pry/default_commands/ls.rb +165 -176
  18. data/lib/pry/default_commands/shell.rb +8 -8
  19. data/lib/pry/extended_commands/experimental.rb +1 -5
  20. data/lib/pry/extended_commands/user_command_api.rb +17 -5
  21. data/lib/pry/helpers.rb +1 -0
  22. data/lib/pry/helpers/base_helpers.rb +5 -1
  23. data/lib/pry/helpers/command_helpers.rb +22 -241
  24. data/lib/pry/helpers/options_helpers.rb +58 -0
  25. data/lib/pry/helpers/text.rb +10 -4
  26. data/lib/pry/history.rb +1 -1
  27. data/lib/pry/indent.rb +205 -0
  28. data/lib/pry/method.rb +412 -0
  29. data/lib/pry/pry_class.rb +56 -15
  30. data/lib/pry/pry_instance.rb +63 -16
  31. data/lib/pry/rbx_method.rb +20 -0
  32. data/lib/pry/rbx_path.rb +34 -0
  33. data/lib/pry/version.rb +1 -1
  34. data/pry.gemspec +16 -16
  35. data/test/helper.rb +8 -4
  36. data/test/test_command_helpers.rb +1 -69
  37. data/test/test_command_set.rb +29 -28
  38. data/test/test_default_commands/test_documentation.rb +23 -10
  39. data/test/test_default_commands/test_introspection.rb +58 -13
  40. data/test/test_default_commands/test_ls.rb +148 -0
  41. data/test/test_indent.rb +234 -0
  42. data/test/test_input_stack.rb +13 -0
  43. data/test/test_method.rb +291 -0
  44. data/test/test_pry.rb +10 -1
  45. metadata +82 -65
@@ -4,7 +4,9 @@ class Pry
4
4
  UserCommandAPI = Pry::CommandSet.new do
5
5
 
6
6
  command "define-command", "Define a command in the session, use same syntax as `command` method for command API" do |arg|
7
- next output.puts("Provide an arg!") if arg.nil?
7
+ if arg.nil?
8
+ raise CommandError, "Provide an arg!"
9
+ end
8
10
 
9
11
  prime_string = "command #{arg_string}\n"
10
12
  command_string = _pry_.r(target, prime_string)
@@ -18,8 +20,13 @@ class Pry
18
20
  end
19
21
 
20
22
  command "reload-command", "Reload a command. reload-command CMD_NAME CMD_SET" do |command_name, set_name|
21
- next output.puts "Must provide command name" if command_name.nil?
22
- next output.puts "Must provide command set name" if set_name.nil?
23
+ if command_name.nil?
24
+ raise CommandError, "Must provide command name"
25
+ end
26
+
27
+ if set_name.nil?
28
+ raise CommandError, "Must provide command set name"
29
+ end
23
30
 
24
31
  cmd = Pry.config.commands.commands[command_name]
25
32
  file_name = cmd.block.source_location.first
@@ -33,8 +40,13 @@ class Pry
33
40
  end
34
41
 
35
42
  command "edit-command", "Edit a command. edit-command CMD_NAME CMD_SET" do |command_name, set_name|
36
- next output.puts "Must provide command name" if command_name.nil?
37
- next output.puts "Must provide a command set name" if set_name.nil?
43
+ if command_name.nil?
44
+ raise CommandError, "Must provide command name"
45
+ end
46
+
47
+ if set_name.nil?
48
+ raise CommandError, "Must provide command set name"
49
+ end
38
50
 
39
51
  cmd = Pry.config.commands.commands[command_name]
40
52
  file_name = cmd.block.source_location.first
@@ -1,3 +1,4 @@
1
1
  require "pry/helpers/base_helpers"
2
+ require "pry/helpers/options_helpers"
2
3
  require "pry/helpers/command_helpers"
3
4
  require "pry/helpers/text"
@@ -35,7 +35,7 @@ class Pry
35
35
  end
36
36
 
37
37
  def set_file_and_dir_locals(file_name)
38
- return if !target
38
+ return if !target or !file_name
39
39
  _pry_.last_file = File.expand_path(file_name)
40
40
  _pry_.inject_local("_file_", _pry_.last_file, target)
41
41
 
@@ -65,6 +65,10 @@ class Pry
65
65
  end
66
66
  end
67
67
 
68
+ def use_ansi_codes?
69
+ defined?(Win32::Console) || ENV['TERM'] && ENV['TERM'] != "dumb"
70
+ end
71
+
68
72
  def colorize_code(code)
69
73
  if Pry.color
70
74
  CodeRay.scan(code, :ruby).term
@@ -2,18 +2,10 @@ class Pry
2
2
  module Helpers
3
3
 
4
4
  module CommandHelpers
5
+ include OptionsHelpers
5
6
 
6
7
  module_function
7
8
 
8
- def meth_name_from_binding(b)
9
- meth_name = b.eval('__method__')
10
- if [:__script__, nil, :__binding__, :__binding_impl__].include?(meth_name)
11
- nil
12
- else
13
- meth_name
14
- end
15
- end
16
-
17
9
  # if start_line is not false then add line numbers starting with start_line
18
10
  def render_output(should_flood, start_line, text, color=:blue)
19
11
  if start_line
@@ -27,18 +19,6 @@ class Pry
27
19
  end
28
20
  end
29
21
 
30
- def is_a_dynamically_defined_method?(meth)
31
- file, _ = meth.source_location
32
- !!(file =~ /(\(.*\))|<.*>/)
33
- end
34
-
35
- def check_for_dynamically_defined_method(meth)
36
- file, _ = meth.source_location
37
- if file =~ /(\(.*\))|<.*>/ && file != Pry.eval_path
38
- raise "Cannot retrieve source for dynamically defined method."
39
- end
40
- end
41
-
42
22
  # Open a temp file and yield it to the block, closing it after
43
23
  # @return [String] The path of the temp file
44
24
  def temp_file
@@ -48,223 +28,42 @@ class Pry
48
28
  file.close
49
29
  end
50
30
 
51
- ########### RBX HELPERS #############
52
- def is_core_rbx_path?(path)
53
- rbx? &&
54
- path.start_with?("kernel")
55
- end
56
-
57
- def rbx_core?(meth)
58
- meth.source_location &&
59
- is_core_rbx_path?(meth.source_location.first)
60
- end
61
-
62
- def rvm_ruby?(path)
63
- !!(path =~ /\.rvm/)
64
- end
65
-
66
- def rbx_core_code_for(meth)
67
- rbx_core_code_or_doc_for(meth, :code)
68
- end
69
-
70
- def rbx_core_doc_for(meth)
71
- rbx_core_code_or_doc_for(meth, :doc)
72
- end
73
-
74
- def rbx_core_code_or_doc_for(meth, code_or_doc)
75
- path_line = rbx_core_path_line_for(meth)
31
+ def get_method_or_raise(name, target, opts={}, omit_help=false)
32
+ meth = Pry::Method.from_str(name, target, opts)
76
33
 
77
- case code_or_doc
78
- when :code
79
- MethodSource.source_helper(path_line)
80
- when :doc
81
- MethodSource.comment_helper(path_line)
34
+ if name && !meth
35
+ command_error("The method '#{name}' could not be found.", omit_help)
36
+ elsif !meth
37
+ command_error("No method name given, and context is not a method.", omit_help)
82
38
  end
83
- end
84
-
85
- def rbx_convert_path_to_full(path)
86
- if rvm_ruby?(Rubinius::BIN_PATH)
87
- rbx_rvm_convert_path_to_full(path)
88
- else
89
- rbx_std_convert_path_to_full(path)
90
- end
91
- end
92
-
93
- def rbx_rvm_convert_path_to_full(path)
94
- ruby_name = File.dirname(Rubinius::BIN_PATH).split("/").last
95
- source_path = File.join(File.dirname(File.dirname(File.dirname(Rubinius::BIN_PATH))), "src", ruby_name)
96
- file_name = File.join(source_path, path)
97
- raise "Cannot find rbx core source" if !File.exists?(file_name)
98
- file_name
99
- end
100
-
101
- def rbx_std_convert_path_to_full(path)
102
- file_name = File.join(Rubinius::BIN_PATH, "..", path)
103
- raise "Cannot find rbx core source" if !File.exists?(file_name)
104
- file_name
105
- end
106
-
107
- def rbx_core_path_line_for(meth)
108
- if rvm_ruby?(Rubinius::BIN_PATH)
109
- rvm_rbx_core_path_line_for(meth)
110
- else
111
- std_rbx_core_path_line_for(meth)
112
- end
113
- end
114
-
115
- def std_rbx_core_path_line_for(meth)
116
- file_name = rbx_std_convert_path_to_full(meth.source_location.first)
117
- start_line = meth.source_location.last
118
-
119
- [file_name, start_line]
120
- end
121
-
122
- def rvm_rbx_core_path_line_for(meth)
123
- file_name = rbx_rvm_convert_path_to_full(meth.source_location.first)
124
- start_line = meth.source_location.last
125
-
126
- [file_name, start_line]
127
- end
128
39
 
129
- ######### END RBX HELPERS ###############
130
-
131
- def code_and_code_type_for(meth)
132
- case code_type = code_type_for(meth)
133
- when nil
134
- return nil
135
- when :c
136
- code = Pry::MethodInfo.info_for(meth).source
137
- code = strip_comments_from_c_code(code)
138
- when :ruby
139
- if meth.source_location.first == Pry.eval_path
140
- start_line = meth.source_location.last
141
-
142
- # FIXME this line below needs to be refactored, WAY too
143
- # much of a hack. We pass nothing to prompt because if
144
- # prompt uses #inspect (or #pretty_inspect) on the context
145
- # it can hang the session if the object being inspected on
146
- # is enormous see: https://github.com/pry/pry/issues/245
147
- p = Pry.new(:input => StringIO.new(Pry.line_buffer[start_line..-1].join), :prompt => proc {""}, :hooks => {}).r(target)
148
- code = strip_leading_whitespace(p)
40
+ (opts[:super] || 0).times do
41
+ if meth.super
42
+ meth = meth.super
149
43
  else
150
- if rbx_core?(meth)
151
- code = strip_leading_whitespace(rbx_core_code_for(meth))
152
- else
153
- code = strip_leading_whitespace(meth.source)
154
- end
44
+ command_error("The method '#{meth.name}' is not defined in a superclass of '#{class_name(meth.owner)}'.", omit_help)
155
45
  end
156
- set_file_and_dir_locals(path_line_for(meth).first)
157
46
  end
158
47
 
159
- [code, code_type]
48
+ set_file_and_dir_locals(meth.source_file)
49
+ meth
160
50
  end
161
51
 
162
- def doc_and_code_type_for(meth)
163
- case code_type = code_type_for(meth)
164
- when nil
165
- return nil
166
- when :c
167
- doc = Pry::MethodInfo.info_for(meth).docstring
168
- when :ruby
169
- if rbx_core?(meth)
170
- doc = strip_leading_hash_and_whitespace_from_ruby_comments(rbx_core_doc_for(meth))
171
- else
172
- doc = strip_leading_hash_and_whitespace_from_ruby_comments(meth.comment)
173
- end
174
- set_file_and_dir_locals(path_line_for(meth).first)
175
- end
176
-
177
- [doc, code_type]
52
+ def command_error(message, omit_help)
53
+ message += " Type `#{command_name} --help` for help." unless omit_help
54
+ raise CommandError, message
178
55
  end
179
56
 
180
- def get_method_object(meth_name, target=nil, options={})
181
- get_method_object_from_target(*get_method_attributes(meth_name, target, options)) rescue nil
182
- end
57
+ def make_header(meth, content=meth.source)
58
+ header = "\n#{Pry::Helpers::Text.bold('From:')} #{meth.source_file} "
183
59
 
184
- def get_method_attributes(meth_name, target=nil, options={})
185
- if meth_name
186
- if meth_name =~ /(\S+)\#(\S+)\Z/
187
- context, meth_name = $1, $2
188
- target = Pry.binding_for(target.eval(context))
189
- type = :instance
190
- elsif meth_name =~ /(\S+)\.(\S+)\Z/
191
- context, meth_name = $1, $2
192
- target = Pry.binding_for(target.eval(context))
193
- type = :singleton
194
- elsif options["instance_methods"]
195
- type = :instance
196
- elsif options[:methods]
197
- type = :singleton
198
- else
199
- type = nil
200
- end
60
+ if meth.source_type == :c
61
+ header << "in Ruby Core (C Method):\n"
201
62
  else
202
- meth_name = meth_name_from_binding(target)
203
- type = nil
63
+ header << "@ line #{meth.source_line}:\n"
204
64
  end
205
- [meth_name, target, type]
206
- end
207
65
 
208
- def get_method_object_from_target(meth_name, target, type=nil)
209
- case type
210
- when :instance
211
- target.eval("instance_method(:#{meth_name})") rescue nil
212
- when :singleton
213
- target.eval("method(:#{meth_name})") rescue nil
214
- else
215
- get_method_object_from_target(meth_name, target, :instance) ||
216
- get_method_object_from_target(meth_name, target, :singleton)
217
- end
218
- end
219
-
220
- def path_line_for(meth)
221
- if rbx_core?(meth)
222
- rbx_core_path_line_for(meth)
223
- else
224
- meth.source_location
225
- end
226
- end
227
-
228
- def make_header(meth, code_type, content)
229
- num_lines = "Number of lines: #{Pry::Helpers::Text.bold(content.each_line.count.to_s)}"
230
- case code_type
231
- when :ruby
232
- file, line = path_line_for(meth)
233
- "\n#{Pry::Helpers::Text.bold('From:')} #{file} @ line #{line}:\n#{num_lines}\n\n"
234
- else
235
- file = Pry::MethodInfo.info_for(meth).file
236
- "\n#{Pry::Helpers::Text.bold('From:')} #{file} in Ruby Core (C Method):\n#{num_lines}\n\n"
237
- end
238
- end
239
-
240
- def is_a_c_method?(meth)
241
- meth.source_location.nil?
242
- end
243
-
244
- def should_use_pry_doc?(meth)
245
- Pry.config.has_pry_doc && is_a_c_method?(meth)
246
- end
247
-
248
- def code_type_for(meth)
249
- # only C methods
250
- if should_use_pry_doc?(meth)
251
- info = Pry::MethodInfo.info_for(meth)
252
- if info && info.source
253
- code_type = :c
254
- else
255
- output.puts "Cannot find C method: #{meth.name}"
256
- code_type = nil
257
- end
258
- else
259
- if is_a_c_method?(meth)
260
- output.puts "Cannot locate this method: #{meth.name}. Try `gem install pry-doc` to get access to Ruby Core documentation."
261
- code_type = nil
262
- else
263
- check_for_dynamically_defined_method(meth)
264
- code_type = :ruby
265
- end
266
- end
267
- code_type
66
+ header << "#{Pry::Helpers::Text.bold("Number of lines:")} #{content.each_line.count.to_s}\n"
268
67
  end
269
68
 
270
69
  def file_map
@@ -357,24 +156,6 @@ class Pry
357
156
  process_yardoc process_rdoc(comment, code_type)
358
157
  end
359
158
 
360
- # strip leading whitespace but preserve indentation
361
- def strip_leading_whitespace(text)
362
- return text if text.empty?
363
- leading_spaces = text.lines.first[/^(\s+)/, 1]
364
- text.gsub(/^#{leading_spaces}/, '')
365
- end
366
-
367
- def strip_leading_hash_and_whitespace_from_ruby_comments(comment)
368
- comment = comment.dup
369
- comment.gsub!(/\A\#+?$/, '')
370
- comment.gsub!(/^\s*#/, '')
371
- strip_leading_whitespace(comment)
372
- end
373
-
374
- def strip_comments_from_c_code(code)
375
- code.sub(/\A\s*\/\*.*?\*\/\s*/m, '')
376
- end
377
-
378
159
  def invoke_editor(file, line)
379
160
  if Pry.config.editor.respond_to?(:call)
380
161
  editor_invocation = Pry.config.editor.call(file, line)
@@ -0,0 +1,58 @@
1
+ class Pry
2
+ module Helpers
3
+ module OptionsHelpers
4
+ module_function
5
+
6
+ # Use Slop to parse the arguments given.
7
+ #
8
+ # @param [Array] args The options are stripped out by Slop.
9
+ # @param [*Symbol] extras Extra features you want returned.
10
+ # @param [&Block] used to add custom arguments to Slop.
11
+ #
12
+ # @option [Extra] :method_object Returns a method object.
13
+ #
14
+ # @return Slop::Options iff you don't pass any extras.
15
+ # @return [Array] If you do pass extras, an array is returned where the first argument is the
16
+ # Slop::Options object, and the remainder are the extras you requested in order.
17
+ #
18
+ def parse_options!(args, *extras, &block)
19
+ opts = Slop.parse!(args) do |opt|
20
+ extras.each{ |extra| send(:"add_#{extra}_options", opt) }
21
+
22
+ yield opt
23
+
24
+ opt.on :h, :help, "This message" do
25
+ output.puts opt
26
+ throw :command_done
27
+ end
28
+ end
29
+
30
+ if extras.empty?
31
+ opts
32
+ else
33
+ [opts] + extras.map{ |extra| send(:"process_#{extra}_options", args, opts) }
34
+ end
35
+ end
36
+
37
+ # Add the method object options to an unused Slop instance.
38
+ def add_method_object_options(opt)
39
+ @method_target = target
40
+ opt.on :M, "instance-methods", "Operate on instance methods."
41
+ opt.on :m, :methods, "Operate on methods."
42
+ opt.on :s, :super, "Select the 'super' method. Can be repeated to traverse the ancestors."
43
+ opt.on :c, :context, "Select object context to run under.", true do |context|
44
+ @method_target = Pry.binding_for(target.eval(context))
45
+ end
46
+ end
47
+
48
+ # Add the derived :method_object option to a used Slop instance.
49
+ def process_method_object_options(args, opts)
50
+ opts[:instance] = opts['instance-methods'] if opts.m?
51
+ # TODO: de-hack when we upgrade Slop: https://github.com/injekt/slop/pull/30
52
+ opts.options[:super].force_argument_value opts.options[:super].count if opts.super?
53
+
54
+ get_method_or_raise(args.empty? ? nil : args.join(" "), @method_target, opts.to_hash(true))
55
+ end
56
+ end
57
+ end
58
+ end
@@ -29,10 +29,6 @@ class Pry
29
29
  end
30
30
  end
31
31
 
32
- alias_method :grey, :bright_black
33
- alias_method :gray, :bright_black
34
-
35
-
36
32
  # Remove any color codes from _text_.
37
33
  #
38
34
  # @param [String, #to_s] text
@@ -50,6 +46,16 @@ class Pry
50
46
  Pry.color ? "\e[1m#{text}\e[0m" : text.to_s
51
47
  end
52
48
 
49
+ # Returns _text_ in the default foreground colour.
50
+ # Use this instead of "black" or "white" when you mean absence of colour.
51
+ #
52
+ # @param [String, #to_s]
53
+ # @return [String] _text_
54
+ def default(text)
55
+ text.to_s
56
+ end
57
+ alias_method :bright_default, :bold
58
+
53
59
  # Executes _block_ with _Pry.color_ set to false.
54
60
  #
55
61
  # @param [Proc]