pry 0.9.7.4-i386-mswin32 → 0.9.8-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.
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