pry 0.7.3 → 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,118 +1,207 @@
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 |meth|
29
- file, _ = meth.source_location
30
- if file =~ /(\(.*\))|<.*>/
31
- raise "Cannot retrieve source for dynamically defined method."
32
- end
24
+ command "!pry", "Start a Pry session on current self; this even works mid-expression." do
25
+ Pry.start(target)
33
26
  end
34
27
 
35
- remove_first_word = lambda do |text|
36
- 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
37
30
  end
38
31
 
39
- get_method_object = lambda do |meth_name, target, options|
40
- if !meth_name
41
- return nil
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
42
39
  end
43
40
 
44
- if options[:M]
45
- target.eval("instance_method(:#{meth_name})")
46
- elsif options[:m]
47
- target.eval("method(:#{meth_name})")
48
- else
49
- begin
50
- target.eval("instance_method(:#{meth_name})")
51
- rescue
52
- begin
53
- target.eval("method(:#{meth_name})")
54
- rescue
55
- return nil
56
- 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
57
46
  end
58
47
  end
59
- end
60
48
 
61
- make_header = lambda do |meth, code_type|
62
- file, line = meth.source_location
63
- header = case code_type
64
- when :ruby
65
- "--\nFrom #{file} @ line #{line}:\n--"
66
- else
67
- "--\nFrom Ruby Core (C Method):\n--"
68
- end
69
- end
49
+ next if opts.h?
70
50
 
71
- is_a_c_method = lambda do |meth|
72
- meth.source_location.nil?
51
+ actions = Array(hist_array[opts[:replay]]).join("\n") + "\n"
52
+ Pry.active_instance.input = StringIO.new(actions)
73
53
  end
74
54
 
75
- should_use_pry_doc = lambda do |meth|
76
- Pry.has_pry_doc && is_a_c_method.call(meth)
55
+ command "exit-program", "End the current program. Aliases: quit-program, !!!" do
56
+ exit
77
57
  end
78
-
79
- code_type_for = lambda do |meth|
80
- # only C methods
81
- if should_use_pry_doc.call(meth)
82
- info = Pry::MethodInfo.info_for(meth)
83
- if info && info.source
84
- code_type = :c
85
- else
86
- output.puts "Cannot find C method: #{meth.name}"
87
- code_type = nil
88
- end
89
- else
90
- if is_a_c_method.call(meth)
91
- output.puts "Cannot locate this method: #{meth.name}. Try `gem install pry-doc` to get access to Ruby Core documentation."
92
- code_type = nil
58
+
59
+ alias_command "quit-program", "exit-program", ""
60
+ alias_command "!!!", "exit-program", ""
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."
93
70
  else
94
- check_for_dynamically_defined_method.call(meth)
95
- code_type = :ruby
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
96
77
  end
78
+ rescue Gem::GemNotFoundException
79
+ output.puts "Required Gem: #{bold(gem_name)} not found."
80
+ next
97
81
  end
98
- code_type
82
+
83
+ Gem.refresh
84
+ output.puts "Refreshed gem cache."
99
85
  end
100
86
 
101
- command "!", "Clear the input buffer. Useful if the parsing process goes wrong and you get stuck in the read loop." do
102
- output.puts "Input buffer cleared!"
103
- opts[:eval_string].clear
87
+ command "ri", "View ri documentation. e.g `ri Array#each`" do |*args|
88
+ run ".ri", *args
104
89
  end
105
90
 
106
- command "!pry", "Start a Pry session on current self; this even works mid-expression." do
107
- Pry.start(target)
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.'))
108
144
  end
109
145
 
110
- command "exit-program", "End the current program. Aliases: quit-program, !!!" do
111
- exit
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
112
197
  end
113
198
 
114
- alias_command "quit-program", "exit-program", ""
115
- alias_command "!!!", "exit-program", ""
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
116
205
 
117
206
  command "toggle-color", "Toggle syntax highlighting." do
118
207
  Pry.color = !Pry.color
@@ -128,9 +217,24 @@ class Pry
128
217
  end
129
218
  end
130
219
 
131
- 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
132
236
  nesting = opts[:nesting]
133
-
237
+
134
238
  output.puts "Nesting status:"
135
239
  output.puts "--"
136
240
  nesting.each do |level, obj|
@@ -144,7 +248,7 @@ class Pry
144
248
 
145
249
  command "status", "Show status information." do
146
250
  nesting = opts[:nesting]
147
-
251
+
148
252
  output.puts "Status:"
149
253
  output.puts "--"
150
254
  output.puts "Receiver: #{Pry.view_clip(target.eval('self'))}"
@@ -152,32 +256,85 @@ class Pry
152
256
  output.puts "Pry version: #{Pry::VERSION}"
153
257
  output.puts "Ruby version: #{RUBY_VERSION}"
154
258
 
155
- mn = meth_name_from_binding.call(target)
259
+ mn = meth_name_from_binding(target)
156
260
  output.puts "Current method: #{mn ? mn : "N/A"}"
157
261
  output.puts "Pry instance: #{Pry.active_instance}"
158
262
  output.puts "Last result: #{Pry.view(Pry.last_result)}"
159
263
  end
160
264
 
161
- 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|
162
312
  file = target.eval('__FILE__')
163
313
  line_num = target.eval('__LINE__')
164
314
  klass = target.eval('self.class')
165
315
 
166
- meth_name = meth_name_from_binding.call(target)
167
- if !meth_name
168
- 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` ?"
169
327
  next
170
328
  end
171
329
 
172
- check_for_dynamically_defined_method.call(file)
173
-
174
- output.puts "--\nFrom #{file} @ line #{line_num} in #{klass}##{meth_name}:\n--"
175
-
330
+ set_file_and_dir_locals(file)
331
+ output.puts "\n#{bold('From:')} #{file} @ line #{line_num} in #{klass}##{meth_name}:\n\n"
332
+
176
333
  # This method inspired by http://rubygems.org/gems/ir_b
177
334
  File.open(file).each_with_index do |line, index|
178
335
  line_n = index + 1
179
- next unless line_n > (line_num - 6)
180
- 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)
181
338
  if line_n == line_num
182
339
  code =" =>#{line_n.to_s.rjust(3)}: #{line.chomp}"
183
340
  if Pry.color
@@ -195,25 +352,24 @@ class Pry
195
352
  end
196
353
  end
197
354
  end
198
-
355
+
199
356
  command "version", "Show Pry version." do
200
357
  output.puts "Pry version: #{Pry::VERSION} on Ruby #{RUBY_VERSION}."
201
358
  end
202
-
203
- command "exit-all", "End all nested Pry sessions. Accepts optional return value. Aliases: !@" do
204
- 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])
205
362
  throw(:breakout, [0, target.eval(str)])
206
363
  end
207
364
 
208
- alias_command "!@", "exit-all", ""
365
+ alias_command "!!@", "exit-all", ""
209
366
 
210
- 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|
211
368
  options = {}
212
-
213
369
  # Set target local to the default -- note that we can set a different target for
214
370
  # ls if we like: e.g ls my_var
215
371
  target = target()
216
-
372
+
217
373
  OptionParser.new do |opts|
218
374
  opts.banner = %{Usage: ls [OPTIONS] [VAR]\n\
219
375
  List information about VAR (the current context by default).
@@ -223,7 +379,7 @@ Shows local and instance variables by default.
223
379
  opts.on("-g", "--globals", "Display global variables.") do
224
380
  options[:g] = true
225
381
  end
226
-
382
+
227
383
  opts.on("-c", "--constants", "Display constants.") do
228
384
  options[:c] = true
229
385
  end
@@ -232,15 +388,15 @@ Shows local and instance variables by default.
232
388
  options[:l] = true
233
389
  end
234
390
 
235
- opts.on("-i", "--ivars", "Display instance variables.") do
391
+ opts.on("-i", "--ivars", "Display instance variables.") do
236
392
  options[:i] = true
237
393
  end
238
394
 
239
- opts.on("-k", "--class-vars", "Display class variables.") do
395
+ opts.on("-k", "--class-vars", "Display class variables.") do
240
396
  options[:k] = true
241
- end
397
+ end
242
398
 
243
- opts.on("-m", "--methods", "Display methods (public methods by default).") do
399
+ opts.on("-m", "--methods", "Display methods (public methods by default).") do
244
400
  options[:m] = true
245
401
  end
246
402
 
@@ -248,34 +404,42 @@ Shows local and instance variables by default.
248
404
  options[:M] = true
249
405
  end
250
406
 
251
- opts.on("-P", "--public", "Display public methods (with -m).") do
407
+ opts.on("-P", "--public", "Display public methods (with -m).") do
252
408
  options[:P] = true
253
409
  end
254
410
 
255
- opts.on("-r", "--protected", "Display protected methods (with -m).") do
411
+ opts.on("-r", "--protected", "Display protected methods (with -m).") do
256
412
  options[:r] = true
257
- end
413
+ end
258
414
 
259
- opts.on("-p", "--private", "Display private methods (with -m).") do
415
+ opts.on("-p", "--private", "Display private methods (with -m).") do
260
416
  options[:p] = true
261
417
  end
262
418
 
263
- 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
264
420
  options[:j] = true
265
- end
421
+ end
266
422
 
267
- 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
268
424
  options[:s] = true
269
425
  end
270
-
426
+
271
427
  opts.on("-a", "--all", "Display all types of entries.") do
272
428
  options[:a] = true
273
429
  end
274
430
 
275
- opts.on("-v", "--verbose", "Verbose ouput.") do
431
+ opts.on("-v", "--verbose", "Verbose ouput.") do
276
432
  options[:v] = true
277
433
  end
278
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
+
279
443
  opts.on_tail("-h", "--help", "Show this message.") do
280
444
  output.puts opts
281
445
  options[:h] = true
@@ -293,18 +457,21 @@ Shows local and instance variables by default.
293
457
  :l => true,
294
458
  :i => true,
295
459
  :k => true
296
- }) 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
+
297
464
 
298
465
  # Display public methods by default if -m or -M switch is used.
299
466
  options[:P] = true if (options[:m] || options[:M]) && !(options[:p] || options[:r] || options[:j])
300
-
467
+
301
468
  info = {}
302
469
  target_self = target.eval('self')
303
470
 
304
471
  # ensure we have a real boolean and not a `nil` (important when
305
472
  # interpolating in the string)
306
473
  options[:s] = !!options[:s]
307
-
474
+
308
475
  # Numbers (e.g 0, 1, 2) are for ordering the hash values in Ruby 1.8
309
476
  i = -1
310
477
 
@@ -319,7 +486,7 @@ Shows local and instance variables by default.
319
486
  end, i += 1] if options[:k] || options[:a]
320
487
 
321
488
  info["global variables"] = [Array(target.eval("global_variables")).sort, i += 1] if options[:g] || options[:a]
322
-
489
+
323
490
  info["public methods"] = [Array(target.eval("public_methods(#{options[:s]})")).uniq.sort, i += 1] if (options[:m] && options[:P]) || options[:a]
324
491
 
325
492
  info["protected methods"] = [Array(target.eval("protected_methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:r]) || options[:a]
@@ -327,59 +494,132 @@ Shows local and instance variables by default.
327
494
  info["private methods"] = [Array(target.eval("private_methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:p]) || options[:a]
328
495
 
329
496
  info["just singleton methods"] = [Array(target.eval("methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:j]) || options[:a]
330
-
497
+
331
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])
332
499
 
333
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])
334
501
 
335
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])
336
-
503
+
337
504
  # dealing with 1.8/1.9 compatibility issues :/
338
505
  csuper = options[:s]
339
506
  if Module.method(:constants).arity == 0
340
507
  csuper = nil
341
508
  end
342
-
509
+
343
510
  info["constants"] = [Array(target_self.is_a?(Module) ? target.eval("constants(#{csuper})") :
344
511
  target.eval("self.class.constants(#{csuper})")).uniq.sort, i += 1] if options[:c] || options[:a]
345
512
 
513
+ text = ""
514
+
346
515
  # verbose output?
347
516
  if options[:v]
348
-
349
517
  # verbose
518
+
350
519
  info.sort_by { |k, v| v.last }.each do |k, v|
351
520
  if !v.first.empty?
352
- output.puts "#{k}:\n--"
521
+ text << "#{k}:\n--\n"
522
+ filtered_list = v.first.grep options[:grep]
353
523
  if Pry.color
354
- output.puts CodeRay.scan(Pry.view(v.first), :ruby).term
524
+ text << CodeRay.scan(Pry.view(filtered_list), :ruby).term + "\n"
355
525
  else
356
- output.puts Pry.view(v.first)
526
+ text << Pry.view(filtered_list) + "\n"
357
527
  end
358
- output.puts
528
+ text << "\n\n"
359
529
  end
360
530
  end
361
531
 
532
+ if !options[:f]
533
+ stagger_output(text)
534
+ else
535
+ output.puts text
536
+ end
537
+
362
538
  # plain
363
539
  else
364
540
  list = info.values.sort_by(&:last).map(&:first).inject(&:+)
541
+ list = list.grep(options[:grep]) if list
365
542
  list.uniq! if list
366
543
  if Pry.color
367
- output.puts CodeRay.scan(Pry.view(list), :ruby).term
544
+ text << CodeRay.scan(Pry.view(list), :ruby).term + "\n"
545
+ else
546
+ text << Pry.view(list) + "\n"
547
+ end
548
+ if !options[:f]
549
+ stagger_output(text)
368
550
  else
369
- output.puts Pry.view(list)
551
+ output.puts text
370
552
  end
371
553
  list
372
554
  end
373
555
  end
374
556
 
375
- 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
+
376
610
  if !file_name
377
611
  output.puts "Must provide a file name."
378
612
  next
379
613
  end
380
614
 
381
- contents = File.read(File.expand_path(file_name))
382
- 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)
383
623
  contents
384
624
  end
385
625
 
@@ -387,7 +627,7 @@ Shows local and instance variables by default.
387
627
  options = {}
388
628
  target = target()
389
629
  file_name = nil
390
-
630
+
391
631
  OptionParser.new do |opts|
392
632
  opts.banner = %{Usage: eval-file [OPTIONS] FILE
393
633
  Eval a Ruby script at top-level or in the specified context. Defaults to top-level.
@@ -399,7 +639,7 @@ e.g: eval-file -c self "hello.rb"
399
639
  target = Pry.binding_for(target.eval(context))
400
640
  end
401
641
 
402
- opts.on_tail("-h", "--help", "This message.") do
642
+ opts.on_tail("-h", "--help", "This message.") do
403
643
  output.puts opts
404
644
  options[:h] = true
405
645
  end
@@ -423,192 +663,193 @@ e.g: eval-file -c self "hello.rb"
423
663
  TOPLEVEL_BINDING.eval(File.read(File.expand_path(file_name)))
424
664
  output.puts "--\nEval'd '#{file_name}' at top-level."
425
665
  end
666
+ set_file_and_dir_locals(file_name)
667
+
426
668
  new_constants = Object.constants - old_constants
427
669
  output.puts "Brought in the following top-level constants: #{new_constants.inspect}" if !new_constants.empty?
428
- end
429
-
430
- command "cat", "Show output of VAR.inspect. Aliases: inspect" do |obj|
431
- if !obj
432
- output.puts "Must provide an object to inspect."
433
- next
434
- end
435
-
436
- output.puts Pry.view(target.eval("#{obj}"))
437
670
  end
438
671
 
439
- alias_command "inspect", "cat", ""
440
-
441
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|
442
673
  if !obj
443
674
  output.puts "Must provide an object."
444
675
  next
445
676
  end
446
-
677
+
447
678
  throw(:breakout, opts[:nesting].level) if obj == ".."
448
679
 
449
- if obj == "/"
680
+ if obj == "/"
450
681
  throw(:breakout, 1) if opts[:nesting].level > 0
451
682
  next
452
- end
453
-
454
- target.eval("#{obj}.pry")
455
- end
456
-
457
- process_comment_markup = lambda do |comment, code_type|
458
- comment.gsub(/<code>(?:\s*\n)?(.*?)\s*<\/code>/m) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }.
459
- gsub(/<em>(?:\s*\n)?(.*?)\s*<\/em>/m) { Pry.color ? "\e[32m#{$1}\e[0m": $1 }.
460
- gsub(/<i>(?:\s*\n)?(.*?)\s*<\/i>/m) { Pry.color ? "\e[34m#{$1}\e[0m" : $1 }.
461
- gsub(/\B\+(\w*?)\+\B/) { Pry.color ? "\e[32m#{$1}\e[0m": $1 }.
462
- gsub(/((?:^[ \t]+.+(?:\n+|\Z))+)/) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }
463
- end
683
+ end
464
684
 
465
- strip_leading_hash_from_ruby_comments = lambda do |comment|
466
- comment.gsub /^\s*#\s*/, ''
685
+ Pry.start target.eval("#{obj}")
467
686
  end
468
687
 
469
- command "show-doc", "Show the comments above METH. Type `show-doc --help` for more info." do |*args|
470
- options = {}
688
+ command "show-doc", "Show the comments above METH. Type `show-doc --help` for more info. Aliases: \?" do |*args|
471
689
  target = target()
472
- meth_name = nil
473
-
474
- OptionParser.new do |opts|
475
- opts.banner = %{Usage: show-doc [OPTIONS] [METH]
690
+
691
+ opts = Slop.parse!(args) do |opts|
692
+ opts.banner %{Usage: show-doc [OPTIONS] [METH]
476
693
  Show the comments above method METH. Tries instance methods first and then methods by default.
477
694
  e.g show-doc hello_method
478
695
  --
479
696
  }
480
- opts.on("-M", "--instance-methods", "Operate on instance methods.") do
481
- options[:M] = true
482
- end
483
-
484
- opts.on("-m", "--methods", "Operate on methods.") do
485
- options[:m] = true
486
- end
487
-
488
- 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|
489
700
  target = Pry.binding_for(target.eval(context))
490
701
  end
491
-
492
- 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
493
704
  output.puts opts
494
- options[:h] = true
495
705
  end
496
- end.order(args) do |v|
497
- meth_name = v
498
706
  end
499
707
 
500
- next if options[:h]
708
+ next if opts.help?
501
709
 
502
- if (meth = get_method_object.call(meth_name, target, options)).nil?
503
- output.puts "Invalid method name: #{meth_name}. Type `show-doc --help` for help"
504
- 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)
505
718
  end
506
719
 
507
- case code_type = code_type_for.call(meth)
508
- when nil
720
+ if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
721
+ output.puts "Invalid method name: #{meth_name}. Type `show-doc --help` for help"
509
722
  next
510
- when :c
511
- doc = Pry::MethodInfo.info_for(meth).docstring
512
- when :ruby
513
- doc = meth.comment
514
- doc = strip_leading_hash_from_ruby_comments.call(doc)
515
723
  end
516
724
 
517
- doc = process_comment_markup.call(doc, code_type)
518
- output.puts make_header.call(meth, code_type)
519
- output.puts doc
725
+ doc, code_type = doc_and_code_type_for(meth)
726
+ next if !doc
727
+
728
+ next output.puts("No documentation found.") if doc.empty?
729
+
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)
520
735
  doc
521
736
  end
522
737
 
523
- strip_comments_from_c_code = lambda do |code|
524
- code.sub /\A\s*\/\*.*?\*\/\s*/m, ''
525
- end
526
-
527
- command "show-method", "Show the source for METH. Type `show-method --help` for more info. Aliases: show-source" do |*args|
528
- 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|
529
741
  target = target()
530
- meth_name = nil
531
-
532
- OptionParser.new do |opts|
533
- opts.banner = %{Usage: show-method [OPTIONS] [METH]
742
+
743
+ opts = Slop.parse!(args) do |opts|
744
+ opts.banner %{Usage: show-method [OPTIONS] [METH]
534
745
  Show the source for method METH. Tries instance methods first and then methods by default.
535
746
  e.g: show-method hello_method
536
747
  --
537
748
  }
538
- opts.on("-M", "--instance-methods", "Operate on instance methods.") do
539
- options[:M] = true
540
- end
541
-
542
- opts.on("-m", "--methods", "Operate on methods.") do
543
- options[:m] = true
544
- end
545
-
546
- 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|
547
754
  target = Pry.binding_for(target.eval(context))
548
755
  end
549
-
550
- opts.on_tail("-h", "--help", "This message.") do
756
+ opts.on :h, :help, "This message." do
551
757
  output.puts opts
552
- options[:h] = true
553
758
  end
554
- end.order(args) do |v|
555
- meth_name = v
556
759
  end
557
760
 
558
- next if options[:h]
761
+ next if opts.help?
559
762
 
560
- if (meth = get_method_object.call(meth_name, target, options)).nil?
561
- output.puts "Invalid method name: #{meth_name}. Type `show-method --help` for help"
562
- 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)
563
771
  end
564
-
565
- case code_type = code_type_for.call(meth)
566
- when nil
772
+
773
+ if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
774
+ output.puts "Invalid method name: #{meth_name}. Type `show-method --help` for help"
567
775
  next
568
- when :c
569
- code = Pry::MethodInfo.info_for(meth).source
570
- code = strip_comments_from_c_code.call(code)
571
- when :ruby
572
- code = meth.source
573
776
  end
574
777
 
575
- output.puts make_header.call(meth, code_type)
778
+ code, code_type = code_and_code_type_for(meth)
779
+ next if !code
780
+
781
+ output.puts make_header(meth, code_type, code)
576
782
  if Pry.color
577
783
  code = CodeRay.scan(code, code_type).term
578
784
  end
579
-
580
- 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)
581
792
  code
582
793
  end
583
794
 
584
795
  alias_command "show-source", "show-method", ""
585
-
586
- command "show-command", "Show sourcecode for a Pry command, e.g: show-command cd" do |command_name|
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
+
587
827
  if !command_name
588
828
  output.puts "You must provide a command name."
589
829
  next
590
830
  end
591
-
831
+
592
832
  if commands[command_name]
593
833
  meth = commands[command_name][:action]
594
834
 
595
- code = meth.source
835
+ code = strip_leading_whitespace(meth.source)
596
836
  file, line = meth.source_location
597
- check_for_dynamically_defined_method.call(meth)
837
+ set_file_and_dir_locals(file)
838
+ check_for_dynamically_defined_method(meth)
598
839
 
599
- output.puts "--\nFrom #{file} @ line #{line}:\n--"
840
+ output.puts make_header(meth, :ruby, code)
600
841
 
601
842
  if Pry.color
602
843
  code = CodeRay.scan(code, :ruby).term
603
844
  end
604
845
 
605
- output.puts code
846
+ render_output(options[:f], options[:l] ? meth.source_location.last : false, code)
606
847
  code
607
848
  else
608
849
  output.puts "No such command: #{command_name}."
609
850
  end
610
851
  end
611
-
852
+
612
853
  command "jump-to", "Jump to a Pry session further up the stack, exiting all sessions below." do |break_level|
613
854
  break_level = break_level.to_i
614
855
  nesting = opts[:nesting]
@@ -624,8 +865,8 @@ e.g: show-method hello_method
624
865
  end
625
866
  end
626
867
 
627
- command "exit", "End the current Pry session. Accepts optional return value. Aliases: quit, back" do
628
- 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])
629
870
  throw(:breakout, [opts[:nesting].level, target.eval(str)])
630
871
  end
631
872
 
@@ -665,11 +906,11 @@ Is absorbed, not refracted, by grey stone.
665
906
  The dahlias sleep in the empty silence.
666
907
  Wait for the early owl.
667
908
  -- T.S Eliot
668
- }
909
+ }
669
910
  output.puts text
670
911
  text
671
912
  end
672
-
913
+
673
914
  command "cohen-poem", "" do
674
915
  text = %{
675
916
  --
@@ -687,7 +928,7 @@ and so small between the thin pines
687
928
  on these enormous landscapes,
688
929
  that if you turn your head
689
930
  they are lost for hours.
690
- -- Leonard Cohen
931
+ -- Leonard Cohen
691
932
  }
692
933
  output.puts text
693
934
  text