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

now clearing :val rather than :eval_string in commands so that current expression context is not destroyed when running pry command. Also added !pry command to enter a pry session

This commit is contained in:
John Mair 2010-12-31 04:01:11 +13:00
parent 1e3539cfda
commit 42fe31e19e
4 changed files with 67 additions and 36 deletions

View file

@ -1,4 +1,11 @@
class Pry class Pry
# Default commands used by Pry.
# @notes
# If you plan to replace the default Commands class with a custom
# one then it must have a `commands` method that returns a Hash.
# The Hash should be set up so that the key is the command String
# (or Regexp)
class Commands class Commands
attr_accessor :out attr_accessor :out
@ -10,23 +17,28 @@ class Pry
@commands ||= { @commands ||= {
"!" => proc do |opts| "!" => proc do |opts|
out.puts "Refreshed REPL" out.puts "Refreshed REPL"
opts[:val].clear
opts[:eval_string].clear opts[:eval_string].clear
end, end,
"!pry" => proc do |opts|
Pry.start(opts[:target])
opts[:val].clear
end,
["exit_program", "quit_program"] => proc do ["exit_program", "quit_program"] => proc do
exit exit
end, end,
/^help\s*(.+)?/ => proc do |opts| /^help\s*(.+)?/ => proc do |opts|
param = opts[:captures].first param = opts[:captures].first
self.show_help(param) self.show_help(param)
opts[:eval_string].clear opts[:val].clear
end, end,
"nesting" => proc do |opts| "nesting" => proc do |opts|
self.show_nesting(opts[:nesting]) self.show_nesting(opts[:nesting])
opts[:eval_string].clear opts[:val].clear
end, end,
"status" => proc do |opts| "status" => proc do |opts|
self.show_status(opts[:nesting], opts[:target]) self.show_status(opts[:nesting], opts[:target])
opts[:eval_string].clear opts[:val].clear
end, end,
"exit_all" => proc do "exit_all" => proc do
throw(:breakout, 0) throw(:breakout, 0)
@ -36,39 +48,39 @@ class Pry
end, end,
"ls" => proc do |opts| "ls" => proc do |opts|
out.puts "#{opts[:target].eval('Pry.view(local_variables + instance_variables)')}" out.puts "#{opts[:target].eval('Pry.view(local_variables + instance_variables)')}"
opts[:eval_string].clear opts[:val].clear
end, end,
/^cat\s+(.+)/ => proc do |opts| /^cat\s+(.+)/ => proc do |opts|
obj = opts[:captures].first obj = opts[:captures].first
out.puts opts[:target].eval("#{obj}.inspect") out.puts opts[:target].eval("#{obj}.inspect")
opts[:eval_string].clear opts[:val].clear
end, end,
/^cd\s+(.+)/ => proc do |opts| /^cd\s+(.+)/ => proc do |opts|
obj = opts[:captures].first obj = opts[:captures].first
opts[:target].eval("#{obj}.pry") opts[:target].eval("#{obj}.pry")
opts[:eval_string].clear opts[:val].clear
end, end,
/^show_doc\s*(.+)/ => proc do |opts| /^show_doc\s*(.+)/ => proc do |opts|
meth_name = opts[:captures].first meth_name = opts[:captures].first
doc = opts[:target].eval("method(:#{meth_name})").comment doc = opts[:target].eval("method(:#{meth_name})").comment
out.puts doc out.puts doc
opts[:eval_string].clear opts[:val].clear
end, end,
/^show_idoc\s*(.+)/ => proc do |opts| /^show_idoc\s*(.+)/ => proc do |opts|
meth_name = opts[:captures].first meth_name = opts[:captures].first
doc = opts[:target].eval("instance_method(:#{meth_name})").comment doc = opts[:target].eval("instance_method(:#{meth_name})").comment
opts[:eval_string].clear opts[:val].clear
end, end,
/^show_method\s*(.+)/ => proc do |opts| /^show_method\s*(.+)/ => proc do |opts|
meth_name = opts[:captures].first meth_name = opts[:captures].first
code = opts[:target].eval("method(:#{meth_name})").source code = opts[:target].eval("method(:#{meth_name})").source
out.puts code out.puts code
opts[:eval_string].clear opts[:val].clear
end, end,
/^show_imethod\s*(.+)/ => proc do |opts| /^show_imethod\s*(.+)/ => proc do |opts|
meth_name = opts[:captures].first meth_name = opts[:captures].first
code = opts[:target].eval("instance_method(:#{meth_name})").source code = opts[:target].eval("instance_method(:#{meth_name})").source
opts[:eval_string].clear opts[:val].clear
end, end,
/^jump_to\s*(\d*)/ => proc do |opts| /^jump_to\s*(\d*)/ => proc do |opts|
break_level = opts[:captures].first.to_i break_level = opts[:captures].first.to_i
@ -77,22 +89,22 @@ class Pry
case break_level case break_level
when nesting.level when nesting.level
out.puts "Already at nesting level #{nesting.level}" out.puts "Already at nesting level #{nesting.level}"
opts[:eval_string].clear opts[:val].clear
when (0...nesting.level) when (0...nesting.level)
throw(:breakout, break_level + 1) throw(:breakout, break_level + 1)
else else
max_nest_level = nesting.level - 1 max_nest_level = nesting.level - 1
out.puts "Invalid nest level. Must be between 0 and #{max_nest_level}. Got #{break_level}." out.puts "Invalid nest level. Must be between 0 and #{max_nest_level}. Got #{break_level}."
opts[:eval_string].clear opts[:val].clear
end end
end, end,
"ls_methods" => proc do |opts| "ls_methods" => proc do |opts|
out.puts "#{Pry.view(opts[:target].eval('public_methods(false)'))}" out.puts "#{Pry.view(opts[:target].eval('public_methods(false)'))}"
opts[:eval_string].clear opts[:val].clear
end, end,
"ls_imethods" => proc do |opts| "ls_imethods" => proc do |opts|
out.puts "#{Pry.view(opts[:target].eval('public_instance_methods(false)'))}" out.puts "#{Pry.view(opts[:target].eval('public_instance_methods(false)'))}"
opts[:eval_string].clear opts[:val].clear
end end
} }
end end
@ -100,6 +112,7 @@ class Pry
def command_info def command_info
@command_info ||= { @command_info ||= {
"!" => "Refresh the REPL.", "!" => "Refresh the REPL.",
"!pry" => "Start a Pry session on current self; this even works mid-expression.",
["exit_program", "quit_program"] => "end the current program.", ["exit_program", "quit_program"] => "end the current program.",
"help" => "This menu.", "help" => "This menu.",
"nesting" => "Show nesting information.", "nesting" => "Show nesting information.",

View file

@ -1,9 +1,28 @@
class Pry class Pry
module ObjectExtensions module ObjectExtensions
# Start a Pry REPL.
# This method differs from `Pry.start` in that it does not
# support an options hash. Also, when no parameter is provided, the Pry
# session will start on the implied receiver rather than on
# top-level (as in the case of `Pry.start`).
# It has two forms of invocation. In the first form no parameter
# should be provided and it will start a pry session on the
# receiver. In the second form it should be invoked without an
# explicit receiver and one parameter; this will start a Pry
# session on the parameter.
# @param [Object, Binding] target The receiver of the Pry session.
# @example First form
# "dummy".pry
# @example Second form
# pry "dummy"
# @example Start a Pry session on current self (whatever that is)
# pry
def pry(target=self) def pry(target=self)
Pry.start(target) Pry.start(target)
end end
# Return a binding object for the receiver.
def __binding__ def __binding__
if is_a?(Module) if is_a?(Module)
return class_eval "binding" return class_eval "binding"

View file

@ -19,45 +19,39 @@ class Pry
# @return [Pry] The active Pry instance. # @return [Pry] The active Pry instance.
attr_accessor :active_instance attr_accessor :active_instance
# Set/Get the object to use for input by default by all Pry instances. # Get/Set the object to use for input by default by all Pry instances.
# (see input.rb)
# @return [#read] The object to use for input by default by all # @return [#read] The object to use for input by default by all
# Pry instances. # Pry instances.
attr_accessor :input attr_accessor :input
# Set/Get the object to use for output by default by all Pry instances. # Get/Set the object to use for output by default by all Pry instances.
# (see: output.rb)
# @return [#puts] The object to use for output by default by all # @return [#puts] The object to use for output by default by all
# Pry instances. # Pry instances.
attr_accessor :output attr_accessor :output
# Set/Get the object to use for commands by default by all Pry instances. # Get/Set the object to use for commands by default by all Pry instances.
# (see commands.rb)
# @return [#commands] The object to use for commands by default by all # @return [#commands] The object to use for commands by default by all
# Pry instances. # Pry instances.
attr_accessor :commands attr_accessor :commands
# Set/Get the Proc to use for printing by default by all Pry # Get/Set the Proc to use for printing by default by all Pry
# instances. # instances.
# This is the 'print' componenent of the REPL. # This is the 'print' component of the REPL.
# (see print.rb)
# @return [Proc] The Proc to use for printing by default by all # @return [Proc] The Proc to use for printing by default by all
# Pry instances. # Pry instances.
attr_accessor :print attr_accessor :print
# Set/Get the Hash that defines Pry hooks used by default by all Pry # Get/Set the Hash that defines Pry hooks used by default by all Pry
# instances. # instances.
# (see print.rb)
# @return [Hash] The hooks used by default by all Pry instances. # @return [Hash] The hooks used by default by all Pry instances.
# @example # @example
# Pry.hooks :before_session => proc { puts "hello" }, # Pry.hooks :before_session => proc { puts "hello" },
# :after_session => proc { puts "goodbye" } # :after_session => proc { puts "goodbye" }
attr_accessor :hooks attr_accessor :hooks
# Set/Get the array of Procs to be used for the prompts by default by # Get/Set the array of Procs to be used for the prompts by default by
# all Pry instances. # all Pry instances.
# (see prompts.rb)
# @return [Array<Proc>] The array of Procs to be used for the # @return [Array<Proc>] The array of Procs to be used for the
# prompts by default by all Pry instances. # prompts by default by all Pry instances.
attr_accessor :default_prompt attr_accessor :default_prompt
@ -65,7 +59,8 @@ class Pry
# Start a Pry REPL. # Start a Pry REPL.
# @param [Object, Binding] target The receiver of the Pry session # @param [Object, Binding] target The receiver of the Pry session
# @param options (see Pry#initialize) # @param [Hash] options
# @option options (see Pry#initialize)
# @example # @example
# Pry.start(Object.new, :input => MyInput.new) # Pry.start(Object.new, :input => MyInput.new)
def self.start(target=TOPLEVEL_BINDING, options={}) def self.start(target=TOPLEVEL_BINDING, options={})

View file

@ -14,11 +14,14 @@ class Pry
# commands. (see commands.rb) # commands. (see commands.rb)
# @option options [Hash] :hooks The defined hook Procs (see hooks.rb) # @option options [Hash] :hooks The defined hook Procs (see hooks.rb)
# @option options [Array<Proc>] :default_prompt The array of Procs # @option options [Array<Proc>] :default_prompt The array of Procs
# to use for the prompts. # to use for the prompts. (see prompts.rb)
# @option options [Proc] :print The Proc to use for the 'print' componenent of the REPL # @option options [Proc] :print The Proc to use for the 'print'
# component of the REPL. (see print.rb)
def initialize(options={}) def initialize(options={})
default_options = ConfigOptions.each_with_object({}) { |v, h| h[v] = Pry.send(v) } h = {}
ConfigOptions.each { |v| h[v] = Pry.send(v) }
default_options = h
default_options.merge!(options) default_options.merge!(options)
ConfigOptions.each do |key| ConfigOptions.each do |key|
@ -68,7 +71,7 @@ class Pry
target.eval("_ = Pry.last_result") target.eval("_ = Pry.last_result")
break_level = catch(:breakout) do break_level = catch(:breakout) do
nesting << [nesting.size, target_self] nesting.push [nesting.size, target_self]
loop do loop do
rep(target) rep(target)
end end
@ -128,8 +131,8 @@ class Pry
eval_string = "" eval_string = ""
loop do loop do
val = input.read(prompt(eval_string, target)) val = input.read(prompt(eval_string, target))
eval_string << "#{val.chomp}\n"
process_commands(val, eval_string, target) process_commands(val, eval_string, target)
eval_string << "#{val.chomp}\n"
break eval_string if valid_expression?(eval_string) break eval_string if valid_expression?(eval_string)
end end
@ -139,7 +142,7 @@ class Pry
# prior to Ruby expressions. # prior to Ruby expressions.
# Commands can be modified/configured by the user: see `Pry::Commands` # Commands can be modified/configured by the user: see `Pry::Commands`
# This method should not need to be invoked directly - it is called # This method should not need to be invoked directly - it is called
# by `Pry#r` # by `Pry#r`.
# @param [String] val The current line of input. # @param [String] val The current line of input.
# @param [String] eval_string The cumulative lines of input for # @param [String] eval_string The cumulative lines of input for
# multi-line input. # multi-line input.
@ -150,8 +153,10 @@ 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
options = { options = {
:captures => $~ ? $~.captures : nil, :captures => last_match ? last_match.captures : nil,
:eval_string => eval_string, :eval_string => eval_string,
:target => target, :target => target,
:val => val, :val => val,
@ -212,7 +217,6 @@ class Pry
end end
end end
# Return a `Binding` object for `target` or return `target` if it is # Return a `Binding` object for `target` or return `target` if it is
# already a `Binding`. # already a `Binding`.
# In the case where `target` is top-level then return `TOPLEVEL_BINDING` # In the case where `target` is top-level then return `TOPLEVEL_BINDING`