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

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,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