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
@@ -8,41 +8,6 @@ class Pry
8
8
  # This class is used to create sets of commands. Commands can be imported from
9
9
  # different sets, aliased, removed, etc.
10
10
  class CommandSet
11
- class Command < Struct.new(:name, :description, :options, :block)
12
-
13
- def call(context, *args)
14
- context.command_name = options[:listing]
15
-
16
- if stub_block = options[:stub_info]
17
- context.instance_eval(&stub_block)
18
- else
19
- ret = context.instance_exec(*correct_arg_arity(block.arity, args), &block)
20
- if options[:keep_retval]
21
- ret
22
- else
23
- Pry::CommandContext::VOID_VALUE
24
- end
25
- end
26
- end
27
-
28
- private
29
- def correct_arg_arity(arity, args)
30
- case arity <=> 0
31
- when -1
32
- args
33
- when 0
34
- []
35
- when 1
36
- # another jruby hack
37
- if Pry::Helpers::BaseHelpers.jruby?
38
- args[0..(arity - 1)]
39
- else
40
- args.values_at 0..(arity - 1)
41
- end
42
- end
43
- end
44
- end
45
-
46
11
  include Enumerable
47
12
  include Pry::Helpers::BaseHelpers
48
13
 
@@ -116,30 +81,74 @@ class Pry
116
81
  # # hello john, nice number: 10
117
82
  # # pry(main)> help number
118
83
  # # number-N regex command
119
- def command(name, description="No description.", options={}, &block)
84
+ def block_command(name, description="No description.", options={}, &block)
85
+ description, options = ["No description.", description] if description.is_a?(Hash)
86
+ options = default_options(name).merge!(options)
120
87
 
121
- options = {
122
- :requires_gem => [],
123
- :keep_retval => false,
124
- :argument_required => false,
125
- :interpolate => true,
126
- :shellwords => true,
127
- :listing => name,
128
- :use_prefix => true
129
- }.merge!(options)
88
+ commands[name] = Pry::BlockCommand.subclass(name, description, options, helper_module, &block)
89
+ end
90
+ alias_method :command, :block_command
91
+
92
+ # Defines a new Pry command class.
93
+ #
94
+ # @param [String, Regexp] name The name of the command. Can be
95
+ # Regexp as well as String.
96
+ # @param [String] description A description of the command.
97
+ # @param [Hash] options The optional configuration parameters, see {#command}
98
+ # @param &Block The class body's definition.
99
+ #
100
+ # @example
101
+ # Pry::Commands.create_command "echo", "echo's the input", :shellwords => false do
102
+ # def options(opt)
103
+ # opt.banner "Usage: echo [-u | -d] <string to echo>"
104
+ # opt.on :u, :upcase, "ensure the output is all upper-case"
105
+ # opt.on :d, :downcase, "ensure the output is all lower-case"
106
+ # end
107
+ #
108
+ # def process
109
+ # raise Pry::CommandError, "-u and -d makes no sense" if opts.present?(:u) && opts.present?(:d)
110
+ # result = args.join(" ")
111
+ # result.downcase! if opts.present?(:downcase)
112
+ # result.upcase! if opts.present?(:upcase)
113
+ # output.puts result
114
+ # end
115
+ # end
116
+ #
117
+ def create_command(name, description="No description.", options={}, &block)
118
+ description, options = ["No description.", description] if description.is_a?(Hash)
119
+ options = default_options(name).merge!(options)
130
120
 
131
- unless command_dependencies_met? options
132
- gems_needed = Array(options[:requires_gem])
133
- gems_not_installed = gems_needed.select { |g| !gem_installed?(g) }
121
+ commands[name] = Pry::ClassCommand.subclass(name, description, options, helper_module, &block)
122
+ commands[name].class_eval(&block)
123
+ commands[name]
124
+ end
134
125
 
135
- options[:stub_info] = proc do
136
- output.puts "\nThe command '#{name}' is #{Helpers::Text.bold("unavailable")} because it requires the following gems to be installed: #{(gems_not_installed.join(", "))}"
137
- output.puts "-"
138
- output.puts "Type `install-command #{name}` to install the required gems and activate this command."
139
- end
140
- end
126
+ # Execute a block of code before a command is invoked. The block also
127
+ # gets access to parameters that will be passed to the command and
128
+ # is evaluated in the same context.
129
+ # @param [String, Regexp] name The name of the command.
130
+ # @yield The block to be run before the command.
131
+ # @example Display parameter before invoking command
132
+ # Pry.commands.before_command("whereami") do |n|
133
+ # output.puts "parameter passed was #{n}"
134
+ # end
135
+ def before_command(name, &block)
136
+ cmd = find_command_by_name_or_listing(name)
137
+ cmd.hooks[:before].unshift block
138
+ end
141
139
 
142
- commands[name] = Command.new(name, description, options, block)
140
+ # Execute a block of code after a command is invoked. The block also
141
+ # gets access to parameters that will be passed to the command and
142
+ # is evaluated in the same context.
143
+ # @param [String, Regexp] name The name of the command.
144
+ # @yield The block to be run after the command.
145
+ # @example Display text 'command complete' after invoking command
146
+ # Pry.commands.after_command("whereami") do |n|
147
+ # output.puts "command complete!"
148
+ # end
149
+ def after_command(name, &block)
150
+ cmd = find_command_by_name_or_listing(name)
151
+ cmd.hooks[:after] << block
143
152
  end
144
153
 
145
154
  def each &block
@@ -149,7 +158,10 @@ class Pry
149
158
  # Removes some commands from the set
150
159
  # @param [Array<String>] names name of the commands to remove
151
160
  def delete(*names)
152
- names.each { |name| commands.delete name }
161
+ names.each do |name|
162
+ cmd = find_command_by_name_or_listing(name)
163
+ commands.delete cmd.name
164
+ end
153
165
  end
154
166
 
155
167
  # Imports all the commands from one or more sets.
@@ -167,50 +179,79 @@ class Pry
167
179
  # @param [Array<String>] names Commands to import
168
180
  def import_from(set, *names)
169
181
  helper_module.send :include, set.helper_module
170
- names.each { |name| commands[name] = set.commands[name] }
182
+ names.each do |name|
183
+ cmd = set.find_command_by_name_or_listing(name)
184
+ commands[cmd.name] = cmd
185
+ end
186
+ end
187
+
188
+ # @param [String, Regexp] name_or_listing The name or listing name
189
+ # of the command to retrieve.
190
+ # @return [Command] The command object matched.
191
+ def find_command_by_name_or_listing(name_or_listing)
192
+ if commands[name_or_listing]
193
+ cmd = commands[name_or_listing]
194
+ else
195
+ _, cmd = commands.find { |name, command| command.options[:listing] == name_or_listing }
196
+ end
197
+
198
+ raise ArgumentError, "Cannot find a command with name: '#{name_or_listing}'!" if !cmd
199
+ cmd
171
200
  end
201
+ protected :find_command_by_name_or_listing
172
202
 
173
203
  # Aliases a command
174
204
  # @param [String] new_name New name of the command.
175
205
  # @param [String] old_name Old name of the command.
176
206
  # @param [String, nil] desc New description of the command.
177
207
  def alias_command(new_name, old_name, desc="")
178
- commands[new_name] = commands[old_name].dup
208
+ orig_command = find_command_by_name_or_listing(old_name)
209
+ commands[new_name] = orig_command.dup
179
210
  commands[new_name].name = new_name
180
211
  commands[new_name].description = desc
181
212
  end
182
213
 
183
- # Runs a command.
184
- # @param [Object] context Object which will be used as self during the
185
- # command.
186
- # @param [String] name Name of the command to be run
187
- # @param [Array<Object>] args Arguments passed to the command
188
- # @raise [NoCommandError] If the command is not defined in this set
189
- def run_command(context, name, *args)
190
- context.extend helper_module
191
- command = commands[name]
214
+ # Rename a command. Accepts either actual name or listing name for
215
+ # the `old_name`.
216
+ # `new_name` must be the actual name of the new command.
217
+ # @param [String, Regexp] new_name The new name for the command.
218
+ # @param [String, Regexp] old_name The command's current name.
219
+ # @param [Hash] options The optional configuration parameters,
220
+ # accepts the same as the `command` method, but also allows the
221
+ # command description to be passed this way too.
222
+ # @example Renaming the `ls` command and changing its description.
223
+ # Pry.config.commands.rename "dir", "ls", :description => "DOS friendly ls"
224
+ def rename_command(new_name, old_name, options={})
225
+ cmd = find_command_by_name_or_listing(old_name)
192
226
 
193
- if command.nil?
194
- raise NoCommandError.new(name, self)
195
- end
227
+ options = {
228
+ :listing => new_name,
229
+ :description => cmd.description
230
+ }.merge!(options)
196
231
 
197
- if command.options[:argument_required] && args.empty?
198
- puts "The command '#{command.name}' requires an argument."
199
- else
200
- command.call context, *args
201
- end
232
+ commands[new_name] = cmd.dup
233
+ commands[new_name].name = new_name
234
+ commands[new_name].description = options.delete(:description)
235
+ commands[new_name].options.merge!(options)
236
+ commands.delete(cmd.name)
202
237
  end
203
238
 
204
- # Sets the description for a command (replacing the old
205
- # description.)
206
- # @param [String] name The command name.
239
+ # Sets or gets the description for a command (replacing the old
240
+ # description). Returns current description if no description
241
+ # parameter provided.
242
+ # @param [String, Regexp] name The command name.
207
243
  # @param [String] description The command description.
208
- # @example
244
+ # @example Setting
209
245
  # MyCommands = Pry::CommandSet.new do
210
246
  # desc "help", "help description"
211
247
  # end
212
- def desc(name, description)
213
- commands[name].description = description
248
+ # @example Getting
249
+ # Pry.config.commands.desc "amend-line"
250
+ def desc(name, description=nil)
251
+ cmd = find_command_by_name_or_listing(name)
252
+ return cmd.description if !description
253
+
254
+ cmd.description = description
214
255
  end
215
256
 
216
257
  # Defines helpers methods for this command sets.
@@ -235,72 +276,161 @@ class Pry
235
276
  commands.keys
236
277
  end
237
278
 
279
+ # Find a command that matches the given line
280
+ #
281
+ # @param [String] the line that may be a command invocation
282
+ # @return [Pry::Command, nil]
283
+ def find_command(val)
284
+ commands.values.detect{ |c| c.matches?(val) }
285
+ end
286
+
287
+ # Is the given line a command invocation?
288
+ #
289
+ # @param [String]
290
+ # @return [Boolean]
291
+ def valid_command?(val)
292
+ !!find_command(val)
293
+ end
294
+
295
+ # Process the given line to see whether it needs executing as a command.
296
+ #
297
+ # @param String the line to execute
298
+ # @param Hash the context to execute the commands with
299
+ # @return CommandSet::Result
300
+ #
301
+ def process_line(val, context={})
302
+ if command = find_command(val)
303
+ context = context.merge(:command_set => self)
304
+ retval = command.new(context).process_line(val)
305
+ Result.new(true, retval)
306
+ else
307
+ Result.new(false)
308
+ end
309
+ end
310
+
311
+ # @nodoc used for testing
312
+ def run_command(context, name, *args)
313
+ command = commands[name] or raise NoCommandError.new(name, self)
314
+ command.new(context).call_safely(*args)
315
+ end
316
+
238
317
  private
318
+
319
+ def default_options(name)
320
+ {
321
+ :requires_gem => [],
322
+ :keep_retval => false,
323
+ :argument_required => false,
324
+ :interpolate => true,
325
+ :shellwords => true,
326
+ :listing => name,
327
+ :use_prefix => true
328
+ }
329
+ end
330
+
239
331
  def define_default_commands
240
332
 
241
- command "help", "This menu." do |cmd|
242
- if !cmd
243
- output.puts
244
- help_text = heading("Command List: ") + "\n"
333
+ create_command "help" do |cmd|
334
+ description "Show a list of commands, or help for one command"
245
335
 
246
- help_text << commands.map do |key, command|
247
- if command.description && !command.description.empty?
248
- "#{command.options[:listing]}".ljust(18) + command.description
249
- end
250
- end.compact.sort.join("\n")
336
+ banner <<-BANNER
337
+ Usage: help [ COMMAND ]
338
+
339
+ With no arguments, help lists all the available commands in the current
340
+ command-set along with their description.
341
+
342
+ When given a command name as an argument, shows the help for that command.
343
+ BANNER
251
344
 
252
- stagger_output(help_text)
253
- else
254
- if command = find_command(cmd)
255
- output.puts command.description
345
+ def process
346
+ if cmd = args.first
347
+ if command = find_command(cmd)
348
+ output.puts command.new.help
349
+ else
350
+ output.puts "No info for command: #{cmd}"
351
+ end
256
352
  else
257
- output.puts "No info for command: #{cmd}"
353
+ output.puts
354
+ help_text = heading("Command List: ") + "\n"
355
+
356
+ help_text << commands.map do |key, command|
357
+ if command.description && !command.description.empty?
358
+ "#{command.options[:listing].to_s.ljust(18)} #{command.description}"
359
+ end
360
+ end.compact.sort.join("\n")
361
+
362
+ stagger_output(help_text)
258
363
  end
259
364
  end
260
365
  end
261
366
 
262
- command "install-command", "Install a disabled command." do |name|
263
- require 'rubygems/dependency_installer' unless defined? Gem::DependencyInstaller
264
- command = find_command(name)
265
- stub_info = command.options[:stub_info]
367
+ create_command "install-command", "Install a disabled command." do |name|
266
368
 
267
- if !stub_info
268
- output.puts "Not a command stub. Nothing to do."
269
- next
270
- end
369
+ banner <<-BANNER
370
+ Usage: install-command COMMAND
271
371
 
272
- output.puts "Attempting to install `#{name}` command..."
273
- gems_to_install = Array(command.options[:requires_gem])
372
+ Installs the gems necessary to run the given COMMAND. You will generally not
373
+ need to run this unless told to by an error message.
374
+ BANNER
274
375
 
275
- gem_install_failed = false
276
- gems_to_install.each do |g|
277
- next if gem_installed?(g)
278
- output.puts "Installing `#{g}` gem..."
376
+ def process(name)
377
+ require 'rubygems/dependency_installer' unless defined? Gem::DependencyInstaller
378
+ command = find_command(name)
279
379
 
280
- begin
281
- Gem::DependencyInstaller.new.install(g)
282
- rescue Gem::GemNotFoundException
283
- output.puts "Required Gem: `#{g}` not found. Aborting command installation."
284
- gem_install_failed = true
285
- next
380
+ if command_dependencies_met?(command.options)
381
+ output.puts "Dependencies for #{command.name} are met. Nothing to do."
382
+ return
286
383
  end
287
- end
288
- next if gem_install_failed
289
-
290
- Gem.refresh
291
- gems_to_install.each do |g|
292
- begin
293
- require g
294
- rescue LoadError
295
- output.puts "Required Gem: `#{g}` installed but not found?!. Aborting command installation."
296
- gem_install_failed = true
384
+
385
+ output.puts "Attempting to install `#{name}` command..."
386
+ gems_to_install = Array(command.options[:requires_gem])
387
+
388
+ gems_to_install.each do |g|
389
+ next if gem_installed?(g)
390
+ output.puts "Installing `#{g}` gem..."
391
+
392
+ begin
393
+ Gem::DependencyInstaller.new.install(g)
394
+ rescue Gem::GemNotFoundException
395
+ raise CommandError, "Required Gem: `#{g}` not found. Aborting command installation."
396
+ end
397
+ end
398
+
399
+ Gem.refresh
400
+ gems_to_install.each do |g|
401
+ begin
402
+ require g
403
+ rescue LoadError
404
+ raise CommandError, "Required Gem: `#{g}` installed but not found?!. Aborting command installation."
405
+ end
297
406
  end
298
- end
299
- next if gem_install_failed
300
407
 
301
- command.options.delete :stub_info
302
- output.puts "Installation of `#{name}` successful! Type `help #{name}` for information"
408
+ output.puts "Installation of `#{name}` successful! Type `help #{name}` for information"
409
+ end
303
410
  end
304
411
  end
305
412
  end
413
+
414
+ # Wraps the return result of process_commands, indicates if the
415
+ # result IS a command and what kind of command (e.g void)
416
+ class Result
417
+ attr_reader :retval
418
+
419
+ def initialize(is_command, retval = nil)
420
+ @is_command, @retval = is_command, retval
421
+ end
422
+
423
+ # Is the result a command?
424
+ # @return [Boolean]
425
+ def command?
426
+ @is_command
427
+ end
428
+
429
+ # Is the result a command and if it is, is it a void command?
430
+ # (one that does not return a value)
431
+ # @return [Boolean]
432
+ def void_command?
433
+ retval == Command::VOID_VALUE
434
+ end
435
+ end
306
436
  end