pry 0.8.0pre9 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,18 +1,18 @@
1
1
  class Pry
2
2
  class Commands < CommandBase
3
- module CommandHelpers
3
+ module CommandHelpers
4
4
 
5
5
  private
6
6
 
7
7
  def try_to_load_pry_doc
8
8
 
9
- # YARD crashes on rbx, so do not require it
9
+ # YARD crashes on rbx, so do not require it
10
10
  if !Object.const_defined?(:RUBY_ENGINE) || RUBY_ENGINE !~ /rbx/
11
11
  require "pry-doc"
12
12
  end
13
13
  rescue LoadError
14
14
  end
15
-
15
+
16
16
  def meth_name_from_binding(b)
17
17
  meth_name = b.eval('__method__')
18
18
  if [:__script__, nil, :__binding__, :__binding_impl__].include?(meth_name)
@@ -29,7 +29,7 @@ class Pry
29
29
  target.eval("_file_ = $_file_temp")
30
30
  target.eval("_dir_ = $_dir_temp")
31
31
  end
32
-
32
+
33
33
  def add_line_numbers(lines, start_line)
34
34
  line_array = lines.each_line.to_a
35
35
  line_array.each_with_index.map do |line, idx|
@@ -110,7 +110,7 @@ class Pry
110
110
  if !meth_name
111
111
  return nil
112
112
  end
113
-
113
+
114
114
  if options[:M]
115
115
  target.eval("instance_method(:#{meth_name})")
116
116
  elsif options[:m]
@@ -127,15 +127,16 @@ class Pry
127
127
  end
128
128
  end
129
129
  end
130
-
130
+
131
131
  def make_header(meth, code_type, content)
132
- file, line = meth.source_location
133
132
  num_lines = "Number of lines: #{bold(content.each_line.count.to_s)}"
134
133
  case code_type
135
134
  when :ruby
135
+ file, line = meth.source_location
136
136
  "\n#{bold('From:')} #{file} @ line #{line}:\n#{num_lines}\n\n"
137
137
  else
138
- "\n#{bold('From:')} Ruby Core (C Method):\n#{num_lines}\n\n"
138
+ file = Pry::MethodInfo.info_for(meth).file
139
+ "\n#{bold('From:')} #{file} in Ruby Core (C Method):\n#{num_lines}\n\n"
139
140
  end
140
141
  end
141
142
 
@@ -146,11 +147,11 @@ class Pry
146
147
  def should_use_pry_doc?(meth)
147
148
  Pry.has_pry_doc && is_a_c_method?(meth)
148
149
  end
149
-
150
+
150
151
  def code_type_for(meth)
151
152
  # only C methods
152
153
  if should_use_pry_doc?(meth)
153
- info = Pry::MethodInfo.info_for(meth)
154
+ info = Pry::MethodInfo.info_for(meth)
154
155
  if info && info.source
155
156
  code_type = :c
156
157
  else
@@ -168,7 +169,7 @@ class Pry
168
169
  end
169
170
  code_type
170
171
  end
171
-
172
+
172
173
  def file_map
173
174
  {
174
175
  [".c", ".h"] => :c,
@@ -187,7 +188,7 @@ class Pry
187
188
  ".json" => :json
188
189
  }
189
190
  end
190
-
191
+
191
192
  def syntax_highlight_by_file_type_or_specified(contents, file_name, file_type)
192
193
  _, language_detected = file_map.find do |k, v|
193
194
  Array(k).any? do |matcher|
@@ -204,7 +205,7 @@ class Pry
204
205
  def normalized_line_number(line_number, total_lines)
205
206
  line_number < 0 ? line_number + total_lines : line_number
206
207
  end
207
-
208
+
208
209
  # returns the file content between the lines and the normalized
209
210
  # start and end line numbers.
210
211
  def read_between_the_lines(file_name, start_line, end_line)
@@ -274,6 +275,29 @@ class Pry
274
275
  code.sub /\A\s*\/\*.*?\*\/\s*/m, ''
275
276
  end
276
277
 
278
+ def prompt(message, options="Yn")
279
+ opts = options.scan(/./)
280
+ optstring = opts.join("/") # case maintained
281
+ defaults = opts.select{|o| o.upcase == o }
282
+ opts = opts.map{|o| o.downcase}
283
+
284
+ raise "Error: Too many default values for the prompt: #{default.inspect}" if defaults.size > 1
285
+
286
+ default = defaults.first
287
+
288
+ loop do
289
+ response = Pry.input.readline("#{message} (#{optstring}) ").downcase
290
+ case response
291
+ when *opts
292
+ return response
293
+ when ""
294
+ return default.downcase
295
+ else
296
+ output.puts " |_ Invalid option: #{response.inspect}. Try again."
297
+ end
298
+ end
299
+ end
300
+
277
301
  end
278
302
  end
279
303
  end
@@ -6,15 +6,15 @@ class Pry
6
6
  SYSTEM_COMMAND_REGEX = /^#{Regexp.escape(SYSTEM_COMMAND_DELIMITER)}(.*)/
7
7
 
8
8
  extend Forwardable
9
-
9
+
10
10
  attr_accessor :pry_instance
11
-
11
+
12
12
  def initialize(pry_instance)
13
13
  @pry_instance = pry_instance
14
14
  end
15
15
 
16
16
  def_delegators :@pry_instance, :commands, :nesting, :output
17
-
17
+
18
18
  # Is the string a command valid?
19
19
  # @param [String] val The string passed in from the Pry prompt.
20
20
  # @return [Boolean] Whether the string is a valid command.
@@ -59,21 +59,31 @@ class Pry
59
59
  def execute_system_command(val, target)
60
60
  SYSTEM_COMMAND_REGEX =~ val
61
61
  cmd = interpolate_string($1, target)
62
-
62
+
63
63
  if cmd =~ /^cd\s+(.+)/i
64
64
  begin
65
- Dir.chdir(File.expand_path($1))
65
+ @@cd_history ||= []
66
+ if $1 == "-"
67
+ dest = @@cd_history.pop || Dir.pwd
68
+ else
69
+ dest = File.expand_path($1)
70
+ end
71
+
72
+ @@cd_history << Dir.pwd
73
+ Dir.chdir(dest)
66
74
  rescue Errno::ENOENT
67
- output.puts "No such directory: #{$1}"
75
+ output.puts "No such directory: #{dest}"
68
76
  end
69
77
  else
70
- system(cmd)
78
+ if !system(cmd)
79
+ output.puts "Error: there was a problem executing system command: #{cmd}"
80
+ end
71
81
  end
72
82
 
73
83
  # Tick, tock, im getting rid of this shit soon.
74
84
  val.replace("")
75
85
  end
76
-
86
+
77
87
  # Determine whether a Pry command was matched and return command data
78
88
  # and argument string.
79
89
  # This method should not need to be invoked directly.
@@ -114,7 +124,7 @@ class Pry
114
124
  args = args_string ? Shellwords.shellwords(args_string) : []
115
125
  action = cmd_data[:action]
116
126
  keep_retval = cmd_data[:keep_retval]
117
-
127
+
118
128
  options = {
119
129
  :val => val,
120
130
  :eval_string => eval_string,
@@ -157,7 +167,7 @@ class Pry
157
167
 
158
168
  # Tick, tock, im getting rid of this shit soon.
159
169
  options[:val].clear
160
-
170
+
161
171
  ret_val
162
172
  end
163
173
  end
@@ -2,6 +2,8 @@ direc = File.dirname(__FILE__)
2
2
 
3
3
  require "optparse"
4
4
  require "method_source"
5
+ require 'slop'
6
+ require 'rubygems/dependency_installer'
5
7
  require "#{direc}/command_base"
6
8
  require "#{direc}/pry_instance"
7
9
  require "#{direc}/command_helpers"
@@ -23,31 +25,30 @@ class Pry
23
25
  Pry.start(target)
24
26
  end
25
27
 
26
- # this cannot be accessed, it's just for help purposed.
28
+ # this cannot be accessed, it's just for help purposes.
27
29
  command ".<shell command>", "All text following a '.' is forwarded to the shell." do
28
30
  end
29
31
 
30
- command "hist", "Show and replay Readline history" do |*args|
31
- require 'slop'
32
+ command "hist", "Show and replay Readline history. Type `hist --help` for more info." do |*args|
33
+ hist_array = Readline::HISTORY.to_a
34
+
32
35
  if args.empty?
33
- text = add_line_numbers(Readline::HISTORY.to_a.join("\n"), 0)
36
+ text = add_line_numbers(hist_array.join("\n"), 0)
34
37
  stagger_output(text)
35
38
  next
36
39
  end
37
40
 
38
- opts = Slop.parse(args) do
39
- banner "Usage: hist [-rSTART..END]"
40
- on :r, :replay, 'The line (or range of lines) to replay.', true, :as => Range do |r|
41
- options[:r].argument_value = r.to_i if r.is_a?(String)
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
42
46
  end
43
- on :h, :help, 'Show this message.', :tail => true do
44
- output.puts help
45
- end
46
47
  end
47
48
 
48
49
  next if opts.h?
49
50
 
50
- actions = Array(Readline::HISTORY.to_a[opts[:r]]).join("\n") + "\n"
51
+ actions = Array(hist_array[opts[:replay]]).join("\n") + "\n"
51
52
  Pry.active_instance.input = StringIO.new(actions)
52
53
  end
53
54
 
@@ -58,46 +59,67 @@ class Pry
58
59
  alias_command "quit-program", "exit-program", ""
59
60
  alias_command "!!!", "exit-program", ""
60
61
 
62
+ command "gem-install", "Install a gem" do |gem_name|
63
+ gem_home = Gem.instance_variable_get(:@gem_home)
64
+ output.puts "Attempting to install gem: #{bold(gem_name)}"
65
+
66
+ begin
67
+ if File.writable?(gem_home)
68
+ Gem::DependencyInstaller.new.install(gem_name)
69
+ output.puts "Gem #{bold(gem_name)} successfully installed."
70
+ else
71
+ if system("sudo gem install #{gem_name}")
72
+ output.puts "Gem #{bold(gem_name)} successfully installed."
73
+ else
74
+ output.puts "Gem #{bold(gem_name)} could not be installed."
75
+ next
76
+ end
77
+ end
78
+ rescue Gem::GemNotFoundException
79
+ output.puts "Required Gem: #{bold(gem_name)} not found."
80
+ next
81
+ end
82
+
83
+ Gem.refresh
84
+ output.puts "Refreshed gem cache."
85
+ end
86
+
61
87
  command "ri", "View ri documentation. e.g `ri Array#each`" do |*args|
62
- run target, ".ri", *args
88
+ run ".ri", *args
63
89
  end
64
90
 
65
- command "stat", "View method information and set _file_ and _dir_ locals" do |*args|
66
- options = {}
91
+ command "stat", "View method information and set _file_ and _dir_ locals. Type `stat --help` for more info." do |*args|
67
92
  target = target()
68
- meth_name = nil
69
-
70
- OptionParser.new do |opts|
71
- opts.banner = %{Usage: stat [OPTIONS] [METH]
72
- Show method information for method METH and set _file_ and _dir_ locals.
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.
73
97
  e.g: stat hello_method
74
98
  --
75
99
  }
76
- opts.on("-M", "--instance-methods", "Operate on instance methods.") do
77
- options[:M] = true
78
- end
79
-
80
- opts.on("-m", "--methods", "Operate on methods.") do
81
- options[:m] = true
82
- end
83
-
84
- opts.on("-c", "--context CONTEXT", "Select object context to run under.") do |context|
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|
85
103
  target = Pry.binding_for(target.eval(context))
86
104
  end
87
-
88
- opts.on_tail("-h", "--help", "This message.") do
105
+ opts.on :h, :help, "This message" do
89
106
  output.puts opts
90
- options[:h] = true
91
107
  end
92
- end.order(args) do |v|
93
- meth_name = v
94
108
  end
95
109
 
96
- next if options[:h]
97
-
98
- meth_name = meth_name_from_binding(target) if !meth_name
110
+ next if opts.help?
99
111
 
100
- if (meth = get_method_object(meth_name, target, options)).nil?
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?
101
123
  output.puts "Invalid method name: #{meth_name}. Type `stat --help` for help"
102
124
  next
103
125
  end
@@ -108,50 +130,58 @@ e.g: stat hello_method
108
130
 
109
131
  output.puts make_header(meth, code_type, code)
110
132
  output.puts bold("Method Name: ") + meth_name
133
+ output.puts bold("Method Owner: ") + (meth.owner.to_s ? meth.owner.to_s : "Unknown")
111
134
  output.puts bold("Method Language: ") + code_type.to_s.capitalize
112
135
  output.puts bold("Method Type: ") + (meth.is_a?(Method) ? "Bound" : "Unbound")
113
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
114
143
  output.puts bold("Comment length: ") + (doc.empty? ? 'No comment.' : (doc.lines.count.to_s + ' lines.'))
115
144
  end
116
145
 
117
- command "gist-method", "Gist a method to github.", :requires_gem => "gist" do |*args|
118
- options = {}
119
- meth_name = nil
146
+ command "gist-method", "Gist a method to github. Type `gist-method --help` for more info.", :requires_gem => "gist" do |*args|
147
+ target = target()
120
148
 
121
- OptionParser.new do |opts|
149
+ opts = Slop.parse!(args) do |opts|
122
150
  opts.banner = %{Usage: gist-method [OPTIONS] [METH]
123
151
  Gist the method (doc or source) to github.
124
152
  e.g: gist -m my_method
125
153
  e.g: gist -d my_method
126
154
  --
127
155
  }
128
- opts.on("-m", "--method", "Gist a method's source.") do |line|
129
- options[:m] = true
130
- end
131
-
132
- opts.on("-d", "--doc", "Gist a method's documentation.") do
133
- options[:d] = true
134
- end
135
-
136
- opts.on_tail("-h", "--help", "This message.") do
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
137
160
  output.puts opts
138
- options[:h] = true
139
161
  end
140
- end.order(args) do |v|
141
- meth_name = v
142
162
  end
143
163
 
144
- next if options[:h]
145
-
146
- meth_name = meth_name_from_binding(target) if !meth_name
164
+ next if opts.help?
147
165
 
148
- if (meth = get_method_object(meth_name, target, options)).nil?
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?
149
179
  output.puts "Invalid method name: #{meth_name}. Type `gist-method --help` for help"
150
180
  next
151
181
  end
152
182
 
153
183
  type_map = { :ruby => "rb", :c => "c", :plain => "plain" }
154
- if !options[:d]
184
+ if !opts.doc?
155
185
  content, code_type = code_and_code_type_for(meth)
156
186
  else
157
187
  content, code_type = doc_and_code_type_for(meth)
@@ -160,8 +190,8 @@ e.g: gist -d my_method
160
190
  end
161
191
  code_type = :plain
162
192
  end
163
-
164
- IO.popen("gist -p -t #{type_map[code_type]} -", "w") do |gist|
193
+
194
+ IO.popen("gist#{' -p' if opts.p?} -t #{type_map[code_type]} -", "w") do |gist|
165
195
  gist.puts content
166
196
  end
167
197
  end
@@ -189,22 +219,22 @@ e.g: gist -d my_method
189
219
 
190
220
  command "shell-mode", "Toggle shell mode. Bring in pwd prompt and file completion." do
191
221
  case Pry.active_instance.prompt
192
- when Pry::FILE_PROMPT
222
+ when Pry::SHELL_PROMPT
193
223
  Pry.active_instance.prompt = Pry::DEFAULT_PROMPT
194
224
  Pry.active_instance.custom_completions = Pry::DEFAULT_CUSTOM_COMPLETIONS
195
225
  else
196
- Pry.active_instance.prompt = Pry::FILE_PROMPT
226
+ Pry.active_instance.prompt = Pry::SHELL_PROMPT
197
227
  Pry.active_instance.custom_completions = Pry::FILE_COMPLETIONS
198
228
  Readline.completion_proc = Pry::InputCompleter.build_completion_proc target,
199
229
  Pry.active_instance.instance_eval(&Pry::FILE_COMPLETIONS)
200
- end
230
+ end
201
231
  end
202
232
 
203
233
  alias_command "file-mode", "shell-mode", ""
204
234
 
205
- command "nesting", "Show nesting information." do
235
+ command "nesting", "Show nesting information." do
206
236
  nesting = opts[:nesting]
207
-
237
+
208
238
  output.puts "Nesting status:"
209
239
  output.puts "--"
210
240
  nesting.each do |level, obj|
@@ -218,7 +248,7 @@ e.g: gist -d my_method
218
248
 
219
249
  command "status", "Show status information." do
220
250
  nesting = opts[:nesting]
221
-
251
+
222
252
  output.puts "Status:"
223
253
  output.puts "--"
224
254
  output.puts "Receiver: #{Pry.view_clip(target.eval('self'))}"
@@ -232,7 +262,53 @@ e.g: gist -d my_method
232
262
  output.puts "Last result: #{Pry.view(Pry.last_result)}"
233
263
  end
234
264
 
235
- 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|
236
312
  file = target.eval('__FILE__')
237
313
  line_num = target.eval('__LINE__')
238
314
  klass = target.eval('self.class')
@@ -246,14 +322,14 @@ e.g: gist -d my_method
246
322
  meth_name = meth_name_from_binding(target)
247
323
  meth_name = "N/A" if !meth_name
248
324
 
249
- if file =~ /(\(.*\))|<.*>/ || file == ""
325
+ if file =~ /(\(.*\))|<.*>/ || file == "" || file == "-e"
250
326
  output.puts "Cannot find local context. Did you use `binding.pry` ?"
251
327
  next
252
328
  end
253
-
254
- set_file_and_dir_locals(file)
329
+
330
+ set_file_and_dir_locals(file)
255
331
  output.puts "\n#{bold('From:')} #{file} @ line #{line_num} in #{klass}##{meth_name}:\n\n"
256
-
332
+
257
333
  # This method inspired by http://rubygems.org/gems/ir_b
258
334
  File.open(file).each_with_index do |line, index|
259
335
  line_n = index + 1
@@ -276,25 +352,24 @@ e.g: gist -d my_method
276
352
  end
277
353
  end
278
354
  end
279
-
355
+
280
356
  command "version", "Show Pry version." do
281
357
  output.puts "Pry version: #{Pry::VERSION} on Ruby #{RUBY_VERSION}."
282
358
  end
283
-
284
- command "exit-all", "End all nested Pry sessions. Accepts optional return value. Aliases: !@" do
359
+
360
+ command "exit-all", "End all nested Pry sessions. Accepts optional return value. Aliases: !!@" do
285
361
  str = remove_first_word(opts[:val])
286
362
  throw(:breakout, [0, target.eval(str)])
287
363
  end
288
364
 
289
- alias_command "!@", "exit-all", ""
365
+ alias_command "!!@", "exit-all", ""
290
366
 
291
367
  command "ls", "Show the list of vars and methods in the current scope. Type `ls --help` for more info." do |*args|
292
368
  options = {}
293
-
294
369
  # Set target local to the default -- note that we can set a different target for
295
370
  # ls if we like: e.g ls my_var
296
371
  target = target()
297
-
372
+
298
373
  OptionParser.new do |opts|
299
374
  opts.banner = %{Usage: ls [OPTIONS] [VAR]\n\
300
375
  List information about VAR (the current context by default).
@@ -304,7 +379,7 @@ Shows local and instance variables by default.
304
379
  opts.on("-g", "--globals", "Display global variables.") do
305
380
  options[:g] = true
306
381
  end
307
-
382
+
308
383
  opts.on("-c", "--constants", "Display constants.") do
309
384
  options[:c] = true
310
385
  end
@@ -313,15 +388,15 @@ Shows local and instance variables by default.
313
388
  options[:l] = true
314
389
  end
315
390
 
316
- opts.on("-i", "--ivars", "Display instance variables.") do
391
+ opts.on("-i", "--ivars", "Display instance variables.") do
317
392
  options[:i] = true
318
393
  end
319
394
 
320
- opts.on("-k", "--class-vars", "Display class variables.") do
395
+ opts.on("-k", "--class-vars", "Display class variables.") do
321
396
  options[:k] = true
322
- end
397
+ end
323
398
 
324
- opts.on("-m", "--methods", "Display methods (public methods by default).") do
399
+ opts.on("-m", "--methods", "Display methods (public methods by default).") do
325
400
  options[:m] = true
326
401
  end
327
402
 
@@ -329,34 +404,42 @@ Shows local and instance variables by default.
329
404
  options[:M] = true
330
405
  end
331
406
 
332
- opts.on("-P", "--public", "Display public methods (with -m).") do
407
+ opts.on("-P", "--public", "Display public methods (with -m).") do
333
408
  options[:P] = true
334
409
  end
335
410
 
336
- opts.on("-r", "--protected", "Display protected methods (with -m).") do
411
+ opts.on("-r", "--protected", "Display protected methods (with -m).") do
337
412
  options[:r] = true
338
- end
413
+ end
339
414
 
340
- opts.on("-p", "--private", "Display private methods (with -m).") do
415
+ opts.on("-p", "--private", "Display private methods (with -m).") do
341
416
  options[:p] = true
342
417
  end
343
418
 
344
- 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
345
420
  options[:j] = true
346
- end
421
+ end
347
422
 
348
- 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
349
424
  options[:s] = true
350
425
  end
351
-
426
+
352
427
  opts.on("-a", "--all", "Display all types of entries.") do
353
428
  options[:a] = true
354
429
  end
355
430
 
356
- opts.on("-v", "--verbose", "Verbose ouput.") do
431
+ opts.on("-v", "--verbose", "Verbose ouput.") do
357
432
  options[:v] = true
358
433
  end
359
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
+
360
443
  opts.on_tail("-h", "--help", "Show this message.") do
361
444
  output.puts opts
362
445
  options[:h] = true
@@ -374,18 +457,21 @@ Shows local and instance variables by default.
374
457
  :l => true,
375
458
  :i => true,
376
459
  :k => true
377
- }) 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
+
378
464
 
379
465
  # Display public methods by default if -m or -M switch is used.
380
466
  options[:P] = true if (options[:m] || options[:M]) && !(options[:p] || options[:r] || options[:j])
381
-
467
+
382
468
  info = {}
383
469
  target_self = target.eval('self')
384
470
 
385
471
  # ensure we have a real boolean and not a `nil` (important when
386
472
  # interpolating in the string)
387
473
  options[:s] = !!options[:s]
388
-
474
+
389
475
  # Numbers (e.g 0, 1, 2) are for ordering the hash values in Ruby 1.8
390
476
  i = -1
391
477
 
@@ -400,7 +486,7 @@ Shows local and instance variables by default.
400
486
  end, i += 1] if options[:k] || options[:a]
401
487
 
402
488
  info["global variables"] = [Array(target.eval("global_variables")).sort, i += 1] if options[:g] || options[:a]
403
-
489
+
404
490
  info["public methods"] = [Array(target.eval("public_methods(#{options[:s]})")).uniq.sort, i += 1] if (options[:m] && options[:P]) || options[:a]
405
491
 
406
492
  info["protected methods"] = [Array(target.eval("protected_methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:r]) || options[:a]
@@ -408,52 +494,77 @@ Shows local and instance variables by default.
408
494
  info["private methods"] = [Array(target.eval("private_methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:p]) || options[:a]
409
495
 
410
496
  info["just singleton methods"] = [Array(target.eval("methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:j]) || options[:a]
411
-
497
+
412
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])
413
499
 
414
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])
415
501
 
416
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])
417
-
503
+
418
504
  # dealing with 1.8/1.9 compatibility issues :/
419
505
  csuper = options[:s]
420
506
  if Module.method(:constants).arity == 0
421
507
  csuper = nil
422
508
  end
423
-
509
+
424
510
  info["constants"] = [Array(target_self.is_a?(Module) ? target.eval("constants(#{csuper})") :
425
511
  target.eval("self.class.constants(#{csuper})")).uniq.sort, i += 1] if options[:c] || options[:a]
426
512
 
513
+ text = ""
514
+
427
515
  # verbose output?
428
516
  if options[:v]
429
-
430
517
  # verbose
518
+
431
519
  info.sort_by { |k, v| v.last }.each do |k, v|
432
520
  if !v.first.empty?
433
- output.puts "#{k}:\n--"
521
+ text << "#{k}:\n--\n"
522
+ filtered_list = v.first.grep options[:grep]
434
523
  if Pry.color
435
- output.puts CodeRay.scan(Pry.view(v.first), :ruby).term
524
+ text << CodeRay.scan(Pry.view(filtered_list), :ruby).term + "\n"
436
525
  else
437
- output.puts Pry.view(v.first)
526
+ text << Pry.view(filtered_list) + "\n"
438
527
  end
439
- output.puts
528
+ text << "\n\n"
440
529
  end
441
530
  end
442
531
 
532
+ if !options[:f]
533
+ stagger_output(text)
534
+ else
535
+ output.puts text
536
+ end
537
+
443
538
  # plain
444
539
  else
445
540
  list = info.values.sort_by(&:last).map(&:first).inject(&:+)
541
+ list = list.grep(options[:grep]) if list
446
542
  list.uniq! if list
447
543
  if Pry.color
448
- 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)
449
550
  else
450
- output.puts Pry.view(list)
551
+ output.puts text
451
552
  end
452
553
  list
453
554
  end
454
555
  end
455
556
 
456
- command "cat-file", "Show output of file FILE. Type `cat-file --help` for more information." do |*args|
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|
457
568
  options= {}
458
569
  file_name = nil
459
570
  start_line = 0
@@ -461,9 +572,9 @@ Shows local and instance variables by default.
461
572
  file_type = nil
462
573
 
463
574
  OptionParser.new do |opts|
464
- opts.banner = %{Usage: cat-file [OPTIONS] FILE
575
+ opts.banner = %{Usage: cat [OPTIONS] FILE
465
576
  Cat a file. Defaults to displaying whole file. Syntax highlights file if type is recognized.
466
- e.g: cat-file hello.rb
577
+ e.g: cat hello.rb
467
578
  --
468
579
  }
469
580
  opts.on("-l", "--line-numbers", "Show line numbers.") do |line|
@@ -482,11 +593,11 @@ e.g: cat-file hello.rb
482
593
  file_type = type.to_sym
483
594
  end
484
595
 
485
- opts.on("-f", "--flood", "Do not use a pager to view text longer than one screen.") do
596
+ opts.on("-f", "--flood", "Do not use a pager to view text longer than one screen.") do
486
597
  options[:f] = true
487
598
  end
488
599
 
489
- opts.on_tail("-h", "--help", "This message.") do
600
+ opts.on_tail("-h", "--help", "This message.") do
490
601
  output.puts opts
491
602
  options[:h] = true
492
603
  end
@@ -495,7 +606,7 @@ e.g: cat-file hello.rb
495
606
  end
496
607
 
497
608
  next if options[:h]
498
-
609
+
499
610
  if !file_name
500
611
  output.puts "Must provide a file name."
501
612
  next
@@ -516,7 +627,7 @@ e.g: cat-file hello.rb
516
627
  options = {}
517
628
  target = target()
518
629
  file_name = nil
519
-
630
+
520
631
  OptionParser.new do |opts|
521
632
  opts.banner = %{Usage: eval-file [OPTIONS] FILE
522
633
  Eval a Ruby script at top-level or in the specified context. Defaults to top-level.
@@ -528,7 +639,7 @@ e.g: eval-file -c self "hello.rb"
528
639
  target = Pry.binding_for(target.eval(context))
529
640
  end
530
641
 
531
- opts.on_tail("-h", "--help", "This message.") do
642
+ opts.on_tail("-h", "--help", "This message.") do
532
643
  output.puts opts
533
644
  options[:h] = true
534
645
  end
@@ -556,73 +667,57 @@ e.g: eval-file -c self "hello.rb"
556
667
 
557
668
  new_constants = Object.constants - old_constants
558
669
  output.puts "Brought in the following top-level constants: #{new_constants.inspect}" if !new_constants.empty?
559
- end
560
-
561
- command "cat", "Show output of VAR.inspect. Aliases: inspect" do |obj|
562
- if !obj
563
- output.puts "Must provide an object to inspect."
564
- next
565
- end
566
-
567
- output.puts Pry.view(target.eval("#{obj}"))
568
670
  end
569
671
 
570
- alias_command "inspect", "cat", ""
571
-
572
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|
573
673
  if !obj
574
674
  output.puts "Must provide an object."
575
675
  next
576
676
  end
577
-
677
+
578
678
  throw(:breakout, opts[:nesting].level) if obj == ".."
579
679
 
580
- if obj == "/"
680
+ if obj == "/"
581
681
  throw(:breakout, 1) if opts[:nesting].level > 0
582
682
  next
583
- end
683
+ end
584
684
 
585
685
  Pry.start target.eval("#{obj}")
586
686
  end
587
687
 
588
688
  command "show-doc", "Show the comments above METH. Type `show-doc --help` for more info. Aliases: \?" do |*args|
589
- options = {}
590
689
  target = target()
591
- meth_name = nil
592
-
593
- OptionParser.new do |opts|
594
- opts.banner = %{Usage: show-doc [OPTIONS] [METH]
690
+
691
+ opts = Slop.parse!(args) do |opts|
692
+ opts.banner %{Usage: show-doc [OPTIONS] [METH]
595
693
  Show the comments above method METH. Tries instance methods first and then methods by default.
596
694
  e.g show-doc hello_method
597
695
  --
598
696
  }
599
- opts.on("-M", "--instance-methods", "Operate on instance methods.") do
600
- options[:M] = true
601
- end
602
-
603
- opts.on("-m", "--methods", "Operate on methods.") do
604
- options[:m] = true
605
- end
606
-
607
- 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|
608
700
  target = Pry.binding_for(target.eval(context))
609
701
  end
610
-
611
- opts.on("-f", "--flood", "Do not use a pager to view text longer than one screen.") do
612
- options[:f] = true
613
- end
614
-
615
- 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
616
704
  output.puts opts
617
- options[:h] = true
618
705
  end
619
- end.order(args) do |v|
620
- meth_name = v
621
706
  end
622
707
 
623
- next if options[:h]
708
+ next if opts.help?
709
+
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)
718
+ end
624
719
 
625
- if (meth = get_method_object(meth_name, target, options)).nil?
720
+ if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
626
721
  output.puts "Invalid method name: #{meth_name}. Type `show-doc --help` for help"
627
722
  next
628
723
  end
@@ -631,65 +726,55 @@ e.g show-doc hello_method
631
726
  next if !doc
632
727
 
633
728
  next output.puts("No documentation found.") if doc.empty?
634
-
729
+
635
730
  doc = process_comment_markup(doc, code_type)
636
-
731
+
637
732
  output.puts make_header(meth, code_type, doc)
638
733
 
639
- render_output(options[:f], false, doc)
734
+ render_output(opts.flood?, false, doc)
640
735
  doc
641
736
  end
642
737
 
643
738
  alias_command "?", "show-doc", ""
644
739
 
645
740
  command "show-method", "Show the source for METH. Type `show-method --help` for more info. Aliases: $, show-source" do |*args|
646
- options = {}
647
741
  target = target()
648
- meth_name = nil
649
-
650
- OptionParser.new do |opts|
651
- opts.banner = %{Usage: show-method [OPTIONS] [METH]
742
+
743
+ opts = Slop.parse!(args) do |opts|
744
+ opts.banner %{Usage: show-method [OPTIONS] [METH]
652
745
  Show the source for method METH. Tries instance methods first and then methods by default.
653
746
  e.g: show-method hello_method
654
747
  --
655
748
  }
656
- opts.on("-l", "--line-numbers", "Show line numbers.") do |line|
657
- options[:l] = true
658
- end
659
-
660
- opts.on("-M", "--instance-methods", "Operate on instance methods.") do
661
- options[:M] = true
662
- end
663
-
664
- opts.on("-m", "--methods", "Operate on methods.") do
665
- options[:m] = true
666
- end
667
-
668
- opts.on("-f", "--flood", "Do not use a pager to view text longer than one screen.") do
669
- options[:f] = true
670
- end
671
-
672
- 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|
673
754
  target = Pry.binding_for(target.eval(context))
674
755
  end
675
-
676
- opts.on_tail("-h", "--help", "This message.") do
756
+ opts.on :h, :help, "This message." do
677
757
  output.puts opts
678
- options[:h] = true
679
758
  end
680
- end.order(args) do |v|
681
- meth_name = v
682
759
  end
683
760
 
684
- next if options[:h]
761
+ next if opts.help?
685
762
 
686
- meth_name = meth_name_from_binding(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
687
772
 
688
- if (meth = get_method_object(meth_name, target, options)).nil?
773
+ if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
689
774
  output.puts "Invalid method name: #{meth_name}. Type `show-method --help` for help"
690
775
  next
691
776
  end
692
-
777
+
693
778
  code, code_type = code_and_code_type_for(meth)
694
779
  next if !code
695
780
 
@@ -699,11 +784,11 @@ e.g: show-method hello_method
699
784
  end
700
785
 
701
786
  start_line = false
702
- if options[:l]
787
+ if opts.l?
703
788
  start_line = meth.source_location ? meth.source_location.last : 1
704
789
  end
705
-
706
- render_output(options[:f], start_line, code)
790
+
791
+ render_output(opts.flood?, start_line, code)
707
792
  code
708
793
  end
709
794
 
@@ -714,10 +799,10 @@ e.g: show-method hello_method
714
799
  options = {}
715
800
  target = target()
716
801
  command_name = nil
717
-
802
+
718
803
  OptionParser.new do |opts|
719
804
  opts.banner = %{Usage: show-command [OPTIONS] [CMD]
720
- Show the source for command CMD.
805
+ Show the source for command CMD.
721
806
  e.g: show-command show-method
722
807
  --
723
808
  }
@@ -725,11 +810,11 @@ e.g: show-command show-method
725
810
  options[:l] = true
726
811
  end
727
812
 
728
- opts.on("-f", "--flood", "Do not use a pager to view text longer than one screen.") do
813
+ opts.on("-f", "--flood", "Do not use a pager to view text longer than one screen.") do
729
814
  options[:f] = true
730
815
  end
731
816
 
732
- opts.on_tail("-h", "--help", "This message.") do
817
+ opts.on_tail("-h", "--help", "This message.") do
733
818
  output.puts opts
734
819
  options[:h] = true
735
820
  end
@@ -743,7 +828,7 @@ e.g: show-command show-method
743
828
  output.puts "You must provide a command name."
744
829
  next
745
830
  end
746
-
831
+
747
832
  if commands[command_name]
748
833
  meth = commands[command_name][:action]
749
834
 
@@ -764,7 +849,7 @@ e.g: show-command show-method
764
849
  output.puts "No such command: #{command_name}."
765
850
  end
766
851
  end
767
-
852
+
768
853
  command "jump-to", "Jump to a Pry session further up the stack, exiting all sessions below." do |break_level|
769
854
  break_level = break_level.to_i
770
855
  nesting = opts[:nesting]
@@ -780,7 +865,7 @@ e.g: show-command show-method
780
865
  end
781
866
  end
782
867
 
783
- command "exit", "End the current Pry session. Accepts optional return value. Aliases: quit, back" do
868
+ command "exit", "End the current Pry session. Accepts optional return value. Aliases: quit, back" do
784
869
  str = remove_first_word(opts[:val])
785
870
  throw(:breakout, [opts[:nesting].level, target.eval(str)])
786
871
  end
@@ -825,7 +910,7 @@ Wait for the early owl.
825
910
  output.puts text
826
911
  text
827
912
  end
828
-
913
+
829
914
  command "cohen-poem", "" do
830
915
  text = %{
831
916
  --
@@ -843,7 +928,7 @@ and so small between the thin pines
843
928
  on these enormous landscapes,
844
929
  that if you turn your head
845
930
  they are lost for hours.
846
- -- Leonard Cohen
931
+ -- Leonard Cohen
847
932
  }
848
933
  output.puts text
849
934
  text