1
0
Fork 0
mirror of https://github.com/pry/pry.git synced 2022-11-09 12:35:05 -05:00

finished updating and improving command API; now command API is as follows: command 'blah' do |x| puts x; end where x is a parameter passed to the command from the pry prompt

This commit is contained in:
John Mair 2011-01-18 03:38:09 +13:00
parent 500456032c
commit f45e8bfbd0
7 changed files with 147 additions and 257 deletions

View file

@ -10,6 +10,7 @@ require "#{direc}/pry/input"
require "#{direc}/pry/output" require "#{direc}/pry/output"
require "#{direc}/pry/hooks" require "#{direc}/pry/hooks"
require "#{direc}/pry/print" require "#{direc}/pry/print"
require "#{direc}/pry/command_base"
require "#{direc}/pry/commands" require "#{direc}/pry/commands"
require "#{direc}/pry/prompts" require "#{direc}/pry/prompts"
require "#{direc}/pry/completion" require "#{direc}/pry/completion"

View file

@ -6,83 +6,54 @@ class Pry
class << self class << self
attr_accessor :commands attr_accessor :commands
attr_accessor :command_info attr_accessor :command_info
end attr_accessor :opts
# A class to assist in building Pry commands # private because we want to force function style invocation. We require
class Command # that the location where the block is defined has the `opts`
Elements = [:name, :describe, :pattern, :action] # method in scope.
private
Elements.each do |e| # Defines a new Pry command.
define_method(e) { |s| instance_variable_set("@#{e}", s) } # @param [String, Array] name The name of the command (or array of
define_method("get_#{e}") { instance_variable_get("@#{e}") } # command name aliases).
end # @yield [command] The action to perform. The parameters in the block
# determines the parameters the command will receive.
def command(name, description="No description.", &block)
@commands ||= {}
@command_info ||= {}
# define action here since it needs to take a block. arg_match = '(?:\s+(\S+))?' * 20
def action(&block) if name.is_a?(Array)
@action = block matcher = []
end name.each do |n|
end matcher << /^#{n}#{arg_match}?/
# Ensure commands are properly constructed.
# @param [Pry::CommandBase::Command] c The command to check.
def self.check_command(c)
c.pattern(c.get_name) if !c.get_pattern
c.describe "No description." if !c.get_describe
Command::Elements.each do |e|
raise "command has no #{e}!" if !c.send("get_#{e}")
end
end
# Defines a new Pry command.
# @param [String, Array] name The name of the command (or array of
# command name aliases).
# @yield [command] The command block. Optionally yields command if
# block arity is 1. Otherwise block is instance_eval'd.
def self.command(name, &block)
@commands ||= {}
@command_info ||= {}
c = Command.new
c.name name
if block.arity == 1
yield(c)
else
c.instance_eval(&block)
end
check_command(c)
commands.merge! c.get_pattern => c.get_action
command_info.merge! c.get_name => c.get_describe
end
command "help" do
pattern /^help\s*(.+)?/
describe "This menu."
action do |opts|
out = opts[:output]
command_info = opts[:command_info]
param = opts[:captures].first
if !param
out.puts "Command list:"
out.puts "--"
command_info.each do |k, v|
out.puts "#{Array(k).first}".ljust(18) + v
end end
else else
key = command_info.keys.find { |v| Array(v).any? { |k| k === param } } matcher = /^#{name}#{arg_match}?/
if key
out.puts command_info[key]
else
out.puts "No info for command: #{param}"
end
end end
opts[:val].clear commands[matcher] = block
command_info[name] = description
end
end
command "help", "This menu." do |cmd|
out = opts[:output]
command_info = opts[:command_info]
param = cmd
if !param
out.puts "Command list:"
out.puts "--"
command_info.each do |k, v|
out.puts "#{Array(k).first}".ljust(18) + v
end
else
key = command_info.keys.find { |v| Array(v).any? { |k| k === param } }
if key
out.puts command_info[key]
else
out.puts "No info for command: #{param}"
end
end end
end end

View file

@ -24,179 +24,111 @@ class Pry
# Pry.commands = MyCommands # Pry.commands = MyCommands
class Commands < CommandBase class Commands < CommandBase
command "!" do command "!", "Refresh the REPL" do
describe "Refresh the REPL" opts[:output].puts "Refreshed REPL"
action do |opts| opts[:eval_string].clear
opts[:output].puts "Refreshed REPL"
opts[:eval_string].clear
end
end end
command "!pry" do command "!pry", "Start a Pry session on current self; this even works mid-expression." do
describe "Start a Pry session on current self; this even works mid-expression." Pry.start(opts[:target])
action do |opts|
Pry.start(opts[:target])
end
end end
command ["exit_program", "quit_program"] do command ["exit_program", "quit_program"], "End the current program." do
describe "End the current program." exit
action { |opts| exit }
end end
command "nesting" do command "nesting", "Show nesting information." do
describe "Show nesting information." out = opts[:output]
nesting = opts[:nesting]
action do |opts| out.puts "Nesting status:"
out = opts[:output] out.puts "--"
nesting = opts[:nesting] nesting.each do |level, obj|
if level == 0
out.puts "Nesting status:" out.puts "#{level}. #{Pry.view(obj)} (Pry top level)"
out.puts "--"
nesting.each do |level, obj|
if level == 0
out.puts "#{level}. #{Pry.view(obj)} (Pry top level)"
else
out.puts "#{level}. #{Pry.view(obj)}"
end
end
end
end
command "status" do
describe "Show status information."
action do |opts|
out = opts[:output]
nesting = opts[:nesting]
target = opts[:target]
out.puts "Status:"
out.puts "--"
out.puts "Receiver: #{Pry.view(target.eval('self'))}"
out.puts "Nesting level: #{nesting.level}"
out.puts "Local variables: #{Pry.view(target.eval('local_variables'))}"
out.puts "Pry instance: #{Pry.active_instance}"
out.puts "Last result: #{Pry.view(Pry.last_result)}"
end
end
command "exit_all" do
describe "End all nested Pry sessions."
action { |opts| throw(:breakout, 0) }
end
command "ls" do
describe "Show the list of vars in the current scope."
action do |opts|
opts[:output].puts "#{opts[:target].eval('Pry.view(local_variables + instance_variables)')}"
end
end
command "cat" do
describe "Show output of <var>.inspect."
pattern /^cat\s+(.+)/
action do |opts|
out = opts[:output]
obj = opts[:captures].first
out.puts opts[:target].eval("#{obj}.inspect")
end
end
command "cd" do
pattern /^cd\s+(.+)/
describe "Start a Pry session on <var> (use `cd ..` to go back)"
action do |opts|
obj = opts[:captures].first
throw(:breakout, opts[:nesting].level) if obj == ".."
opts[:target].eval("#{obj}.pry")
end
end
command "show_doc" do
pattern /^show_doc\s*(.+)/
describe "Show the comments above <methname>"
action do |opts|
meth_name = opts[:captures].first
doc = opts[:target].eval("method(:#{meth_name})").comment
opts[:output].puts doc
end
end
command "show_idoc" do
pattern /^show_idoc\s*(.+)/
describe "Show the comments above instance method <methname>"
action do |opts|
meth_name = opts[:captures].first
doc = opts[:target].eval("instance_method(:#{meth_name})").comment
opts[:output].puts doc
end
end
command "show_method" do
pattern /^show_method\s*(.+)/
describe "Show sourcecode for method <methname>."
action do |opts|
meth_name = opts[:captures].first
doc = opts[:target].eval("method(:#{meth_name})").source
opts[:output].puts doc
end
end
command "show_imethod" do
pattern /^show_imethod\s*(.+)/
describe "Show sourcecode for instance method <methname>."
action do |opts|
meth_name = opts[:captures].first
doc = opts[:target].eval("instance_method(:#{meth_name})").source
opts[:output].puts doc
end
end
command "jump_to" do
pattern /^jump_to\s*(\d*)/
describe "Jump to a Pry session further up the stack, exiting all sessions below."
action do |opts|
break_level = opts[:captures].first.to_i
nesting = opts[:nesting]
case break_level
when nesting.level
opts[:output].puts "Already at nesting level #{nesting.level}"
when (0...nesting.level)
throw(:breakout, break_level + 1)
else else
max_nest_level = nesting.level - 1 out.puts "#{level}. #{Pry.view(obj)}"
opts[:output].puts "Invalid nest level. Must be between 0 and #{max_nest_level}. Got #{break_level}."
end end
end end
end end
command "ls_methods" do command "status", "Show status information." do
describe "List public methods defined on class of receiver." out = opts[:output]
nesting = opts[:nesting]
target = opts[:target]
action do |opts| out.puts "Status:"
opts[:output].puts "#{Pry.view(opts[:target].eval('public_methods(false)'))}" out.puts "--"
out.puts "Receiver: #{Pry.view(target.eval('self'))}"
out.puts "Nesting level: #{nesting.level}"
out.puts "Local variables: #{Pry.view(target.eval('local_variables'))}"
out.puts "Pry instance: #{Pry.active_instance}"
out.puts "Last result: #{Pry.view(Pry.last_result)}"
end
command "exit_all", "End all nested Pry sessions." do
throw(:breakout, 0)
end
command "ls", "Show the list of vars in the current scope." do
opts[:output].puts "#{opts[:target].eval('Pry.view(local_variables + instance_variables)')}"
end
command "cat", "Show output of <var>.inspect." do |obj|
out = opts[:output]
out.puts opts[:target].eval("#{obj}.inspect")
end
command "cd", "Start a Pry session on <var> (use `cd ..` to go back)" do |obj|
throw(:breakout, opts[:nesting].level) if obj == ".."
opts[:target].eval("#{obj}.pry")
end
command "show_doc", "Show the comments above <methname>" do |meth_name|
doc = opts[:target].eval("method(:#{meth_name})").comment
opts[:output].puts doc
end
command "show_idoc", "Show the comments above instance method <methname>" do |meth_name|
doc = opts[:target].eval("instance_method(:#{meth_name})").comment
opts[:output].puts doc
end
command "show_method", "Show sourcecode for method <methname>." do |meth_name|
doc = opts[:target].eval("method(:#{meth_name})").source
opts[:output].puts doc
end
command "show_imethod", "Show sourcecode for instance method <methname>." do |meth_name|
doc = opts[:target].eval("instance_method(:#{meth_name})").source
opts[:output].puts doc
end
command "jump_to", "Jump to a Pry session further up the stack, exiting all sessions below." do |break_level|
break_level = break_level.to_i
nesting = opts[:nesting]
case break_level
when nesting.level
opts[: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}."
end end
end end
command "ls_imethods" do command "ls_methods", "List public methods defined on class of receiver." do
describe "List public instance methods defined on class of receiver." opts[:output].puts "#{Pry.view(opts[:target].eval('public_methods(false)'))}"
action do |opts|
opts[:output].puts "#{Pry.view(opts[:target].eval('public_instance_methods(false)'))}"
end
end end
command ["exit", "quit", "back"] do command "ls_imethods", "List public instance methods defined on class of receiver." do
describe "End the current Pry session." opts[:output].puts "#{Pry.view(opts[:target].eval('public_instance_methods(false)'))}"
action do |opts| end
throw(:breakout, opts[:nesting].level)
end command ["exit", "quit", "back"], "End the current Pry session." do
throw(:breakout, opts[:nesting].level)
end end
end end
end end

View file

@ -85,7 +85,9 @@ class Pry
def self.reset_defaults def self.reset_defaults
@input = Readline @input = Readline
@output = $stdout @output = $stdout
@commands = Commands
# FIXME
@commands = Pry::Commands
@prompt = DEFAULT_PROMPT @prompt = DEFAULT_PROMPT
@print = DEFAULT_PRINT @print = DEFAULT_PRINT
@hooks = DEFAULT_HOOKS @hooks = DEFAULT_HOOKS

View file

@ -185,10 +185,11 @@ class Pry
pattern, action = commands.commands.find { |k, v| Array(k).any? { |a| a === val } } pattern, action = commands.commands.find { |k, v| Array(k).any? { |a| a === val } }
if pattern if pattern
last_match = Regexp.last_match captures = Regexp.last_match.captures
captures.compact!
options = { options = {
:captures => last_match ? last_match.captures : nil, :captures => captures,
:eval_string => eval_string, :eval_string => eval_string,
:target => target, :target => target,
:val => val, :val => val,
@ -197,7 +198,12 @@ class Pry
:command_info => commands.command_info :command_info => commands.command_info
} }
action.call(options) # because procs are defined in different places (e.g 'help' in CommandBase)
# we cannot simply use `commands.opts=...`
action_self = action.binding.eval('self')
action_self.opts = options
action.call(*captures)
val.clear val.clear
end end
end end

View file

@ -261,12 +261,11 @@ describe Pry do
end end
describe "commands" do describe "commands" do
it 'should set the commands default, and the default should be overridable' do it 'should set the commands default, and the default should be overridable' do
class Command0 < Pry::CommandBase class Command0 < Pry::CommandBase
command "hello" do command "hello" do
describe "" opts[:output].puts "hello world"
action { |opts| opts[:output].puts "hello world"; opts[:val].clear } opts[:val].clear
end end
end end
@ -277,9 +276,9 @@ describe Pry do
str_output.string.should =~ /hello world/ str_output.string.should =~ /hello world/
class Command1 < Pry::CommandBase class Command1 < Pry::CommandBase
command "goodbye" do command "goodbye", "" do
describe "" opts[:output].puts "goodbye world"
action { |opts| opts[:output].puts "goodbye world"; opts[:val].clear } opts[:val].clear
end end
end end
@ -294,9 +293,7 @@ describe Pry do
it 'should inherit "help" command from Pry::CommandBase' do it 'should inherit "help" command from Pry::CommandBase' do
class Command2 < Pry::CommandBase class Command2 < Pry::CommandBase
command "h" do |v| command "h", "h command" do
v.describe "h command"
v.action { }
end end
end end
@ -310,7 +307,6 @@ describe Pry do
it 'should inherit comands from Pry::Commands' do it 'should inherit comands from Pry::Commands' do
class Command3 < Pry::Commands class Command3 < Pry::Commands
command "v" do command "v" do
action {}
end end
end end

View file

@ -19,31 +19,13 @@ end
class CommandTester < Pry::CommandBase class CommandTester < Pry::CommandBase
command "command1" do command "command1", "command 1 test" do
describe "command 1 test" opts[:output].puts "command1"
action { |opts| opts[:output].puts "command1"; opts[:val].clear } opts[:val].clear
end end
command "command2" do command "command2", "command 2 test" do |arg|
describe "command 2 test" opts[:output].puts arg
pattern /command2\s*(.*)/ opts[:val].clear
action { |opts|
arg = opts[:captures].first
opts[:output].puts arg
opts[:val].clear
}
end end
# def commands
# @commands ||= {
# "command1" => proc { |opts| opts[:output].puts "command1"; opts[:val].clear },
# /command2\s*(.*)/ => proc do |opts|
# arg = opts[:captures].first
# opts[:output].puts arg
# opts[:val].clear
# end
# }
# end
# e
end end