pry 0.7.2 → 0.8.0

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.
data/lib/pry/commands.rb CHANGED
@@ -1,70 +1,55 @@
1
+ direc = File.dirname(__FILE__)
2
+
1
3
  require "optparse"
2
4
  require "method_source"
3
- require "pry/command_base"
4
- require "pry/pry_instance"
5
-
6
- begin
7
- require "pry-doc"
8
- rescue LoadError
9
- end
5
+ require 'slop'
6
+ require 'rubygems/dependency_installer'
7
+ require "#{direc}/command_base"
8
+ require "#{direc}/pry_instance"
9
+ require "#{direc}/command_helpers"
10
10
 
11
11
  class Pry
12
12
 
13
13
  # Default commands used by Pry.
14
14
  class Commands < CommandBase
15
+ extend CommandHelpers
15
16
 
16
- # We make this a lambda to avoid documenting it
17
- meth_name_from_binding = lambda do |b|
18
- meth_name = b.eval('__method__')
17
+ try_to_load_pry_doc
19
18
 
20
- # :__script__ for rubinius
21
- if [:__script__, nil, :__binding__, :__binding_impl__].include?(meth_name)
22
- nil
23
- else
24
- meth_name
25
- end
19
+ command "!", "Clear the input buffer. Useful if the parsing process goes wrong and you get stuck in the read loop." do
20
+ output.puts "Input buffer cleared!"
21
+ opts[:eval_string].clear
26
22
  end
27
23
 
28
- check_for_dynamically_defined_method = lambda do |file|
29
- if file =~ /(\(.*\))|<.*>/
30
- raise "Cannot retrieve source for dynamically defined method."
31
- end
24
+ command "!pry", "Start a Pry session on current self; this even works mid-expression." do
25
+ Pry.start(target)
32
26
  end
33
27
 
34
- remove_first_word = lambda do |text|
35
- text.split.drop(1).join(' ')
28
+ # this cannot be accessed, it's just for help purposes.
29
+ command ".<shell command>", "All text following a '.' is forwarded to the shell." do
36
30
  end
37
31
 
38
- get_method_object = lambda do |meth_name, target, options|
39
- if options[:M]
40
- target.eval("instance_method(:#{meth_name})")
41
- elsif options[:m]
42
- target.eval("method(:#{meth_name})")
43
- else
44
- begin
45
- target.eval("instance_method(:#{meth_name})")
46
- rescue
47
- target.eval("method(:#{meth_name})")
48
- end
32
+ command "hist", "Show and replay Readline history. Type `hist --help` for more info." do |*args|
33
+ hist_array = Readline::HISTORY.to_a
34
+
35
+ if args.empty?
36
+ text = add_line_numbers(hist_array.join("\n"), 0)
37
+ stagger_output(text)
38
+ next
49
39
  end
50
- end
51
40
 
52
- make_header = lambda do |file, line, code_type|
53
- header = case code_type
54
- when :ruby
55
- "--\nFrom #{file} @ line #{line}:\n--"
56
- else
57
- "--\nFrom Ruby Core (C Method):\n--"
58
- end
59
- end
41
+ opts = Slop.parse(args) do |opt|
42
+ opt.banner "Usage: hist [--replay START..END]\nView and replay history\ne.g hist --replay 2..8"
43
+ opt.on :r, :replay, 'The line (or range of lines) to replay.', true, :as => Range
44
+ opt.on :h, :help, 'Show this message.', :tail => true do
45
+ output.puts opt.help
46
+ end
47
+ end
60
48
 
61
- command "!", "Clear the input buffer. Useful if the parsing process goes wrong and you get stuck in the read loop." do
62
- output.puts "Input buffer cleared!"
63
- opts[:eval_string].clear
64
- end
49
+ next if opts.h?
65
50
 
66
- command "!pry", "Start a Pry session on current self; this even works mid-expression." do
67
- Pry.start(target)
51
+ actions = Array(hist_array[opts[:replay]]).join("\n") + "\n"
52
+ Pry.active_instance.input = StringIO.new(actions)
68
53
  end
69
54
 
70
55
  command "exit-program", "End the current program. Aliases: quit-program, !!!" do
@@ -74,6 +59,150 @@ class Pry
74
59
  alias_command "quit-program", "exit-program", ""
75
60
  alias_command "!!!", "exit-program", ""
76
61
 
62
+ command "gem-install", "Install a gem" do |gem_name|
63
+ gem_home = Gem.instance_variable_get(:@gem_home)
64
+ output.puts "Attempting to install gem: #{bold(gem_name)}"
65
+
66
+ begin
67
+ if File.writable?(gem_home)
68
+ Gem::DependencyInstaller.new.install(gem_name)
69
+ output.puts "Gem #{bold(gem_name)} successfully installed."
70
+ else
71
+ if system("sudo gem install #{gem_name}")
72
+ output.puts "Gem #{bold(gem_name)} successfully installed."
73
+ else
74
+ output.puts "Gem #{bold(gem_name)} could not be installed."
75
+ next
76
+ end
77
+ end
78
+ rescue Gem::GemNotFoundException
79
+ output.puts "Required Gem: #{bold(gem_name)} not found."
80
+ next
81
+ end
82
+
83
+ Gem.refresh
84
+ output.puts "Refreshed gem cache."
85
+ end
86
+
87
+ command "ri", "View ri documentation. e.g `ri Array#each`" do |*args|
88
+ run ".ri", *args
89
+ end
90
+
91
+ command "stat", "View method information and set _file_ and _dir_ locals. Type `stat --help` for more info." do |*args|
92
+ target = target()
93
+
94
+ opts = Slop.parse!(args) do |opts|
95
+ opts.banner %{Usage: stat [OPTIONS] [METH]
96
+ Show method information for method METH and set _file_ and _dir_ locals.
97
+ e.g: stat hello_method
98
+ --
99
+ }
100
+ opts.on :M, "instance-methods", "Operate on instance methods."
101
+ opts.on :m, :methods, "Operate on methods."
102
+ opts.on :c, :context, "Select object context to run under.", true do |context|
103
+ target = Pry.binding_for(target.eval(context))
104
+ end
105
+ opts.on :h, :help, "This message" do
106
+ output.puts opts
107
+ end
108
+ end
109
+
110
+ next if opts.help?
111
+
112
+ meth_name = args.shift
113
+ if meth_name
114
+ if meth_name =~ /\A([^\.\#]+)[\.\#](.+)\z/ && !opts.context?
115
+ context, meth_name = $1, $2
116
+ target = Pry.binding_for(target.eval(context))
117
+ end
118
+ else
119
+ meth_name = meth_name_from_binding(target)
120
+ end
121
+
122
+ if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
123
+ output.puts "Invalid method name: #{meth_name}. Type `stat --help` for help"
124
+ next
125
+ end
126
+
127
+ code, code_type = code_and_code_type_for(meth)
128
+ next if !code
129
+ doc, code_type = doc_and_code_type_for(meth)
130
+
131
+ output.puts make_header(meth, code_type, code)
132
+ output.puts bold("Method Name: ") + meth_name
133
+ output.puts bold("Method Owner: ") + (meth.owner.to_s ? meth.owner.to_s : "Unknown")
134
+ output.puts bold("Method Language: ") + code_type.to_s.capitalize
135
+ output.puts bold("Method Type: ") + (meth.is_a?(Method) ? "Bound" : "Unbound")
136
+ output.puts bold("Method Arity: ") + meth.arity.to_s
137
+
138
+ name_map = { :req => "Required:", :opt => "Optional:", :rest => "Rest:" }
139
+ if meth.respond_to?(:parameters)
140
+ output.puts bold("Method Parameters: ") + meth.parameters.group_by(&:first).
141
+ map { |k, v| "#{name_map[k]} #{v.map { |kk, vv| vv ? vv.to_s : "noname" }.join(", ")}" }.join(". ")
142
+ end
143
+ output.puts bold("Comment length: ") + (doc.empty? ? 'No comment.' : (doc.lines.count.to_s + ' lines.'))
144
+ end
145
+
146
+ command "gist-method", "Gist a method to github. Type `gist-method --help` for more info.", :requires_gem => "gist" do |*args|
147
+ target = target()
148
+
149
+ opts = Slop.parse!(args) do |opts|
150
+ opts.banner = %{Usage: gist-method [OPTIONS] [METH]
151
+ Gist the method (doc or source) to github.
152
+ e.g: gist -m my_method
153
+ e.g: gist -d my_method
154
+ --
155
+ }
156
+ opts.on :m, :method, "Gist a method's source."
157
+ opts.on :d, :doc, "Gist a method's documentation."
158
+ opts.on :p, :private, "Create a private gist (default: true)", :default => true
159
+ opts.on :h, :help, "This message" do
160
+ output.puts opts
161
+ end
162
+ end
163
+
164
+ next if opts.help?
165
+
166
+ # This needs to be extracted into its own method as it's shared
167
+ # by show-method and show-doc and stat commands
168
+ meth_name = args.shift
169
+ if meth_name
170
+ if meth_name =~ /\A([^\.\#]+)[\.\#](.+)\z/
171
+ context, meth_name = $1, $2
172
+ target = Pry.binding_for(target.eval(context))
173
+ end
174
+ else
175
+ meth_name = meth_name_from_binding(target)
176
+ end
177
+
178
+ if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
179
+ output.puts "Invalid method name: #{meth_name}. Type `gist-method --help` for help"
180
+ next
181
+ end
182
+
183
+ type_map = { :ruby => "rb", :c => "c", :plain => "plain" }
184
+ if !opts.doc?
185
+ content, code_type = code_and_code_type_for(meth)
186
+ else
187
+ content, code_type = doc_and_code_type_for(meth)
188
+ no_color do
189
+ content = process_comment_markup(content, code_type)
190
+ end
191
+ code_type = :plain
192
+ end
193
+
194
+ IO.popen("gist#{' -p' if opts.p?} -t #{type_map[code_type]} -", "w") do |gist|
195
+ gist.puts content
196
+ end
197
+ end
198
+
199
+ command "gem-cd", "Change working directory to specified gem's directory." do |gem_name|
200
+ require 'rubygems'
201
+ gem_spec = Gem.source_index.find_name(gem_name).first
202
+ next output.puts("Gem `#{gem_name}` not found.") if !gem_spec
203
+ Dir.chdir(File.expand_path(gem_spec.full_gem_path))
204
+ end
205
+
77
206
  command "toggle-color", "Toggle syntax highlighting." do
78
207
  Pry.color = !Pry.color
79
208
  output.puts "Syntax highlighting #{Pry.color ? "on" : "off"}"
@@ -88,9 +217,24 @@ class Pry
88
217
  end
89
218
  end
90
219
 
91
- command "nesting", "Show nesting information." do
220
+ command "shell-mode", "Toggle shell mode. Bring in pwd prompt and file completion." do
221
+ case Pry.active_instance.prompt
222
+ when Pry::SHELL_PROMPT
223
+ Pry.active_instance.prompt = Pry::DEFAULT_PROMPT
224
+ Pry.active_instance.custom_completions = Pry::DEFAULT_CUSTOM_COMPLETIONS
225
+ else
226
+ Pry.active_instance.prompt = Pry::SHELL_PROMPT
227
+ Pry.active_instance.custom_completions = Pry::FILE_COMPLETIONS
228
+ Readline.completion_proc = Pry::InputCompleter.build_completion_proc target,
229
+ Pry.active_instance.instance_eval(&Pry::FILE_COMPLETIONS)
230
+ end
231
+ end
232
+
233
+ alias_command "file-mode", "shell-mode", ""
234
+
235
+ command "nesting", "Show nesting information." do
92
236
  nesting = opts[:nesting]
93
-
237
+
94
238
  output.puts "Nesting status:"
95
239
  output.puts "--"
96
240
  nesting.each do |level, obj|
@@ -104,7 +248,7 @@ class Pry
104
248
 
105
249
  command "status", "Show status information." do
106
250
  nesting = opts[:nesting]
107
-
251
+
108
252
  output.puts "Status:"
109
253
  output.puts "--"
110
254
  output.puts "Receiver: #{Pry.view_clip(target.eval('self'))}"
@@ -112,32 +256,85 @@ class Pry
112
256
  output.puts "Pry version: #{Pry::VERSION}"
113
257
  output.puts "Ruby version: #{RUBY_VERSION}"
114
258
 
115
- mn = meth_name_from_binding.call(target)
259
+ mn = meth_name_from_binding(target)
116
260
  output.puts "Current method: #{mn ? mn : "N/A"}"
117
261
  output.puts "Pry instance: #{Pry.active_instance}"
118
262
  output.puts "Last result: #{Pry.view(Pry.last_result)}"
119
263
  end
120
264
 
121
- command "whereami", "Show the code context for the session." do
265
+
266
+ command "req", "Requires gem(s). No need for quotes! (If the gem isn't installed, it will ask if you want to install it.)" do |*gems|
267
+ gems = gems.join(' ').gsub(',', '').split(/\s+/)
268
+ gems.each do |gem|
269
+ begin
270
+ if require gem
271
+ output.puts "#{bright_yellow(gem)} loaded"
272
+ else
273
+ output.puts "#{bright_white(gem)} already loaded"
274
+ end
275
+
276
+ rescue LoadError => e
277
+
278
+ if gem_installed? gem
279
+ output.puts e.inspect
280
+ else
281
+ output.puts "#{bright_red(gem)} not found"
282
+ if prompt("Install the gem?") == "y"
283
+ run "gem-install", gem
284
+ end
285
+ end
286
+
287
+ end # rescue
288
+ end # gems.each
289
+ end
290
+
291
+
292
+ command "gem-list", "List/search installed gems. (Optional parameter: a regexp to limit the search)" do |arg|
293
+ gems = Gem.source_index.gems.values.group_by(&:name)
294
+ if arg
295
+ query = Regexp.new(arg, Regexp::IGNORECASE)
296
+ gems = gems.select { |gemname, specs| gemname =~ query }
297
+ end
298
+
299
+ gems.each do |gemname, specs|
300
+ versions = specs.map(&:version).sort.reverse.map(&:to_s)
301
+ versions = ["<bright_green>#{versions.first}</bright_green>"] +
302
+ versions[1..-1].map{|v| "<green>#{v}</green>" }
303
+
304
+ gemname = highlight(gemname, query) if query
305
+ result = "<white>#{gemname} <grey>(#{versions.join ', '})</grey>"
306
+ output.puts colorize(result)
307
+ end
308
+ end
309
+
310
+
311
+ command "whereami", "Show the code context for the session. (whereami <n> shows <n> extra lines of code around the invocation line. Default: 5)" do |num|
122
312
  file = target.eval('__FILE__')
123
313
  line_num = target.eval('__LINE__')
124
314
  klass = target.eval('self.class')
125
315
 
126
- meth_name = meth_name_from_binding.call(target)
127
- if !meth_name
128
- output.puts "Cannot find containing method. Did you remember to use \`binding.pry\` ?"
316
+ if num
317
+ i_num = num.to_i
318
+ else
319
+ i_num = 5
320
+ end
321
+
322
+ meth_name = meth_name_from_binding(target)
323
+ meth_name = "N/A" if !meth_name
324
+
325
+ if file =~ /(\(.*\))|<.*>/ || file == "" || file == "-e"
326
+ output.puts "Cannot find local context. Did you use `binding.pry` ?"
129
327
  next
130
328
  end
131
329
 
132
- check_for_dynamically_defined_method.call(file)
133
-
134
- output.puts "--\nFrom #{file} @ line #{line_num} in #{klass}##{meth_name}:\n--"
135
-
330
+ set_file_and_dir_locals(file)
331
+ output.puts "\n#{bold('From:')} #{file} @ line #{line_num} in #{klass}##{meth_name}:\n\n"
332
+
136
333
  # This method inspired by http://rubygems.org/gems/ir_b
137
334
  File.open(file).each_with_index do |line, index|
138
335
  line_n = index + 1
139
- next unless line_n > (line_num - 6)
140
- break if line_n > (line_num + 5)
336
+ next unless line_n > (line_num - i_num - 1)
337
+ break if line_n > (line_num + i_num)
141
338
  if line_n == line_num
142
339
  code =" =>#{line_n.to_s.rjust(3)}: #{line.chomp}"
143
340
  if Pry.color
@@ -155,25 +352,24 @@ class Pry
155
352
  end
156
353
  end
157
354
  end
158
-
355
+
159
356
  command "version", "Show Pry version." do
160
357
  output.puts "Pry version: #{Pry::VERSION} on Ruby #{RUBY_VERSION}."
161
358
  end
162
-
163
- command "exit-all", "End all nested Pry sessions. Accepts optional return value. Aliases: !@" do
164
- str = remove_first_word.call(opts[:val])
359
+
360
+ command "exit-all", "End all nested Pry sessions. Accepts optional return value. Aliases: !!@" do
361
+ str = remove_first_word(opts[:val])
165
362
  throw(:breakout, [0, target.eval(str)])
166
363
  end
167
364
 
168
- alias_command "!@", "exit-all", ""
365
+ alias_command "!!@", "exit-all", ""
169
366
 
170
- command "ls", "Show the list of vars in the current scope. Type `ls --help` for more info." do |*args|
367
+ command "ls", "Show the list of vars and methods in the current scope. Type `ls --help` for more info." do |*args|
171
368
  options = {}
172
-
173
369
  # Set target local to the default -- note that we can set a different target for
174
370
  # ls if we like: e.g ls my_var
175
371
  target = target()
176
-
372
+
177
373
  OptionParser.new do |opts|
178
374
  opts.banner = %{Usage: ls [OPTIONS] [VAR]\n\
179
375
  List information about VAR (the current context by default).
@@ -183,7 +379,7 @@ Shows local and instance variables by default.
183
379
  opts.on("-g", "--globals", "Display global variables.") do
184
380
  options[:g] = true
185
381
  end
186
-
382
+
187
383
  opts.on("-c", "--constants", "Display constants.") do
188
384
  options[:c] = true
189
385
  end
@@ -192,15 +388,15 @@ Shows local and instance variables by default.
192
388
  options[:l] = true
193
389
  end
194
390
 
195
- opts.on("-i", "--ivars", "Display instance variables.") do
391
+ opts.on("-i", "--ivars", "Display instance variables.") do
196
392
  options[:i] = true
197
393
  end
198
394
 
199
- opts.on("-k", "--class-vars", "Display class variables.") do
395
+ opts.on("-k", "--class-vars", "Display class variables.") do
200
396
  options[:k] = true
201
- end
397
+ end
202
398
 
203
- opts.on("-m", "--methods", "Display methods (public methods by default).") do
399
+ opts.on("-m", "--methods", "Display methods (public methods by default).") do
204
400
  options[:m] = true
205
401
  end
206
402
 
@@ -208,34 +404,42 @@ Shows local and instance variables by default.
208
404
  options[:M] = true
209
405
  end
210
406
 
211
- opts.on("-P", "--public", "Display public methods (with -m).") do
407
+ opts.on("-P", "--public", "Display public methods (with -m).") do
212
408
  options[:P] = true
213
409
  end
214
410
 
215
- opts.on("-r", "--protected", "Display protected methods (with -m).") do
411
+ opts.on("-r", "--protected", "Display protected methods (with -m).") do
216
412
  options[:r] = true
217
- end
413
+ end
218
414
 
219
- opts.on("-p", "--private", "Display private methods (with -m).") do
415
+ opts.on("-p", "--private", "Display private methods (with -m).") do
220
416
  options[:p] = true
221
417
  end
222
418
 
223
- opts.on("-j", "--just-singletons", "Display just the singleton methods (with -m).") do
419
+ opts.on("-j", "--just-singletons", "Display just the singleton methods (with -m).") do
224
420
  options[:j] = true
225
- end
421
+ end
226
422
 
227
- opts.on("-s", "--super", "Include superclass entries (relevant to constant and methods options).") do
423
+ opts.on("-s", "--super", "Include superclass entries (relevant to constant and methods options).") do
228
424
  options[:s] = true
229
425
  end
230
-
426
+
231
427
  opts.on("-a", "--all", "Display all types of entries.") do
232
428
  options[:a] = true
233
429
  end
234
430
 
235
- opts.on("-v", "--verbose", "Verbose ouput.") do
431
+ opts.on("-v", "--verbose", "Verbose ouput.") do
236
432
  options[:v] = true
237
433
  end
238
434
 
435
+ opts.on("-f", "--flood", "Do not use a pager to view text longer than one screen.") do
436
+ options[:f] = true
437
+ end
438
+
439
+ opts.on("--grep REG", "Regular expression to be used.") do |reg|
440
+ options[:grep] = Regexp.new(reg)
441
+ end
442
+
239
443
  opts.on_tail("-h", "--help", "Show this message.") do
240
444
  output.puts opts
241
445
  options[:h] = true
@@ -253,18 +457,21 @@ Shows local and instance variables by default.
253
457
  :l => true,
254
458
  :i => true,
255
459
  :k => true
256
- }) if options.empty? || (options.size == 1 && options[:v])
460
+ }) if options.empty? || (options.size == 1 && options[:v]) || (options.size == 1 && options[:grep])
461
+
462
+ options[:grep] = // if !options[:grep]
463
+
257
464
 
258
465
  # Display public methods by default if -m or -M switch is used.
259
466
  options[:P] = true if (options[:m] || options[:M]) && !(options[:p] || options[:r] || options[:j])
260
-
467
+
261
468
  info = {}
262
469
  target_self = target.eval('self')
263
470
 
264
471
  # ensure we have a real boolean and not a `nil` (important when
265
472
  # interpolating in the string)
266
473
  options[:s] = !!options[:s]
267
-
474
+
268
475
  # Numbers (e.g 0, 1, 2) are for ordering the hash values in Ruby 1.8
269
476
  i = -1
270
477
 
@@ -279,7 +486,7 @@ Shows local and instance variables by default.
279
486
  end, i += 1] if options[:k] || options[:a]
280
487
 
281
488
  info["global variables"] = [Array(target.eval("global_variables")).sort, i += 1] if options[:g] || options[:a]
282
-
489
+
283
490
  info["public methods"] = [Array(target.eval("public_methods(#{options[:s]})")).uniq.sort, i += 1] if (options[:m] && options[:P]) || options[:a]
284
491
 
285
492
  info["protected methods"] = [Array(target.eval("protected_methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:r]) || options[:a]
@@ -287,59 +494,132 @@ Shows local and instance variables by default.
287
494
  info["private methods"] = [Array(target.eval("private_methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:p]) || options[:a]
288
495
 
289
496
  info["just singleton methods"] = [Array(target.eval("methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:j]) || options[:a]
290
-
497
+
291
498
  info["public instance methods"] = [Array(target.eval("public_instance_methods(#{options[:s]})")).uniq.sort, i += 1] if target_self.is_a?(Module) && ((options[:M] && options[:P]) || options[:a])
292
499
 
293
500
  info["protected instance methods"] = [Array(target.eval("protected_instance_methods(#{options[:s]})")).uniq.sort, i += 1] if target_self.is_a?(Module) && ((options[:M] && options[:r]) || options[:a])
294
501
 
295
502
  info["private instance methods"] = [Array(target.eval("private_instance_methods(#{options[:s]})")).uniq.sort, i += 1] if target_self.is_a?(Module) && ((options[:M] && options[:p]) || options[:a])
296
-
503
+
297
504
  # dealing with 1.8/1.9 compatibility issues :/
298
505
  csuper = options[:s]
299
506
  if Module.method(:constants).arity == 0
300
507
  csuper = nil
301
508
  end
302
-
509
+
303
510
  info["constants"] = [Array(target_self.is_a?(Module) ? target.eval("constants(#{csuper})") :
304
511
  target.eval("self.class.constants(#{csuper})")).uniq.sort, i += 1] if options[:c] || options[:a]
305
512
 
513
+ text = ""
514
+
306
515
  # verbose output?
307
516
  if options[:v]
308
-
309
517
  # verbose
518
+
310
519
  info.sort_by { |k, v| v.last }.each do |k, v|
311
520
  if !v.first.empty?
312
- output.puts "#{k}:\n--"
521
+ text << "#{k}:\n--\n"
522
+ filtered_list = v.first.grep options[:grep]
313
523
  if Pry.color
314
- output.puts CodeRay.scan(Pry.view(v.first), :ruby).term
524
+ text << CodeRay.scan(Pry.view(filtered_list), :ruby).term + "\n"
315
525
  else
316
- output.puts Pry.view(v.first)
526
+ text << Pry.view(filtered_list) + "\n"
317
527
  end
318
- output.puts
528
+ text << "\n\n"
319
529
  end
320
530
  end
321
531
 
532
+ if !options[:f]
533
+ stagger_output(text)
534
+ else
535
+ output.puts text
536
+ end
537
+
322
538
  # plain
323
539
  else
324
540
  list = info.values.sort_by(&:last).map(&:first).inject(&:+)
541
+ list = list.grep(options[:grep]) if list
325
542
  list.uniq! if list
326
543
  if Pry.color
327
- output.puts CodeRay.scan(Pry.view(list), :ruby).term
544
+ text << CodeRay.scan(Pry.view(list), :ruby).term + "\n"
328
545
  else
329
- output.puts Pry.view(list)
546
+ text << Pry.view(list) + "\n"
547
+ end
548
+ if !options[:f]
549
+ stagger_output(text)
550
+ else
551
+ output.puts text
330
552
  end
331
553
  list
332
554
  end
333
555
  end
334
556
 
335
- command "cat-file", "Show output of file FILE" do |file_name|
557
+ command "lls", "List local files using 'ls'" do |*args|
558
+ cmd = ".ls"
559
+ cmd << " --color=always" if Pry.color
560
+ run cmd, *args
561
+ end
562
+
563
+ command "lcd", "Change the current (working) directory" do |*args|
564
+ run ".cd", *args
565
+ end
566
+
567
+ command "cat", "Show output of file FILE. Type `cat --help` for more information." do |*args|
568
+ options= {}
569
+ file_name = nil
570
+ start_line = 0
571
+ end_line = -1
572
+ file_type = nil
573
+
574
+ OptionParser.new do |opts|
575
+ opts.banner = %{Usage: cat [OPTIONS] FILE
576
+ Cat a file. Defaults to displaying whole file. Syntax highlights file if type is recognized.
577
+ e.g: cat hello.rb
578
+ --
579
+ }
580
+ opts.on("-l", "--line-numbers", "Show line numbers.") do |line|
581
+ options[:l] = true
582
+ end
583
+
584
+ opts.on("-s", "--start LINE", "Start line (defaults to start of file). Line 1 is the first line.") do |line|
585
+ start_line = line.to_i - 1
586
+ end
587
+
588
+ opts.on("-e", "--end LINE", "End line (defaults to end of file). Line -1 is the last line.") do |line|
589
+ end_line = line.to_i - 1
590
+ end
591
+
592
+ opts.on("-t", "--type TYPE", "The specific file type for syntax higlighting (e.g ruby, python, cpp, java)") do |type|
593
+ file_type = type.to_sym
594
+ end
595
+
596
+ opts.on("-f", "--flood", "Do not use a pager to view text longer than one screen.") do
597
+ options[:f] = true
598
+ end
599
+
600
+ opts.on_tail("-h", "--help", "This message.") do
601
+ output.puts opts
602
+ options[:h] = true
603
+ end
604
+ end.order(args) do |v|
605
+ file_name = v
606
+ end
607
+
608
+ next if options[:h]
609
+
336
610
  if !file_name
337
611
  output.puts "Must provide a file name."
338
612
  next
339
613
  end
340
614
 
341
- contents = File.read(File.expand_path(file_name))
342
- output.puts contents
615
+ contents, normalized_start_line, _ = read_between_the_lines(file_name, start_line, end_line)
616
+
617
+ if Pry.color
618
+ contents = syntax_highlight_by_file_type_or_specified(contents, file_name, file_type)
619
+ end
620
+
621
+ set_file_and_dir_locals(file_name)
622
+ render_output(options[:f], options[:l] ? normalized_start_line + 1 : false, contents)
343
623
  contents
344
624
  end
345
625
 
@@ -347,7 +627,7 @@ Shows local and instance variables by default.
347
627
  options = {}
348
628
  target = target()
349
629
  file_name = nil
350
-
630
+
351
631
  OptionParser.new do |opts|
352
632
  opts.banner = %{Usage: eval-file [OPTIONS] FILE
353
633
  Eval a Ruby script at top-level or in the specified context. Defaults to top-level.
@@ -359,7 +639,7 @@ e.g: eval-file -c self "hello.rb"
359
639
  target = Pry.binding_for(target.eval(context))
360
640
  end
361
641
 
362
- opts.on_tail("-h", "--help", "This message.") do
642
+ opts.on_tail("-h", "--help", "This message.") do
363
643
  output.puts opts
364
644
  options[:h] = true
365
645
  end
@@ -383,235 +663,193 @@ e.g: eval-file -c self "hello.rb"
383
663
  TOPLEVEL_BINDING.eval(File.read(File.expand_path(file_name)))
384
664
  output.puts "--\nEval'd '#{file_name}' at top-level."
385
665
  end
666
+ set_file_and_dir_locals(file_name)
667
+
386
668
  new_constants = Object.constants - old_constants
387
669
  output.puts "Brought in the following top-level constants: #{new_constants.inspect}" if !new_constants.empty?
388
- end
389
-
390
- command "cat", "Show output of VAR.inspect. Aliases: inspect" do |obj|
391
- if !obj
392
- output.puts "Must provide an object to inspect."
393
- next
394
- end
395
-
396
- output.puts Pry.view(target.eval("#{obj}"))
397
670
  end
398
671
 
399
- alias_command "inspect", "cat", ""
400
-
401
672
  command "cd", "Start a Pry session on VAR (use `cd ..` to go back and `cd /` to return to Pry top-level)", :keep_retval => true do |obj|
402
673
  if !obj
403
674
  output.puts "Must provide an object."
404
675
  next
405
676
  end
406
-
677
+
407
678
  throw(:breakout, opts[:nesting].level) if obj == ".."
408
679
 
409
- if obj == "/"
680
+ if obj == "/"
410
681
  throw(:breakout, 1) if opts[:nesting].level > 0
411
682
  next
412
- end
413
-
414
- target.eval("#{obj}.pry")
415
- end
416
-
417
- process_comment_markup = lambda do |comment, code_type|
418
- comment.gsub(/<code>(?:\s*\n)?(.*?)\s*<\/code>/m) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }.
419
- gsub(/<em>(?:\s*\n)?(.*?)\s*<\/em>/m) { Pry.color ? "\e[32m#{$1}\e[0m": $1 }.
420
- gsub(/<i>(?:\s*\n)?(.*?)\s*<\/i>/m) { Pry.color ? "\e[34m#{$1}\e[0m" : $1 }.
421
- gsub(/\B\+(\w*?)\+\B/) { Pry.color ? "\e[32m#{$1}\e[0m": $1 }.
422
- gsub(/((?:^[ \t]+.+(?:\n+|\Z))+)/) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }
423
- end
683
+ end
424
684
 
425
- strip_leading_hash_from_ruby_comments = lambda do |comment|
426
- comment.gsub /^\s*#\s*/, ''
685
+ Pry.start target.eval("#{obj}")
427
686
  end
428
687
 
429
- command "show-doc", "Show the comments above METH. Type `show-doc --help` for more info." do |*args|
430
- options = {}
688
+ command "show-doc", "Show the comments above METH. Type `show-doc --help` for more info. Aliases: \?" do |*args|
431
689
  target = target()
432
- meth_name = nil
433
-
434
- OptionParser.new do |opts|
435
- opts.banner = %{Usage: show-doc [OPTIONS] [METH]
690
+
691
+ opts = Slop.parse!(args) do |opts|
692
+ opts.banner %{Usage: show-doc [OPTIONS] [METH]
436
693
  Show the comments above method METH. Tries instance methods first and then methods by default.
437
694
  e.g show-doc hello_method
438
695
  --
439
696
  }
440
- opts.on("-M", "--instance-methods", "Operate on instance methods.") do
441
- options[:M] = true
442
- end
443
-
444
- opts.on("-m", "--methods", "Operate on methods.") do
445
- options[:m] = true
446
- end
447
-
448
- opts.on("-c", "--context CONTEXT", "Select object context to run under.") do |context|
697
+ opts.on :M, "instance-methods", "Operate on instance methods."
698
+ opts.on :m, :methods, "Operate on methods."
699
+ opts.on :c, :context, "Select object context to run under.", true do |context|
449
700
  target = Pry.binding_for(target.eval(context))
450
701
  end
451
-
452
- opts.on_tail("-h", "--help", "This message.") do
702
+ opts.on :f, :flood, "Do not use a pager to view text longer than one screen."
703
+ opts.on :h, :help, "This message." do
453
704
  output.puts opts
454
- options[:h] = true
455
705
  end
456
- end.order(args) do |v|
457
- meth_name = v
458
706
  end
459
707
 
460
- next if options[:h]
708
+ next if opts.help?
461
709
 
462
- if !meth_name
463
- output.puts "You need to specify a method. Type `show-doc --help` for help"
464
- next
710
+ meth_name = args.shift
711
+ if meth_name
712
+ if meth_name =~ /\A([^\.\#]+)[\.\#](.+)\z/ && !opts.context?
713
+ context, meth_name = $1, $2
714
+ target = Pry.binding_for(target.eval(context))
715
+ end
716
+ else
717
+ meth_name = meth_name_from_binding(target)
465
718
  end
466
-
467
- begin
468
- meth = get_method_object.call(meth_name, target, options)
469
- rescue
719
+
720
+ if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
470
721
  output.puts "Invalid method name: #{meth_name}. Type `show-doc --help` for help"
471
722
  next
472
723
  end
473
724
 
474
- code_type = :ruby
475
- if Pry.has_pry_doc && meth.source_location.nil?
476
- info = Pry::MethodInfo.info_for(meth)
477
- if !info
478
- output.puts "Cannot find docs for C method: #{meth_name}"
479
- next
480
- end
481
- doc = info.docstring
482
- code_type = info.source_type
483
- else
484
- begin
485
- doc = meth.comment
486
- rescue
487
- output.puts "Cannot locate source for this method: #{meth_name}. Try `gem install pry-doc` to get access to Ruby Core documentation."
488
- next
489
- end
490
- doc = strip_leading_hash_from_ruby_comments.call(doc)
491
- end
725
+ doc, code_type = doc_and_code_type_for(meth)
726
+ next if !doc
492
727
 
493
- doc = process_comment_markup.call(doc, code_type)
494
-
495
- file, line = meth.source_location
496
- check_for_dynamically_defined_method.call(file)
728
+ next output.puts("No documentation found.") if doc.empty?
497
729
 
498
- output.puts make_header.call(file, line, code_type)
499
-
500
- output.puts doc
730
+ doc = process_comment_markup(doc, code_type)
731
+
732
+ output.puts make_header(meth, code_type, doc)
733
+
734
+ render_output(opts.flood?, false, doc)
501
735
  doc
502
736
  end
503
737
 
504
- strip_comments_from_c_code = lambda do |code|
505
- code.sub /\A\s*\/\*.*?\*\/\s*/m, ''
506
- end
507
-
508
- command "show-method", "Show the source for METH. Type `show-method --help` for more info." do |*args|
509
- options = {}
738
+ alias_command "?", "show-doc", ""
739
+
740
+ command "show-method", "Show the source for METH. Type `show-method --help` for more info. Aliases: $, show-source" do |*args|
510
741
  target = target()
511
- meth_name = nil
512
-
513
- OptionParser.new do |opts|
514
- opts.banner = %{Usage: show-method [OPTIONS] [METH]
742
+
743
+ opts = Slop.parse!(args) do |opts|
744
+ opts.banner %{Usage: show-method [OPTIONS] [METH]
515
745
  Show the source for method METH. Tries instance methods first and then methods by default.
516
746
  e.g: show-method hello_method
517
747
  --
518
748
  }
519
- opts.on("-M", "--instance-methods", "Operate on instance methods.") do
520
- options[:M] = true
521
- end
522
-
523
- opts.on("-m", "--methods", "Operate on methods.") do
524
- options[:m] = true
525
- end
526
-
527
- opts.on("-c", "--context CONTEXT", "Select object context to run under.") do |context|
749
+ opts.on :l, "line-numbers", "Show line numbers."
750
+ opts.on :M, "instance-methods", "Operate on instance methods."
751
+ opts.on :m, :methods, "Operate on methods."
752
+ opts.on :f, :flood, "Do not use a pager to view text longer than one screen."
753
+ opts.on :c, :context, "Select object context to run under.", true do |context|
528
754
  target = Pry.binding_for(target.eval(context))
529
755
  end
530
-
531
- opts.on_tail("-h", "--help", "This message.") do
756
+ opts.on :h, :help, "This message." do
532
757
  output.puts opts
533
- options[:h] = true
534
758
  end
535
- end.order(args) do |v|
536
- meth_name = v
537
759
  end
538
760
 
539
- next if options[:h]
761
+ next if opts.help?
540
762
 
541
- # If no method name is given then use current method, if it exists
542
- meth_name = meth_name_from_binding.call(target) if !meth_name
543
- if !meth_name
544
- output.puts "You need to specify a method. Type `show-method --help` for help"
545
- next
763
+ meth_name = args.shift
764
+ if meth_name
765
+ if meth_name =~ /\A([^\.\#]+)[\.\#](.+)\z/ && !opts.context?
766
+ context, meth_name = $1, $2
767
+ target = Pry.binding_for(target.eval(context))
768
+ end
769
+ else
770
+ meth_name = meth_name_from_binding(target)
546
771
  end
547
-
548
- begin
549
- meth = get_method_object.call(meth_name, target, options)
550
- rescue
772
+
773
+ if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
551
774
  output.puts "Invalid method name: #{meth_name}. Type `show-method --help` for help"
552
775
  next
553
776
  end
554
777
 
555
- code_type = :ruby
556
-
557
- # Try to find source for C methods using MethodInfo (if possible)
558
- if Pry.has_pry_doc && meth.source_location.nil?
559
- info = Pry::MethodInfo.info_for(meth)
560
- if !info || !info.source
561
- output.puts "Cannot find source for C method: #{meth_name}"
562
- next
563
- end
564
- code = info.source
565
- code = strip_comments_from_c_code.call(code)
566
- code_type = info.source_type
567
- else
568
- begin
569
- code = meth.source
570
- rescue
571
- output.puts "Cannot locate source for this method: #{meth_name}. Try `gem install pry-doc` to get access to Ruby Core documentation."
572
- next
573
- end
574
- end
575
-
576
- file, line = meth.source_location
577
- check_for_dynamically_defined_method.call(file)
578
-
579
- output.puts make_header.call(file, line, code_type)
778
+ code, code_type = code_and_code_type_for(meth)
779
+ next if !code
580
780
 
781
+ output.puts make_header(meth, code_type, code)
581
782
  if Pry.color
582
783
  code = CodeRay.scan(code, code_type).term
583
784
  end
584
-
585
- output.puts code
785
+
786
+ start_line = false
787
+ if opts.l?
788
+ start_line = meth.source_location ? meth.source_location.last : 1
789
+ end
790
+
791
+ render_output(opts.flood?, start_line, code)
586
792
  code
587
793
  end
588
-
589
- command "show-command", "Show sourcecode for a Pry command, e.g: show-command cd" do |command_name|
794
+
795
+ alias_command "show-source", "show-method", ""
796
+ alias_command "$", "show-method", ""
797
+
798
+ command "show-command", "Show the source for CMD. Type `show-command --help` for more info." do |*args|
799
+ options = {}
800
+ target = target()
801
+ command_name = nil
802
+
803
+ OptionParser.new do |opts|
804
+ opts.banner = %{Usage: show-command [OPTIONS] [CMD]
805
+ Show the source for command CMD.
806
+ e.g: show-command show-method
807
+ --
808
+ }
809
+ opts.on("-l", "--line-numbers", "Show line numbers.") do |line|
810
+ options[:l] = true
811
+ end
812
+
813
+ opts.on("-f", "--flood", "Do not use a pager to view text longer than one screen.") do
814
+ options[:f] = true
815
+ end
816
+
817
+ opts.on_tail("-h", "--help", "This message.") do
818
+ output.puts opts
819
+ options[:h] = true
820
+ end
821
+ end.order(args) do |v|
822
+ command_name = v
823
+ end
824
+
825
+ next if options[:h]
826
+
590
827
  if !command_name
591
828
  output.puts "You must provide a command name."
592
829
  next
593
830
  end
594
-
831
+
595
832
  if commands[command_name]
596
833
  meth = commands[command_name][:action]
597
834
 
598
- code = meth.source
835
+ code = strip_leading_whitespace(meth.source)
599
836
  file, line = meth.source_location
600
- check_for_dynamically_defined_method.call(file)
837
+ set_file_and_dir_locals(file)
838
+ check_for_dynamically_defined_method(meth)
601
839
 
602
- output.puts "--\nFrom #{file} @ line #{line}:\n--"
840
+ output.puts make_header(meth, :ruby, code)
603
841
 
604
842
  if Pry.color
605
843
  code = CodeRay.scan(code, :ruby).term
606
844
  end
607
845
 
608
- output.puts code
846
+ render_output(options[:f], options[:l] ? meth.source_location.last : false, code)
609
847
  code
610
848
  else
611
849
  output.puts "No such command: #{command_name}."
612
850
  end
613
851
  end
614
-
852
+
615
853
  command "jump-to", "Jump to a Pry session further up the stack, exiting all sessions below." do |break_level|
616
854
  break_level = break_level.to_i
617
855
  nesting = opts[:nesting]
@@ -627,8 +865,8 @@ e.g: show-method hello_method
627
865
  end
628
866
  end
629
867
 
630
- command "exit", "End the current Pry session. Accepts optional return value. Aliases: quit, back" do
631
- str = remove_first_word.call(opts[:val])
868
+ command "exit", "End the current Pry session. Accepts optional return value. Aliases: quit, back" do
869
+ str = remove_first_word(opts[:val])
632
870
  throw(:breakout, [opts[:nesting].level, target.eval(str)])
633
871
  end
634
872
 
@@ -668,11 +906,11 @@ Is absorbed, not refracted, by grey stone.
668
906
  The dahlias sleep in the empty silence.
669
907
  Wait for the early owl.
670
908
  -- T.S Eliot
671
- }
909
+ }
672
910
  output.puts text
673
911
  text
674
912
  end
675
-
913
+
676
914
  command "cohen-poem", "" do
677
915
  text = %{
678
916
  --
@@ -690,7 +928,7 @@ and so small between the thin pines
690
928
  on these enormous landscapes,
691
929
  that if you turn your head
692
930
  they are lost for hours.
693
- -- Leonard Cohen
931
+ -- Leonard Cohen
694
932
  }
695
933
  output.puts text
696
934
  text