diff --git a/README.markdown b/README.markdown index b4f02480..a92a5a3c 100644 --- a/README.markdown +++ b/README.markdown @@ -343,14 +343,19 @@ and executed before a Ruby eval takes place. Pry comes with a default command set (`Pry::Commands`), but these commands can be augmented or overriden by user-specified ones. +The Pry command API is quite sophisticated supporting features such as: +command set inheritance, importing of specific commands from another +command set, deletion of commands, calling of commands within other +commands, and so on. + A valid Pry command object must inherit from `Pry::CommandBase` and use the special command API: #### Example: Defining a command object and setting it globally class MyCommands < Pry::CommandBase - command "hello", "Output hello to the user." do |name| - opts[:output].puts "hello #{name}!" + command greet", "Greet the user." do |name| + output.puts "Hello #{name.capitalize}, how are you?" end end @@ -358,8 +363,8 @@ A valid Pry command object must inherit from Then inside a pry session: - pry(main)> hello john - hello john! + pry(main)> greet john + hello John, how are you? => nil #### Example: Using a command object in a specific session @@ -367,7 +372,7 @@ Then inside a pry session: As in the case of `input` and `output`: ##### At session start: -nnnnn + Pry.start(self, :commands => MyCommands) ##### At runtime: @@ -377,9 +382,9 @@ nnnnn #### The command API The command API is defined by the `Pry::CommandBase` class (hence why -all commands must inherit from it). The API works as follows: +all commands must inherit from it or a subclass). The API works as follows: -The `command` method defines a new command, its parameter is the +* The `command` method defines a new command, its parameter is the name of the command and an optional second parameter is a description of the command. @@ -398,23 +403,64 @@ for the command name - all these strings will be valid names for the command. command ["ls", "dir"], "show a list of local vars" do - opts[:output].puts opts[:target].eval("local_variables") + output.puts target.eval("local_variables") end +* The `delete` method deletes a command or a group of a commands; it + can be useful when inheriting from another command set when you decide + to keep only a portion of inherited commands. -#### opts hash + class MyCommands < Pry::Commands + delete "show_method", "show_imethod" + end -Note that in the example above we are using `opts[:output]` for output; this is the output -object in use by the current pry session. Other hash values accessible -within a `command` block include: +* The `import_from` method enables you to specifically select which + commands will be copied across from another command set, useful when + you only want a small number of commands and so inheriting and then + deleting would be inefficient. The first parameter to `import_from` + is the class to import from and the other paramters are the names of + the commands to import: + + class MyCommands < Pry::CommandBase + import_from Pry::Commands, "ls", "status", "!" + end + +* The `run` command invokes one command from within another. + The first parameter is the name of the command to invoke + and the remainder of the parameters will be passed on to the command + being invoked: + + class MyCommands < Pry::Commands + command "ls_with_hello" do + output.puts "hello!" + run "ls" + end + end + +#### Utility methods for commands + +All commands can access the special `output` and `target` methods. The +`output` method returns the `output` object for the active pry session. +Ensuring that your commands invoke `puts` on this rather than using +the top-level `puts` will ensure that all your session output goes to +the same place. + +The `target` method returns the `Binding` object the Pry session is currently +active on - useful when your commands need to manipulate or examine +the state of the object. E.g, the "ls" command is implemented as follows + + command "ls" do + output.puts target.eval("local_variables + instance_variables").inspect + end + +#### The opts hash + +These are miscellaneous variables that may be useful to your own commands: -* `opts[:output]` - The session's output object. * `opts[:val]` - The line of input that invoked the command. * `opts[:eval_string]` - The cumulative lines of input for multi-line input. -* `opts[:target]` - The object the Pry session is currently on. -* `opts[:captures]` - The array of regex captures generated by the command (if any). * `opts[:nesting]` - Lowlevel session nesting information. -* `opts[:command_info]` - Lowlevel information about all Pry commands. +* `opts[:commands]` - Lowlevel data of all Pry commands. (see commands.rb for examples of how some of these options are used) @@ -424,7 +470,11 @@ The `Pry::CommandBase` class automatically defines a `help` command for you. Typing `help` in a Pry session will show a list of commands to the user followed by their descriptions. Passing a parameter to `help` with the command name will just return the description of that -specific command. +specific command. If a description is left out it will automatically +be given the description "No description.". + +If the description is explicitly set to `""` then this command will +not be displayed in `help`. ### Hooks diff --git a/examples/example_command_override.rb b/examples/example_command_override.rb new file mode 100644 index 00000000..49f5abed --- /dev/null +++ b/examples/example_command_override.rb @@ -0,0 +1,27 @@ +direc = File.dirname(__FILE__) + +require 'rubygems' +require "#{direc}/../lib/pry" + +# inherit standard command set, but tweak them by deleting some and +# overriding others +class MyCommands < Pry::CommandBase + + # Override ls command + command "ls", "An unhelpful ls" do + output.puts "No, i refuse to display any useful information." + end + + # Invoke one command from within another using `run` + command "status2" do |x| + output.puts "About to show status, are you ready?" + run "status", x + output.puts "Finished showing status." + end + + import_from Pry::Commands, "quit", "show_method", "ls" +end + +# Start a Pry session using the commands defined in MyCommands +# Type 'help' in Pry to get a list of the commands and their descriptions +Pry.start(TOPLEVEL_BINDING, :commands => MyCommands) diff --git a/examples/example_commands.rb b/examples/example_commands.rb new file mode 100644 index 00000000..d53561f2 --- /dev/null +++ b/examples/example_commands.rb @@ -0,0 +1,36 @@ +direc = File.dirname(__FILE__) + +require 'rubygems' +require "#{direc}/../lib/pry" + +class MathCommands < Pry::CommandBase + command "greet", "Greet a person, e.g: greet john" do |name| + output.puts "Good afternoon #{name.capitalize}! Do you like Math?" + end + + command "add", "Add a list of numbers together, e.g: add 1 2 3 4" do |*args| + output.puts "Total: #{args.map(&:to_f).inject(&:+)}" + end + + command "multiply", "Multiply a list of numbers together, e.g: multiply 1 2 3 4" do |*args| + output.puts "Total: #{args.map(&:to_f).inject(&:*)}" + end + + # Explicitly giving a description of "" to prevent command being + # displayed in 'help' + command "exit", "" do + throw :breakout, 0 + end +end + +# Since we provide math commands, let's have mathematical +# before_session and after_session hooks, and a mathematical prompt +math_prompt = proc { "math> " } +math_hooks = { + :before_session => proc { |output, *| output.puts "Welcome! Let's do some math! Type 'help' for a list of commands." }, + :after_session => proc { |output, *| output.puts "Goodbye!" } +} + +# Start a Pry session using the commands defined in MyCommands +# Type 'help' in Pry to get a list of the commands and their descriptions +Pry.start(TOPLEVEL_BINDING, :commands => MathCommands, :prompt => math_prompt, :hooks => math_hooks) diff --git a/examples/example_hooks.rb b/examples/example_hooks.rb new file mode 100644 index 00000000..a5789c63 --- /dev/null +++ b/examples/example_hooks.rb @@ -0,0 +1,12 @@ +direc = File.dirname(__FILE__) + +require 'rubygems' +require "#{direc}/../lib/pry" + +my_hooks = { + :before_session => proc { |out, obj| out.puts "Opening #{obj}." }, + :after_session => proc { |out, obj| out.puts "Closing #{obj}." } +} + +# Start a Pry session using the hooks hash defined in my_hooks +Pry.start(TOPLEVEL_BINDING, :hooks => my_hooks) diff --git a/examples/example_image_edit.rb b/examples/example_image_edit.rb new file mode 100644 index 00000000..ad29de60 --- /dev/null +++ b/examples/example_image_edit.rb @@ -0,0 +1,70 @@ +# Note: this requires you to have Gosu and TexPlay installed. +# `gem install gosu` +# `gem install texplay` +# +# Extra instructions for installing Gosu on Linux can be found here: +# http://code.google.com/p/gosu/wiki/GettingStartedOnLinux +# +# Instructions for using TexPlay can be found here: +# http://banisterfiend.wordpress.com/2008/08/23/texplay-an-image-manipulation-tool-for-ruby-and-gosu/ +# +# Have fun! :) + +direc = File.dirname(__FILE__) + +require 'rubygems' +require "texplay" +require "#{direc}/../lib/pry" + +WIDTH = 640 +HEIGHT = 480 + +IMAGE_PROMPT = [ proc { "(image edit)> " }, proc { "(image edit)* " } ] + +class ImageCommands < Pry::CommandBase + command "drawing_methods", "Show a list of TexPlay methods" do + output.puts "#{Pry.view(TexPlay.public_instance_methods)}" + end + + command "exit", "Exit the program." do + output.puts "Thanks for dropping by!" + exit + end + + import_from Pry::Commands, "ls", "ls_methods", "!" +end + +class WinClass < Gosu::Window + + def initialize + super(WIDTH, HEIGHT, false) + @img = TexPlay.create_image(self, 200, 200) + @img.rect 0, 0, @img.width - 1, @img.height - 1 + + @binding = @img.__binding__ + + @pry_instance = Pry.new(:commands => ImageCommands, :prompt => IMAGE_PROMPT) + end + + def draw + @img.draw_rot(WIDTH / 2, HEIGHT / 2, 1, 0, 0.5, 0.5) + end + + def update + exit if button_down?(Gosu::KbEscape) + + # We do not want a REPL session as the loop prevents the image + # being updated; instead we do a REP session, and let the image + # update each time the user presses enter. We maintain the same + # binding object to keep locals between calls to `Pry#rep()` + @pry_instance.rep(@binding) + end +end + +puts "Welcome to ImageEdit; type `help` for a list of commands and `drawing_methods` for a list of drawing methods available." +puts "--" +puts "Example: Try typing 'circle width/2, height/2, 95, :color => :blue, :fill => true'" +puts "If you want to save your image, type: save(\"img.png\")" + +WinClass.new.show + diff --git a/examples/example_input.rb b/examples/example_input.rb new file mode 100644 index 00000000..dd7c8d4e --- /dev/null +++ b/examples/example_input.rb @@ -0,0 +1,10 @@ +direc = File.dirname(__FILE__) + +require 'rubygems' +require "#{direc}/../lib/pry" + +# Create a StringIO that contains the input data +str_input = StringIO.new("puts 'hello world!'\nputs \"I am in \#{self}\"\nexit") + +# Start a Pry session on the Fixnum 5 using the input data in str_input +Pry.start(5, :input => str_input) diff --git a/examples/example_output.rb b/examples/example_output.rb new file mode 100644 index 00000000..e54dad77 --- /dev/null +++ b/examples/example_output.rb @@ -0,0 +1,14 @@ +direc = File.dirname(__FILE__) + +require 'rubygems' +require "#{direc}/../lib/pry" + +# Create a StringIO to contain the output data +str_output = StringIO.new + +# Start a Pry session on the Fixnum 5 using str_output to store the +# output (not writing to $stdout) +Pry.start(5, :output => str_output) + +# Display all the output accumulated during the session +puts str_output.string diff --git a/examples/example_print.rb b/examples/example_print.rb new file mode 100644 index 00000000..0b55a31a --- /dev/null +++ b/examples/example_print.rb @@ -0,0 +1,9 @@ +direc = File.dirname(__FILE__) + +require 'rubygems' +require "#{direc}/../lib/pry" + +my_print = proc { |out, value| out.puts "Output is: #{value.inspect}" } + +# Start a Pry session using the print object defined in my_print +Pry.start(TOPLEVEL_BINDING, :print => my_print) diff --git a/examples/example_prompt.rb b/examples/example_prompt.rb new file mode 100644 index 00000000..44b68092 --- /dev/null +++ b/examples/example_prompt.rb @@ -0,0 +1,12 @@ +direc = File.dirname(__FILE__) + +require 'rubygems' +require "#{direc}/../lib/pry" + +# Remember, first prompt in array is the main prompt, second is the wait +# prompt (used for multiline input when more input is required) +my_prompt = [ proc { |obj, *| "inside #{obj}> " }, + proc { |obj, *| "inside #{obj}* "} ] + +# Start a Pry session using the prompt defined in my_prompt +Pry.start(TOPLEVEL_BINDING, :prompt => my_prompt) diff --git a/lib/pry/command_base.rb b/lib/pry/command_base.rb index 36893d5c..378dc51f 100644 --- a/lib/pry/command_base.rb +++ b/lib/pry/command_base.rb @@ -6,7 +6,7 @@ class Pry class << self attr_accessor :commands attr_accessor :command_info - attr_accessor :opts + attr_accessor :opts, :output, :target # private because we want to force function style invocation. We require # that the location where the block is defined has the `opts` @@ -14,7 +14,7 @@ class Pry private # Defines a new Pry command. - # @param [String, Array] name The name of the command (or array of + # @param [String, Array] names The name of the command (or array of # command name aliases). # @param [String] description A description of the command. # @yield The action to perform. The parameters in the block @@ -34,42 +34,73 @@ class Pry # # Good afternoon John! # # pry(main)> help greet # # Greet somebody - def command(name, description="No description.", &block) + def command(names, description="No description.", &block) @commands ||= {} - @command_info ||= {} - arg_match = '(?:\s+(\S+))?' * 20 - if name.is_a?(Array) - name.each do |n| - matcher = /^#{n}(?!\S)#{arg_match}?/ - commands[matcher] = block - command_info[n] = description - end - else - matcher = /^#{name}(?!\S)#{arg_match}?/ - commands[matcher] = block - command_info[name] = description + Array(names).each do |name| + commands[name] = { :description => description, :action => block } end + end + # Delete a command or an array of commands. + # Useful when inheriting from another command set and pruning + # those commands down to the ones you want. + # @param [Array] names The command name or array + # of command names you want to delete + # @example Deleteing inherited commands + # class MyCommands < Pry::Commands + # delete "show_method", "show_imethod", "show_doc", "show_idoc" + # end + # Pry.commands = MyCommands + def delete(*names) + names.each { |name| commands.delete(name) } + end + + # Execute a command (this enables commands to call other commands). + # @param [String] name The command to execute + # @param [Array] args The parameters to pass to the command. + # @example Wrap one command with another + # class MyCommands < Pry::Commands + # command "ls2" do + # output.puts "before ls" + # run "ls" + # output.puts "after ls" + # end + # end + def run(name, *args) + action = opts[:commands][name][:action] + instance_exec(*args, &action) + end + + # Import commands from another command object. + # @param [Pry::CommandBase] klass The class to import from (must + # be a subclass of `Pry::CommandBase`) + # @param [Array] names The commands to import. + # @example + # class MyCommands < Pry::CommandBase + # import_from Pry::Commands, "ls", "show_method", "cd" + # end + def import_from(klass, *names) + imported_hash = Hash[klass.commands.select { |k, v| names.include?(k) }] + commands.merge!(imported_hash) end end + command "help", "This menu." do |cmd| - out = opts[:output] - command_info = opts[:command_info] + command_info = opts[:commands] param = cmd if !param - out.puts "Command list:" - out.puts "--" - command_info.each do |k, v| - out.puts "#{k}".ljust(18) + v + output.puts "Command list:" + output.puts "--" + command_info.each do |k, data| + output.puts "#{k}".ljust(18) + data[:description] if !data[:description].empty? end else - key = command_info.keys.find { |v| Array(v).any? { |k| k === param } } - if key - out.puts command_info[key] + if command_info[param] + output.puts command_info[param][:description] else - out.puts "No info for command: #{param}" + output.puts "No info for command: #{param}" end end end @@ -77,7 +108,7 @@ class Pry # Ensures that commands can be inherited def self.inherited(klass) klass.commands = commands.dup - klass.command_info = command_info.dup end + end end diff --git a/lib/pry/commands.rb b/lib/pry/commands.rb index 2bc54a64..f134ea77 100644 --- a/lib/pry/commands.rb +++ b/lib/pry/commands.rb @@ -7,12 +7,12 @@ class Pry class Commands < CommandBase command "!", "Refresh the REPL" do - opts[:output].puts "Refreshed REPL" + output.puts "Refreshed REPL" opts[:eval_string].clear end command "!pry", "Start a Pry session on current self; this even works mid-expression." do - Pry.start(opts[:target]) + Pry.start(target) end command ["exit_program", "quit_program"], "End the current program." do @@ -20,7 +20,7 @@ class Pry end command "nesting", "Show nesting information." do - out = opts[:output] + out = output nesting = opts[:nesting] out.puts "Nesting status:" @@ -35,9 +35,8 @@ class Pry end command "status", "Show status information." do - out = opts[:output] + out = output nesting = opts[:nesting] - target = opts[:target] out.puts "Status:" out.puts "--" @@ -53,37 +52,37 @@ class Pry end command "ls", "Show the list of vars in the current scope." do - opts[:output].puts "#{Pry.view(opts[:target].eval('local_variables + instance_variables'))}" + output.puts "#{Pry.view(target.eval('local_variables + instance_variables'))}" end command "cat", "Show output of .inspect." do |obj| - out = opts[:output] - out.puts opts[:target].eval("#{obj}.inspect") + out = output + out.puts target.eval("#{obj}.inspect") end command "cd", "Start a Pry session on (use `cd ..` to go back)" do |obj| throw(:breakout, opts[:nesting].level) if obj == ".." - opts[:target].eval("#{obj}.pry") + target.eval("#{obj}.pry") end command "show_doc", "Show the comments above " do |meth_name| - doc = opts[:target].eval("method(:#{meth_name})").comment - opts[:output].puts doc + doc = target.eval("method(:#{meth_name})").comment + output.puts doc end command "show_idoc", "Show the comments above instance method " do |meth_name| - doc = opts[:target].eval("instance_method(:#{meth_name})").comment - opts[:output].puts doc + doc = target.eval("instance_method(:#{meth_name})").comment + output.puts doc end command "show_method", "Show sourcecode for method ." do |meth_name| - doc = opts[:target].eval("method(:#{meth_name})").source - opts[:output].puts doc + doc = target.eval("method(:#{meth_name})").source + output.puts doc end command "show_imethod", "Show sourcecode for instance method ." do |meth_name| - doc = opts[:target].eval("instance_method(:#{meth_name})").source - opts[:output].puts doc + doc = target.eval("instance_method(:#{meth_name})").source + output.puts doc end command "jump_to", "Jump to a Pry session further up the stack, exiting all sessions below." do |break_level| @@ -92,21 +91,21 @@ class Pry case break_level when nesting.level - opts[:output].puts "Already at nesting level #{nesting.level}" + output.puts "Already at nesting level #{nesting.level}" when (0...nesting.level) throw(:breakout, break_level + 1) else max_nest_level = nesting.level - 1 - opts[:output].puts "Invalid nest level. Must be between 0 and #{max_nest_level}. Got #{break_level}." + output.puts "Invalid nest level. Must be between 0 and #{max_nest_level}. Got #{break_level}." end end command "ls_methods", "List all methods defined on class of receiver." do - opts[:output].puts "#{Pry.view(opts[:target].eval('public_methods(false) + private_methods(false) + protected_methods(false)'))}" + output.puts "#{Pry.view(target.eval('public_methods(false) + private_methods(false) + protected_methods(false)'))}" end command "ls_imethods", "List all instance methods defined on class of receiver." do - opts[:output].puts "#{Pry.view(opts[:target].eval('public_instance_methods(false) + private_instance_methods(false) + protected_instance_methods(false)'))}" + output.puts "#{Pry.view(target.eval('public_instance_methods(false) + private_instance_methods(false) + protected_instance_methods(false)'))}" end command ["exit", "quit", "back"], "End the current Pry session." do diff --git a/lib/pry/pry_instance.rb b/lib/pry/pry_instance.rb index 0475170c..3923aa9f 100644 --- a/lib/pry/pry_instance.rb +++ b/lib/pry/pry_instance.rb @@ -125,7 +125,7 @@ class Pry target = binding_for(target) if input == Readline - Readline.completion_proc = Pry::InputCompleter.build_completion_proc(target, Pry.commands.command_info.keys.flatten) + Readline.completion_proc = Pry::InputCompleter.build_completion_proc(target, commands.commands.keys) end # eval the expression and save to last_result @@ -182,28 +182,29 @@ class Pry def val.clear() replace("") end def eval_string.clear() replace("") end - pattern, action = commands.commands.find { |k, v| k === val } + pattern, data = commands.commands.find do |name, data| + /^#{name}(?!\S)(?:\s+(.+))?/ =~ val + end if pattern - captures = Regexp.last_match.captures - captures.compact! + args_string = $1 + args = args_string ? args_string.split : [] + action = data[:action] options = { - :captures => captures, + :captures => args_string, :eval_string => eval_string, :target => target, :val => val, :nesting => nesting, :output => output, - :command_info => commands.command_info + :commands => commands.commands } - # because procs are defined in different places (e.g 'help' in CommandBase) - # we cannot simply use `commands.opts=...`; instead we have to - # retrieve the object where the block was defined; since that is - # where the `opts` method the block will have access to is defined. - action_self = action.binding.eval('self') - action_self.opts = options + # set some useful methods to be used by the action blocks + commands.opts = options + commands.target = target + commands.output = output # send the correct number of parameters to the block (to avoid # warnings in 1.8.7) @@ -212,14 +213,19 @@ class Pry # if arity is negative then we have a *args in 1.8.7. # In 1.9 we have default values or *args - action.call(*captures) + # Use instance_exec() to make the opts, target, output, etc methods available + commands.instance_exec(*args, &action) when 1, 0 # ensure that we get the right number of parameters; # using values_at we pad out missing parameters with nils so # that 1.8.7 doesn't complain about incorrect arity (1.9.2 # doesn't care) - action.call(*captures.values_at(*0..(action.arity - 1))) + args_with_corrected_arity = args.values_at *0..(action.arity - 1) + + # Use instance_exec() to make the opts, target, output, etc methods + # available + commands.instance_exec(*args_with_corrected_arity, &action) end val.clear diff --git a/test/test.rb b/test/test.rb index 4b6e73db..cf057fd9 100644 --- a/test/test.rb +++ b/test/test.rb @@ -298,25 +298,122 @@ describe Pry do end Command2.commands.keys.size.should == 2 - Command2.command_info.keys.include?("help").should == true - Command2.command_info.keys.include?("h").should == true + Command2.commands.keys.include?("help").should == true + Command2.commands.keys.include?("h").should == true Object.remove_const(:Command2) end - it 'should inherit comands from Pry::Commands' do + it 'should inherit commands from Pry::Commands' do class Command3 < Pry::Commands command "v" do end end - Command3.command_info.include?("nesting").should == true - Command3.command_info.include?("jump_to").should == true - Command3.command_info.include?("cd").should == true - Command3.command_info.include?("v").should == true + Command3.commands.include?("nesting").should == true + Command3.commands.include?("jump_to").should == true + Command3.commands.include?("cd").should == true + Command3.commands.include?("v").should == true Object.remove_const(:Command3) end + + it 'should run a command from within a command' do + class Command3 < Pry::Commands + command "v" do + output.puts "v command" + end + + command "run_v" do + run "v" + end + end + + str_output = StringIO.new + Pry.new(:input => InputTester.new("run_v"), :output => str_output, :commands => Command3).rep + str_output.string.should =~ /v command/ + + Object.remove_const(:Command3) + end + + it 'should enable an inherited method to access opts and output and target, due to instance_exec' do + class Command3 < Pry::Commands + command "v" do + output.puts "#{target.eval('self')}" + end + end + + class Command4 < Command3 + end + + str_output = StringIO.new + Pry.new(:print => proc {}, :input => InputTester.new("v"), + :output => str_output, :commands => Command4).rep("john") + str_output.string.chomp.should == "john" + + Object.remove_const(:Command3) + Object.remove_const(:Command4) + end + + it 'should import commands from another command object' do + class Command3 < Pry::CommandBase + import_from Pry::Commands, "status", "jump_to" + end + + str_output = StringIO.new + Pry.new(:print => proc {}, :input => InputTester.new("status"), + :output => str_output, :commands => Command3).rep("john") + str_output.string.should =~ /Status:/ + + Object.remove_const(:Command3) + end + + it 'should delete some inherited commands when using delete method' do + class Command3 < Pry::Commands + command "v" do + end + + delete "show_doc", "show_method" + delete "ls" + end + + Command3.commands.include?("nesting").should == true + Command3.commands.include?("jump_to").should == true + Command3.commands.include?("cd").should == true + Command3.commands.include?("v").should == true + Command3.commands.include?("show_doc").should == false + Command3.commands.include?("show_method").should == false + Command3.commands.include?("ls").should == false + + Object.remove_const(:Command3) + end + + it 'should override some inherited commands' do + class Command3 < Pry::Commands + command "jump_to" do + output.puts "jump_to the music" + end + + command "help" do + output.puts "help to the music" + end + end + + # suppress evaluation output + Pry.print = proc {} + + str_output = StringIO.new + Pry.new(:input => InputTester.new("jump_to"), :output => str_output, :commands => Command3).rep + str_output.string.chomp.should == "jump_to the music" + + str_output = StringIO.new + Pry.new(:input => InputTester.new("help"), :output => str_output, :commands => Command3).rep + str_output.string.chomp.should == "help to the music" + + Object.remove_const(:Command3) + + Pry.reset_defaults + end end it "should set the print default, and the default should be overridable" do