pry 0.9.7.4-i386-mswin32 → 0.9.8-i386-mswin32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/.gitignore +2 -3
  2. data/CHANGELOG +43 -0
  3. data/README.markdown +3 -1
  4. data/Rakefile +51 -32
  5. data/bin/pry +2 -80
  6. data/lib/pry.rb +33 -26
  7. data/lib/pry/cli.rb +152 -0
  8. data/lib/pry/code.rb +351 -0
  9. data/lib/pry/command.rb +422 -0
  10. data/lib/pry/command_set.rb +259 -129
  11. data/lib/pry/commands.rb +0 -1
  12. data/lib/pry/config.rb +43 -9
  13. data/lib/pry/default_commands/context.rb +109 -92
  14. data/lib/pry/default_commands/documentation.rb +174 -63
  15. data/lib/pry/default_commands/easter_eggs.rb +26 -2
  16. data/lib/pry/default_commands/gems.rb +65 -37
  17. data/lib/pry/default_commands/input.rb +175 -243
  18. data/lib/pry/default_commands/introspection.rb +173 -112
  19. data/lib/pry/default_commands/ls.rb +96 -114
  20. data/lib/pry/default_commands/shell.rb +175 -70
  21. data/lib/pry/helpers/base_helpers.rb +7 -2
  22. data/lib/pry/helpers/command_helpers.rb +71 -77
  23. data/lib/pry/helpers/options_helpers.rb +10 -41
  24. data/lib/pry/helpers/text.rb +24 -4
  25. data/lib/pry/history.rb +55 -17
  26. data/lib/pry/history_array.rb +2 -0
  27. data/lib/pry/hooks.rb +252 -0
  28. data/lib/pry/indent.rb +9 -5
  29. data/lib/pry/method.rb +149 -50
  30. data/lib/pry/plugins.rb +12 -4
  31. data/lib/pry/pry_class.rb +69 -26
  32. data/lib/pry/pry_instance.rb +187 -115
  33. data/lib/pry/version.rb +1 -1
  34. data/lib/pry/wrapped_module.rb +73 -0
  35. data/man/pry.1 +195 -0
  36. data/man/pry.1.html +204 -0
  37. data/man/pry.1.ronn +141 -0
  38. data/pry.gemspec +29 -32
  39. data/test/helper.rb +32 -36
  40. data/test/test_cli.rb +78 -0
  41. data/test/test_code.rb +201 -0
  42. data/test/test_command.rb +327 -0
  43. data/test/test_command_integration.rb +512 -0
  44. data/test/test_command_set.rb +338 -12
  45. data/test/test_completion.rb +1 -1
  46. data/test/test_default_commands.rb +1 -2
  47. data/test/test_default_commands/test_context.rb +27 -5
  48. data/test/test_default_commands/test_documentation.rb +20 -8
  49. data/test/test_default_commands/test_input.rb +84 -45
  50. data/test/test_default_commands/test_introspection.rb +74 -17
  51. data/test/test_default_commands/test_ls.rb +9 -36
  52. data/test/test_default_commands/test_shell.rb +240 -13
  53. data/test/test_hooks.rb +490 -0
  54. data/test/test_indent.rb +2 -0
  55. data/test/test_method.rb +60 -0
  56. data/test/test_pry.rb +29 -904
  57. data/test/test_pry_defaults.rb +380 -0
  58. data/test/test_pry_history.rb +24 -24
  59. data/test/test_syntax_checking.rb +63 -0
  60. data/test/test_wrapped_module.rb +71 -0
  61. metadata +50 -39
  62. data/lib/pry/command_context.rb +0 -53
  63. data/lib/pry/command_processor.rb +0 -181
  64. data/lib/pry/extended_commands/user_command_api.rb +0 -65
  65. data/test/test_command_processor.rb +0 -176
@@ -5,40 +5,58 @@ class Pry
5
5
 
6
6
  Introspection = Pry::CommandSet.new do
7
7
 
8
- command "show-method", "Show the source for METH. Type `show-method --help` for more info. Aliases: $, show-source", :shellwords => false do |*args|
9
- opts, meth = parse_options!(args, :method_object) do |opt|
10
- opt.banner unindent <<-USAGE
11
- Usage: show-method [OPTIONS] [METH]
12
- Show the source for method METH. Tries instance methods first and then methods by default.
13
- e.g: show-method hello_method
14
- USAGE
8
+ create_command "show-method" do
9
+ description "Show the source for METH. Type `show-method --help` for more info. Aliases: $, show-source"
10
+
11
+ banner <<-BANNER
12
+ Usage: show-method [OPTIONS] [METH]
13
+ Aliases: $, show-source
14
+
15
+ Show the source for method METH. Tries instance methods first and then methods by default.
15
16
 
17
+ e.g: `show-method hello_method`
18
+ e.g: `show-method -m hello_method`
19
+ e.g: `show-method Pry#rep`
20
+
21
+ https://github.com/pry/pry/wiki/Source-browsing#wiki-Show_method
22
+ BANNER
23
+
24
+ command_options(
25
+ :shellwords => false
26
+ )
27
+
28
+ def options(opt)
29
+ method_options(opt)
16
30
  opt.on :l, "line-numbers", "Show line numbers."
17
31
  opt.on :b, "base-one", "Show line numbers but start numbering at 1 (useful for `amend-line` and `play` commands)."
18
32
  opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
19
33
  end
20
34
 
21
- raise CommandError, "Could not find method source" unless meth.source
35
+ def process
36
+ raise CommandError, "Could not find method source" unless method_object.source
37
+
38
+ output.puts make_header(method_object)
39
+ output.puts "#{text.bold("Owner:")} #{method_object.owner || "N/A"}"
40
+ output.puts "#{text.bold("Visibility:")} #{method_object.visibility}"
41
+ output.puts
22
42
 
23
- output.puts make_header(meth)
24
- output.puts "#{text.bold("Owner:")} #{meth.owner || "N/A"}"
25
- output.puts "#{text.bold("Visibility:")} #{meth.visibility}"
26
- output.puts
43
+ code = Code.from_method(method_object, start_line).
44
+ with_line_numbers(use_line_numbers?)
27
45
 
28
- if Pry.color
29
- code = CodeRay.scan(meth.source, meth.source_type).term
30
- else
31
- code = meth.source
46
+ render_output(code, opts)
32
47
  end
33
48
 
34
- start_line = false
35
- if opts.b?
36
- start_line = 1
37
- elsif opts.l?
38
- start_line = meth.source_line || 1
49
+ def use_line_numbers?
50
+ opts.present?(:b) || opts.present?(:l)
39
51
  end
40
52
 
41
- render_output(opts.flood?, start_line, code)
53
+ def start_line
54
+ if opts.present?(:'base-one')
55
+ 1
56
+ else
57
+ method_object.source_line || 1
58
+ end
59
+ end
42
60
  end
43
61
 
44
62
  alias_command "show-source", "show-method"
@@ -57,11 +75,11 @@ class Pry
57
75
  opt.on :l, "line-numbers", "Show line numbers."
58
76
  opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
59
77
  opt.on :h, :help, "This message." do
60
- output.puts opt
78
+ output.puts opt.help
61
79
  end
62
80
  end
63
81
 
64
- next if opts.help?
82
+ next if opts.present?(:help)
65
83
 
66
84
  command_name = args.shift
67
85
  if !command_name
@@ -77,68 +95,75 @@ class Pry
77
95
  output.puts make_header(block)
78
96
  output.puts
79
97
 
80
- if Pry.color
81
- code = CodeRay.scan(block.source, :ruby).term
82
- else
83
- code = block.source
84
- end
85
-
86
- start_line = false
87
- if opts.l?
88
- start_line = block.source_line || 1
89
- end
98
+ code = Code.from_method(block).with_line_numbers(opts.present?(:'line-numbers'))
90
99
 
91
- render_output(opts.flood?, opts.l? ? block.source_line : false, code)
92
- code
100
+ render_output(code, opts)
93
101
  else
94
102
  raise CommandError, "No such command: #{command_name}."
95
103
  end
96
104
  end
97
105
 
98
- command "edit", "Invoke the default editor on a file. Type `edit --help` for more info" do |*args|
99
- opts = Slop.parse!(args) do |opt|
100
- opt.banner unindent <<-USAGE
101
- Usage: edit [--no-reload|--reload] [--line LINE] [--temp|--ex|FILE[:LINE]|--in N]
102
- Open a text editor. When no FILE is given, edits the pry input buffer.
103
- Ensure #{text.bold("Pry.config.editor")} is set to your editor of choice.
104
- e.g: edit sample.rb
105
- USAGE
106
+ create_command "edit" do
107
+ description "Invoke the default editor on a file. Type `edit --help` for more info"
108
+
109
+ banner <<-BANNER
110
+ Usage: edit [--no-reload|--reload] [--line LINE] [--temp|--ex|FILE[:LINE]|--in N]
111
+
112
+ Open a text editor. When no FILE is given, edits the pry input buffer.
113
+ Ensure Pry.config.editor is set to your editor of choice.
114
+
115
+ e.g: `edit sample.rb`
116
+ e.g: `edit sample.rb --line 105`
117
+ e.g: `edit --ex`
118
+
119
+ https://github.com/pry/pry/wiki/Editor-integration#wiki-Edit_command
120
+ BANNER
106
121
 
122
+ def options(opt)
107
123
  opt.on :e, :ex, "Open the file that raised the most recent exception (_ex_.file)", :optional => true, :as => Integer
108
124
  opt.on :i, :in, "Open a temporary file containing the Nth line of _in_. N may be a range.", :optional => true, :as => Range, :default => -1..-1
109
125
  opt.on :t, :temp, "Open an empty temporary file"
110
126
  opt.on :l, :line, "Jump to this line in the opened file", true, :as => Integer
111
127
  opt.on :n, :"no-reload", "Don't automatically reload the edited code"
112
128
  opt.on :r, :reload, "Reload the edited code immediately (default for ruby files)"
113
- opt.on :h, :help, "This message." do
114
- output.puts opt
129
+ end
130
+
131
+ def process
132
+ if [opts.present?(:ex), opts.present?(:temp), opts.present?(:in), !args.empty?].count(true) > 1
133
+ raise CommandError, "Only one of --ex, --temp, --in and FILE may be specified."
134
+ end
135
+
136
+ if !opts.present?(:ex) && args.empty?
137
+ # edit of local code, eval'd within pry.
138
+ process_local_edit
139
+ else
140
+ # edit of remote code, eval'd at top-level
141
+ process_remote_edit
115
142
  end
116
143
  end
117
- next if opts.h?
118
144
 
119
- if [opts.ex?, opts.t?, opts.i?, !args.empty?].count(true) > 1
120
- raise CommandError, "Only one of --ex, --temp, --in and FILE may be specified."
145
+ def process_i
146
+ case opts[:i]
147
+ when Range
148
+ (_pry_.input_array[opts[:i]] || []).join
149
+ when Fixnum
150
+ _pry_.input_array[opts[:i]] || ""
151
+ else
152
+ return output.puts "Not a valid range: #{opts[:i]}"
153
+ end
121
154
  end
122
155
 
123
- # edit of local code, eval'd within pry.
124
- if !opts.ex? && args.empty?
125
-
126
- content = if opts.t?
127
- ""
128
- elsif opts.i?
129
- case opts[:i]
130
- when Range
131
- (_pry_.input_array[opts[:i]] || []).join
132
- when Fixnum
133
- _pry_.input_array[opts[:i]] || ""
134
- else
135
- next output.puts "Not a valid range: #{opts[:i]}"
136
- end
137
- elsif eval_string.strip != ""
138
- eval_string
139
- else
140
- _pry_.input_array.reverse_each.find{ |x| x && x.strip != "" } || ""
141
- end
156
+ def process_local_edit
157
+ content = case
158
+ when opts.present?(:temp)
159
+ ""
160
+ when opts.present?(:in)
161
+ process_i
162
+ when eval_string.strip != ""
163
+ eval_string
164
+ else
165
+ _pry_.input_array.reverse_each.find{ |x| x && x.strip != "" } || ""
166
+ end
142
167
 
143
168
  line = content.lines.count
144
169
 
@@ -146,16 +171,16 @@ class Pry
146
171
  f.puts(content)
147
172
  f.flush
148
173
  invoke_editor(f.path, line)
149
- if !opts.n?
174
+ if !opts.present?(:'no-reload')
150
175
  silence_warnings do
151
176
  eval_string.replace(File.read(f.path))
152
177
  end
153
178
  end
154
179
  end
180
+ end
155
181
 
156
- # edit of remote code, eval'd at top-level
157
- else
158
- if opts.ex?
182
+ def process_remote_edit
183
+ if opts.present?(:ex)
159
184
  if _pry_.last_exception.nil?
160
185
  raise CommandError, "No exception found."
161
186
  end
@@ -186,12 +211,12 @@ class Pry
186
211
  line = file_name.sub!(/:(\d+)$/, "") ? $1.to_i : 1
187
212
  end
188
213
 
189
- line = opts[:l].to_i if opts.l?
214
+ line = opts[:l].to_i if opts.present?(:line)
190
215
 
191
216
  invoke_editor(file_name, line)
192
217
  set_file_and_dir_locals(file_name)
193
218
 
194
- if opts.r? || ((opts.ex? || file_name.end_with?(".rb")) && !opts.n?)
219
+ if opts.present?(:reload) || ((opts.present?(:ex) || file_name.end_with?(".rb")) && !opts.present?(:'no-reload'))
195
220
  silence_warnings do
196
221
  TOPLEVEL_BINDING.eval(File.read(file_name), file_name)
197
222
  end
@@ -199,33 +224,60 @@ class Pry
199
224
  end
200
225
  end
201
226
 
202
- command "edit-method", "Edit a method. Type `edit-method --help` for more info.", :shellwords => false do |*args|
203
- target = target()
227
+ create_command "edit-method" do
228
+ description "Edit a method. Type `edit-method --help` for more info."
204
229
 
205
- opts, meth = parse_options!(args, :method_object) do |opt|
206
- opt.banner unindent <<-USAGE
207
- Usage: edit-method [OPTIONS] [METH]
208
- Edit the method METH in an editor.
209
- Ensure #{text.bold("Pry.config.editor")} is set to your editor of choice.
210
- e.g: edit-method hello_method
211
- USAGE
230
+ banner <<-BANNER
231
+ Usage: edit-method [OPTIONS] [METH]
232
+
233
+ Edit the method METH in an editor.
234
+ Ensure Pry.config.editor is set to your editor of choice.
212
235
 
236
+ e.g: `edit-method hello_method`
237
+ e.g: `edit-method Pry#rep`
238
+ e.g: `edit-method`
239
+
240
+ https://github.com/pry/pry/wiki/Editor-integration#wiki-Edit_method
241
+ BANNER
242
+
243
+ command_options :shellwords => false
244
+
245
+ def options(opt)
246
+ method_options(opt)
213
247
  opt.on :n, "no-reload", "Do not automatically reload the method's file after editing."
214
248
  opt.on "no-jump", "Do not fast forward editor to first line of method."
215
249
  opt.on :p, :patch, "Instead of editing the method's file, try to edit in a tempfile and apply as a monkey patch."
216
- opt.on :h, :help, "This message." do
217
- output.puts opt
218
- end
219
250
  end
220
251
 
221
- if !Pry.config.editor
222
- raise CommandError, "No editor set!\nEnsure that #{text.bold("Pry.config.editor")} is set to your editor of choice."
252
+ def process
253
+ if !Pry.config.editor
254
+ raise CommandError, "No editor set!\nEnsure that #{text.bold("Pry.config.editor")} is set to your editor of choice."
255
+ end
256
+
257
+ begin
258
+ @method = method_object
259
+ rescue NonMethodContextError => err
260
+ end
261
+
262
+ if opts.present?(:patch) || (@method && @method.dynamically_defined?)
263
+ if err
264
+ raise err # can't patch a non-method
265
+ end
266
+
267
+ process_patch
268
+ else
269
+ if err && !File.exist?(target.eval('__FILE__'))
270
+ raise err # can't edit a non-file
271
+ end
272
+
273
+ process_file
274
+ end
223
275
  end
224
276
 
225
- if opts.p? || meth.dynamically_defined?
226
- lines = meth.source.lines.to_a
277
+ def process_patch
278
+ lines = @method.source.lines.to_a
227
279
 
228
- if ((original_name = meth.original_name) &&
280
+ if ((original_name = @method.original_name) &&
229
281
  lines[0] =~ /^def (?:.*?\.)?#{original_name}(?=[\(\s;]|$)/)
230
282
  lines[0] = "def #{original_name}#{$'}"
231
283
  else
@@ -237,40 +289,49 @@ class Pry
237
289
  f.flush
238
290
  invoke_editor(f.path, 0)
239
291
 
240
- if meth.alias?
241
- with_method_transaction(original_name, meth.owner) do
242
- Pry.new(:input => StringIO.new(File.read(f.path))).rep(meth.owner)
243
- Pry.binding_for(meth.owner).eval("alias #{meth.name} #{original_name}")
292
+ if @method.alias?
293
+ with_method_transaction(original_name, @method.owner) do
294
+ Pry.new(:input => StringIO.new(File.read(f.path))).rep(@method.owner)
295
+ Pry.binding_for(@method.owner).eval("alias #{@method.name} #{original_name}")
244
296
  end
245
297
  else
246
- Pry.new(:input => StringIO.new(File.read(f.path))).rep(meth.owner)
298
+ Pry.new(:input => StringIO.new(File.read(f.path))).rep(@method.owner)
247
299
  end
248
300
  end
249
- next
250
301
  end
251
302
 
252
- if meth.source_type == :c
253
- raise CommandError, "Can't edit a C method."
254
- else
255
- file, line = meth.source_file, meth.source_line
303
+ def process_file
304
+ file, line = extract_file_and_line
256
305
 
257
306
  invoke_editor(file, opts["no-jump"] ? 0 : line)
258
307
  silence_warnings do
259
- load file if !opts.n? && !Pry.config.disable_auto_reload
308
+ load file unless opts.present?(:'no-jump') || Pry.config.disable_auto_reload
260
309
  end
261
310
  end
262
- end
263
311
 
264
- helpers do
265
- def with_method_transaction(meth_name, target=TOPLEVEL_BINDING)
266
- target = Pry.binding_for(target)
267
- temp_name = "__pry_#{meth_name}__"
312
+ protected
313
+ def extract_file_and_line
314
+ if @method
315
+ if @method.source_type == :c
316
+ raise CommandError, "Can't edit a C method."
317
+ else
318
+ [@method.source_file, @method.source_line]
319
+ end
320
+ else
321
+ [target.eval('__FILE__'), target.eval('__LINE__')]
322
+ end
323
+ end
324
+
325
+ def with_method_transaction(meth_name, target=TOPLEVEL_BINDING)
326
+ target = Pry.binding_for(target)
327
+ temp_name = "__pry_#{meth_name}__"
268
328
 
269
- target.eval("alias #{temp_name} #{meth_name}")
270
- yield
271
- target.eval("alias #{meth_name} #{temp_name}")
272
- target.eval("undef #{temp_name}")
273
- end
329
+ target.eval("alias #{temp_name} #{meth_name}")
330
+ yield
331
+ target.eval("alias #{meth_name} #{temp_name}")
332
+ ensure
333
+ target.eval("undef #{temp_name}") rescue nil
334
+ end
274
335
  end
275
336
  end
276
337
  end
@@ -3,7 +3,94 @@ class Pry
3
3
 
4
4
  Ls = Pry::CommandSet.new do
5
5
 
6
- helpers do
6
+ create_command "ls","Show the list of vars and methods in the current scope. Type `ls --help` for more info.",
7
+ :shellwords => false, :interpolate => false do
8
+
9
+ def options(opt)
10
+ opt.banner unindent <<-USAGE
11
+ Usage: ls [-m|-M|-p|-pM] [-q|-v] [-c|-i] [Object]
12
+ ls [-g] [-l]
13
+
14
+ ls shows you which methods, constants and variables are accessible to Pry. By default it shows you the local variables defined in the current shell, and any public methods or instance variables defined on the current object.
15
+
16
+ The colours used are configurable using Pry.config.ls.*_color, and the separator is Pry.config.ls.separator.
17
+
18
+ Pry.config.ls.ceiling is used to hide methods defined higher up in the inheritance chain, this is by default set to [Object, Module, Class] so that methods defined on all Objects are omitted. The -v flag can be used to ignore this setting and show all methods, while the -q can be used to set the ceiling much lower and show only methods defined on the object or its direct class.
19
+ USAGE
20
+
21
+ opt.on :m, "methods", "Show public methods defined on the Object (default)"
22
+ opt.on :M, "instance-methods", "Show methods defined in a Module or Class"
23
+
24
+ opt.on :p, "ppp", "Show public, protected (in yellow) and private (in green) methods"
25
+ opt.on :q, "quiet", "Show only methods defined on object.singleton_class and object.class"
26
+ opt.on :v, "verbose", "Show methods and constants on all super-classes (ignores Pry.config.ls.ceiling)"
27
+
28
+ opt.on :g, "globals", "Show global variables, including those builtin to Ruby (in cyan)"
29
+ opt.on :l, "locals", "Show locals, including those provided by Pry (in red)"
30
+
31
+ opt.on :c, "constants", "Show constants, highlighting classes (in blue), and exceptions (in purple)"
32
+
33
+ opt.on :i, "ivars", "Show instance variables (in blue) and class variables (in bright blue)"
34
+
35
+ opt.on :G, "grep", "Filter output by regular expression", :optional => false
36
+ end
37
+
38
+ def process
39
+ obj = args.empty? ? target_self : target.eval(args.join(" "))
40
+
41
+ # exclude -q, -v and --grep because they don't specify what the user wants to see.
42
+ has_opts = (opts.present?(:methods) || opts.present?(:'instance-methods') || opts.present?(:ppp) ||
43
+ opts.present?(:globals) || opts.present?(:locals) || opts.present?(:constants) ||
44
+ opts.present?(:ivars))
45
+
46
+ show_methods = opts.present?(:methods) || opts.present?(:'instance-methods') || opts.present?(:ppp) || !has_opts
47
+ show_constants = opts.present?(:constants) || (!has_opts && Module === obj)
48
+ show_ivars = opts.present?(:ivars) || !has_opts
49
+ show_locals = opts.present?(:locals) || (!has_opts && args.empty?)
50
+
51
+ grep_regex, grep = [Regexp.new(opts[:G] || "."), lambda{ |x| x.grep(grep_regex) }]
52
+
53
+ raise Pry::CommandError, "-l does not make sense with a specified Object" if opts.present?(:locals) && !args.empty?
54
+ raise Pry::CommandError, "-g does not make sense with a specified Object" if opts.present?(:globals) && !args.empty?
55
+ raise Pry::CommandError, "-q does not make sense with -v" if opts.present?(:quiet) && opts.present?(:verbose)
56
+ raise Pry::CommandError, "-M only makes sense with a Module or a Class" if opts.present?(:'instance-methods') && !(Module === obj)
57
+ raise Pry::CommandError, "-c only makes sense with a Module or a Class" if opts.present?(:constants) && !args.empty? && !(Module === obj)
58
+
59
+
60
+ if opts.present?(:globals)
61
+ output_section("global variables", grep[format_globals(target.eval("global_variables"))])
62
+ end
63
+
64
+ if show_constants
65
+ mod = Module === obj ? obj : Object
66
+ constants = mod.constants
67
+ constants -= (mod.ancestors - [mod]).map(&:constants).flatten unless opts.present?(:verbose)
68
+ output_section("constants", grep[format_constants(mod, constants)])
69
+ end
70
+
71
+ if show_methods
72
+ # methods is a hash {Module/Class => [Pry::Methods]}
73
+ methods = all_methods(obj).select{ |method| opts.present?(:ppp) || method.visibility == :public }.group_by(&:owner)
74
+
75
+ # reverse the resolution order so that the most useful information appears right by the prompt
76
+ resolution_order(obj).take_while(&below_ceiling(obj)).reverse.each do |klass|
77
+ methods_here = format_methods((methods[klass] || []).select{ |m| m.name =~ grep_regex })
78
+ output_section "#{Pry::WrappedModule.new(klass).method_prefix}methods", methods_here
79
+ end
80
+ end
81
+
82
+ if show_ivars
83
+ klass = (Module === obj ? obj : obj.class)
84
+ output_section("instance variables", format_variables(:instance_var, grep[obj.__send__(:instance_variables)]))
85
+ output_section("class variables", format_variables(:class_var, grep[klass.__send__(:class_variables)]))
86
+ end
87
+
88
+ if show_locals
89
+ output_section("locals", format_locals(grep[target.eval("local_variables")]))
90
+ end
91
+ end
92
+
93
+ private
7
94
 
8
95
  # http://ruby.runpaint.org/globals, and running "puts global_variables.inspect".
9
96
  BUILTIN_GLOBALS = %w($" $$ $* $, $-0 $-F $-I $-K $-W $-a $-d $-i $-l $-p $-v $-w $. $/ $\\
@@ -20,37 +107,20 @@ class Pry
20
107
  $LAST_PAREN_MATCH $LAST_READ_LINE $MATCH $POSTMATCH $PREMATCH)
21
108
 
22
109
  # Get all the methods that we'll want to output
23
- def all_methods(obj, opts)
24
- opts.M? ? Pry::Method.all_from_class(obj) : Pry::Method.all_from_obj(obj)
110
+ def all_methods(obj)
111
+ opts.present?(:'instance-methods') ? Pry::Method.all_from_class(obj) : Pry::Method.all_from_obj(obj)
25
112
  end
26
113
 
27
- def resolution_order(obj, opts)
28
- opts.M? ? Pry::Method.instance_resolution_order(obj) : Pry::Method.resolution_order(obj)
29
- end
30
-
31
- # Get the name of the klass for pretty display in the title column of ls -m
32
- # as there can only ever be one singleton class of a non-class, we just call
33
- # that "self".
34
- def class_name(klass)
35
- if klass == klass.ancestors.first
36
- (klass.name || "") == "" ? klass.to_s : klass.name
37
- elsif klass.ancestors.include?(Module)
38
- begin
39
- "#{class_name(ObjectSpace.each_object(klass).detect{ |x| class << x; self; end == klass })}.self"
40
- rescue # ObjectSpace is not enabled by default in jruby
41
- klass.to_s.sub(/#<Class:(.*)>/, '\1.self')
42
- end
43
- else
44
- "self"
45
- end
114
+ def resolution_order(obj)
115
+ opts.present?(:'instance-methods') ? Pry::Method.instance_resolution_order(obj) : Pry::Method.resolution_order(obj)
46
116
  end
47
117
 
48
118
  # Get a lambda that can be used with .take_while to prevent over-eager
49
119
  # traversal of the Object's ancestry graph.
50
- def below_ceiling(obj, opts)
51
- ceiling = if opts.q?
52
- [opts.M? ? obj.ancestors[1] : obj.class.ancestors[1]] + Pry.config.ls.ceiling
53
- elsif opts.v?
120
+ def below_ceiling(obj)
121
+ ceiling = if opts.present?(:quiet)
122
+ [opts.present?(:'instance-methods') ? obj.ancestors[1] : obj.class.ancestors[1]] + Pry.config.ls.ceiling
123
+ elsif opts.present?(:verbose)
54
124
  []
55
125
  else
56
126
  Pry.config.ls.ceiling.dup
@@ -125,94 +195,6 @@ class Pry
125
195
  text.send(Pry.config.ls.send(:"#{type}_color"), str)
126
196
  end
127
197
  end
128
-
129
- command "ls", "Show the list of vars and methods in the current scope. Type `ls --help` for more info.",
130
- :shellwords => false, :interpolate => false do |*args|
131
-
132
- opts = Slop.parse!(args, :strict => true) do |opt|
133
- opt.banner unindent <<-USAGE
134
- Usage: ls [-m|-M|-p|-pM] [-q|-v] [-c|-i] [Object]
135
- ls [-g] [-l]
136
-
137
- ls shows you which methods, constants and variables are accessible to Pry. By default it shows you the local variables defined in the current shell, and any public methods or instance variables defined on the current object.
138
-
139
- The colours used are configurable using Pry.config.ls.*_color, and the separator is Pry.config.ls.separator.
140
-
141
- Pry.config.ls.ceiling is used to hide methods defined higher up in the inheritance chain, this is by default set to [Object, Module, Class] so that methods defined on all Objects are omitted. The -v flag can be used to ignore this setting and show all methods, while the -q can be used to set the ceiling much lower and show only methods defined on the object or its direct class.
142
- USAGE
143
-
144
- opt.on :m, "methods", "Show public methods defined on the Object (default)"
145
- opt.on :M, "module", "Show methods defined in a Module or Class"
146
-
147
- opt.on :p, "ppp", "Show public, protected (in yellow) and private (in green) methods"
148
- opt.on :q, "quiet", "Show only methods defined on object.singleton_class and object.class"
149
- opt.on :v, "verbose", "Show methods and constants on all super-classes (ignores Pry.config.ls.ceiling)"
150
-
151
- opt.on :g, "globals", "Show global variables, including those builtin to Ruby (in cyan)"
152
- opt.on :l, "locals", "Show locals, including those provided by Pry (in red)"
153
-
154
- opt.on :c, "constants", "Show constants, highlighting classes (in blue), and exceptions (in purple)"
155
-
156
- opt.on :i, "ivars", "Show instance variables (in blue) and class variables (in bright blue)"
157
-
158
- opt.on :G, "grep", "Filter output by regular expression", :optional => false
159
-
160
- opt.on :h, "help", "Show help"
161
- end
162
-
163
- next output.puts(opts) if opts.h?
164
-
165
- obj = args.empty? ? target_self : target.eval(args.join(" "))
166
-
167
- # exclude -q, -v and --grep because they don't specify what the user wants to see.
168
- has_opts = (opts.m? || opts.M? || opts.p? || opts.g? || opts.l? || opts.c? || opts.i?)
169
-
170
- show_methods = opts.m? || opts.M? || opts.p? || !has_opts
171
- show_constants = opts.c? || (!has_opts && Module === obj)
172
- show_ivars = opts.i? || !has_opts
173
- show_locals = opts.l? || (!has_opts && args.empty?)
174
-
175
- grep_regex, grep = [Regexp.new(opts[:G] || "."), lambda{ |x| x.grep(grep_regex) }]
176
-
177
- raise Pry::CommandError, "-l does not make sense with a specified Object" if opts.l? && !args.empty?
178
- raise Pry::CommandError, "-g does not make sense with a specified Object" if opts.g? && !args.empty?
179
- raise Pry::CommandError, "-q does not make sense with -v" if opts.q? && opts.v?
180
- raise Pry::CommandError, "-M only makes sense with a Module or a Class" if opts.M? && !(Module === obj)
181
- raise Pry::CommandError, "-c only makes sense with a Module or a Class" if opts.c? && !args.empty? && !(Module === obj)
182
-
183
-
184
- if opts.g?
185
- output_section("global variables", grep[format_globals(target.eval("global_variables"))])
186
- end
187
-
188
- if show_constants
189
- mod = Module === obj ? obj : Object
190
- constants = mod.constants
191
- constants -= (mod.ancestors - [mod]).map(&:constants).flatten unless opts.v?
192
- output_section("constants", grep[format_constants(mod, constants)])
193
- end
194
-
195
- if show_methods
196
- # methods is a hash {Module/Class => [Pry::Methods]}
197
- methods = all_methods(obj, opts).select{ |method| opts.p? || method.visibility == :public }.group_by(&:owner)
198
-
199
- # reverse the resolution order so that the most useful information appears right by the prompt
200
- resolution_order(obj, opts).take_while(&below_ceiling(obj, opts)).reverse.each do |klass|
201
- methods_here = format_methods((methods[klass] || []).select{ |m| m.name =~ grep_regex })
202
- output_section "#{class_name(klass)} methods", methods_here
203
- end
204
- end
205
-
206
- if show_ivars
207
- klass = (Module === obj ? obj : obj.class)
208
- output_section("instance variables", format_variables(:instance_var, grep[obj.__send__(:instance_variables)]))
209
- output_section("class variables", format_variables(:class_var, grep[klass.__send__(:class_variables)]))
210
- end
211
-
212
- if show_locals
213
- output_section("locals", format_locals(grep[target.eval("local_variables")]))
214
- end
215
- end
216
198
  end
217
199
  end
218
200
  end