pry 0.7.7.2-i386-mswin32 → 0.8.0-i386-mswin32

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