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:
parent
500456032c
commit
f45e8bfbd0
7 changed files with 147 additions and 257 deletions
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
16
test/test.rb
16
test/test.rb
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue