diff --git a/lib/pry.rb b/lib/pry.rb index 566d3491..f592be93 100644 --- a/lib/pry.rb +++ b/lib/pry.rb @@ -19,7 +19,8 @@ end require "pry/version" require "pry/hooks" require "pry/print" -require "pry/command_base" +require "pry/command_set" +require "pry/command_base" # to be romved require "pry/commands" require "pry/prompts" require "pry/custom_completions" diff --git a/lib/pry/command_set.rb b/lib/pry/command_set.rb new file mode 100644 index 00000000..4c92d6a3 --- /dev/null +++ b/lib/pry/command_set.rb @@ -0,0 +1,106 @@ +class Pry + class NoCommandError < StandardError + def initialize(name, owner) + super "Command '#{name}' not found in command set #{owner}" + end + end + + # This class used to create sets of commands. Commands can be impoted from + # different sets, aliased, removed, etc. + class CommandSet + class Command < Struct.new(:name, :description, :options, :block) + def call(context, *args) + context.instance_exec(*args, &block) + end + end + + attr_reader :commands + attr_reader :name + + # @param [Symbol] name Name of the command set + # @param [Array] imported_sets Sets which will be imported + # automatically + # @yield Optional block run to define commands + def initialize(name, *imported_sets, &block) + @name = name + @commands = {} + + import(*imported_sets) + + instance_eval(&block) if block + end + + # Defines a new Pry command. + # @param [String, Array] names The name of the command (or array of + # command name aliases). + # @param [String] description A description of the command. + # @param [Hash] options The optional configuration parameters. + # @option options [Boolean] :keep_retval Whether or not to use return value + # of the block for return of `command` or just to return `nil` + # (the default). + # @yield The action to perform. The parameters in the block + # determines the parameters the command will receive. All + # parameters passed into the block will be strings. Successive + # command parameters are separated by whitespace at the Pry prompt. + # @example + # MyCommands Pry::CommandSet.new :mine do + # command "greet", "Greet somebody" do |name| + # puts "Good afternoon #{name.capitalize}!" + # end + # end + # + # # From pry: + # # pry(main)> _pry_.commands = MyCommands + # # pry(main)> greet john + # # Good afternoon John! + # # pry(main)> help greet + # # Greet somebody + def command(names, description="No description.", options={}, &block) + Array(names).each do |name| + commands[name] = Command.new(name, description, options, block) + end + end + + # Removes some commands from the set + # @param [Arary] names name of the commands to remove + def delete(*names) + names.each { |name| commands.delete name } + end + + # Imports all the commands from one or more sets. + # @param [Array] sets Command sets, all of the commands of which + # will be imported. + def import(*sets) + sets.each { |set| commands.merge! set.commands } + end + + # Imports some commands from a set + # @param [CommandSet] set Set to import commands from + # @param [Array] names Commands to import + def import_from(set, *names) + names.each { |name| commands[name] = set.commands[name] } + end + + # Aliases a command + # @param [String] new_name new name of the command + # @param [String] old_name old name of the command + def alias_command(new_name, old_name) + commands[new_name] = commands[old_name].dup + commands[new_name].name = new_name + end + + # Runs a command. + # @param [Object] context Object which will be used as self during the + # command. + # @param [String] name Name of the command to be run + # @param [Array] args Arguments passed to the command + # @raise [NoCommandError] If the command is not defined in this set + def run_command(context, name, *args) + if command = commands[name] + command.call(context, *args) + else + raise NoCommandError.new(name, self) + end + end + end +end diff --git a/test/test.rb b/test/test.rb index ecaecede..64766899 100644 --- a/test/test.rb +++ b/test/test.rb @@ -1,8 +1,9 @@ direc = File.dirname(__FILE__) +$LOAD_PATH.unshift "#{direc}/../lib" require 'rubygems' require 'bacon' -require "#{direc}/../lib/pry" +require "pry" require "#{direc}/test_helper" puts "Ruby Version #{RUBY_VERSION}" @@ -73,7 +74,7 @@ describe Pry do pry_tester.rep(o) str_output.string.should == "" end - + it 'should suppress output if input ends in a ";" (multi-line)' do o = Object.new @@ -790,3 +791,117 @@ describe Pry do end end end + +describe Pry::CommandSet do + before do + @set = Pry::CommandSet.new(:some_name) + end + + it 'should use the name specified at creation' do + @set.name.should == :some_name + end + + it 'should have no commands' do + @set.commands.should.be.empty + end + + it 'should call the block used for the command when it is called' do + run = false + @set.command 'foo' do + run = true + end + + @set.run_command nil, 'foo' + run.should == true + end + + it 'should pass arguments of the command to the block' do + @set.command 'foo' do |*args| + args.should == [1, 2, 3] + end + + @set.run_command nil, 'foo', 1, 2, 3 + end + + it 'should use the first argument as self' do + @set.command 'foo' do + self.should == true + end + + @set.run_command true, 'foo' + end + + it 'should raise an error when calling an undefined comand' do + @set.command('foo') {} + lambda { + @set.run_command nil, 'bar' + }.should.raise(Pry::NoCommandError) + end + + it 'should be able to remove its own commands' do + @set.command('foo') {} + @set.delete 'foo' + + lambda { + @set.run_command nil, 'foo' + }.should.raise(Pry::NoCommandError) + end + + it 'should be able to import some commands from other sets' do + run = false + + other_set = Pry::CommandSet.new :foo do + command('foo') { run = true } + command('bar') {} + end + + @set.import_from(other_set, 'foo') + + @set.run_command nil, 'foo' + run.should == true + + lambda { + @set.run_command nil, 'bar' + }.should.raise(Pry::NoCommandError) + end + + it 'should be able to import a whole set' do + run = [] + + other_set = Pry::CommandSet.new :foo do + command('foo') { run << true } + command('bar') { run << true } + end + + @set.import other_set + + @set.run_command nil, 'foo' + @set.run_command nil, 'bar' + run.should == [true, true] + end + + it 'should be able to import sets at creation' do + run = false + @set.command('foo') { run = true } + + Pry::CommandSet.new(:other, @set).run_command nil, 'foo' + run.should == true + end + + it 'should set the descriptions of commands' do + @set.command('foo', 'some stuff') {} + @set.commands['foo'].description.should == 'some stuff' + end + + it 'should be able to alias method' do + run = false + @set.command('foo', 'stuff') { run = true } + + @set.alias_command 'bar', 'foo' + @set.commands['bar'].name.should == 'bar' + @set.commands['bar'].description.should == 'stuff' + + @set.run_command nil, 'bar' + run.should == true + end +end