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

added Pry.sessions and Pry#parent, for more info on pry sessions. Also completed more documentation

This commit is contained in:
John Mair 2011-01-14 01:35:46 +11:00
parent ead507210d
commit ce3532e7ca
3 changed files with 112 additions and 42 deletions

View file

@ -16,7 +16,7 @@ commands such as `show_method` and `jump_to`
* Read the [documentation](http://rdoc.info/github/banister/pry/master/file/README.markdown) * Read the [documentation](http://rdoc.info/github/banister/pry/master/file/README.markdown)
* See the [source code](http://github.com/banister/pry) * See the [source code](http://github.com/banister/pry)
Example: Interacting with an object at runtime Example: Interacting with an object at runtime
--------------------------------------- ---------------------------------------
With the `Object#pry` method we can pry (open an irb-like session) on With the `Object#pry` method we can pry (open an irb-like session) on
@ -24,7 +24,7 @@ an object. In the example below we open a Pry session for the `Test` class and e
an instance variable. The current thread is halted for the duration of the session. an instance variable. The current thread is halted for the duration of the session.
require 'pry' require 'pry'
class Test class Test
def self.hello() "hello world" end def self.hello() "hello world" end
end end
@ -54,13 +54,13 @@ effect:
You can also use the `Pry.start(obj)` or `pry(obj)` syntax to start a pry session on You can also use the `Pry.start(obj)` or `pry(obj)` syntax to start a pry session on
`obj`. e.g `obj`. e.g
Pry.start 5 Pry.start(5)
Beginning Pry session for 5 Beginning Pry session for 5
pry(5)> pry(5)>
OR OR
pry 6 pry(6)
beginning Pry session for 6 beginning Pry session for 6
pry(6)> pry(6)>
@ -103,7 +103,7 @@ command. E.g
2. 100 2. 100
3. "friend" 3. "friend"
=> nil => nil
We can then jump back to any of the previous nesting levels by using We can then jump back to any of the previous nesting levels by using
the `jump_to` command: the `jump_to` command:
@ -113,7 +113,7 @@ the `jump_to` command:
=> 100 => 100
pry(Hello):1> pry(Hello):1>
If we just want to go back one level of nesting we can of course If we just want to go back one level of nesting we can of course
use the `quit` or `exit` or `back` commands. use the `quit` or `exit` or `back` commands.
To break out of all levels of Pry nesting and return immediately to the To break out of all levels of Pry nesting and return immediately to the
@ -125,7 +125,7 @@ calling process use `exit_all`:
Ending Pry session for Hello Ending Pry session for Hello
Ending Pry session for main Ending Pry session for main
=> main => main
# program resumes here # program resumes here
Features and limitations Features and limitations
@ -167,7 +167,7 @@ invoke any of these methods directly depending on exactly what aspect of the fun
see [ripl](https://github.com/cldwalker/ripl) see [ripl](https://github.com/cldwalker/ripl)
* Pry's `show_method` and `show_doc` commands do not work * Pry's `show_method` and `show_doc` commands do not work
in Ruby 1.8. in Ruby 1.8.
Commands Commands
----------- -----------
@ -196,7 +196,7 @@ that is a hash of configuration options (discussed further, below).
* If, for some reason you do not want to 'loop' then use `Pry.new.rep()`; it * If, for some reason you do not want to 'loop' then use `Pry.new.rep()`; it
only performs the Read-Eval-Print section of the REPL - it ends the only performs the Read-Eval-Print section of the REPL - it ends the
session after just one line of input. It takes the same parameters as session after just one line of input. It takes the same parameters as
`Pry#repl()` `Pry#repl()`
* Likewise `Pry#re()` only performs the Read-Eval section of the REPL, * Likewise `Pry#re()` only performs the Read-Eval section of the REPL,
it returns the result of the evaluation or an Exception object in it returns the result of the evaluation or an Exception object in
case of error. It also takes the same parameters as `Pry#repl()` case of error. It also takes the same parameters as `Pry#repl()`
@ -262,8 +262,8 @@ are:
Local customization (applied to a single Pry session) is done by Local customization (applied to a single Pry session) is done by
passing config hash options to `Pry.start()` or to `Pry.new()`; also the passing config hash options to `Pry.start()` or to `Pry.new()`; also the
same accessors as described above for the `Pry` class also exist for a same accessors as described above for the `Pry` class exist for a
Pry instance. Pry instance so that customization can occur during runtime.
### Input: ### Input:
@ -278,7 +278,7 @@ this input by default:
Pry.input = StringIO.new("@x = 10\nexit") Pry.input = StringIO.new("@x = 10\nexit")
Object.pry Object.pry
Object.instance_variable_get(:@x) #=> 10 Object.instance_variable_get(:@x) #=> 10
The above will execute the code in the `StringIO` The above will execute the code in the `StringIO`
@ -291,19 +291,26 @@ session will hang as it loops indefinitely awaiting new input.
The settings for a specific session override the global settings The settings for a specific session override the global settings
(discussed above). There are two ways to set input for a specific pry session: At the (discussed above). There are two ways to set input for a specific pry session: At the
point the session is started, or within the session itself: point the session is started, or within the session itself (at runtime):
Here is the first case: ##### At session start
Pry.start(Object, :input => StringIO.new("@x = 10\nexit")) Pry.start(Object, :input => StringIO.new("@x = 10\nexit"))
Object.instance_variable_get(:@x) #=> 10 Object.instance_variable_get(:@x) #=> 10
##### At runtime
If you want to set the input object within the session itself you use If you want to set the input object within the session itself you use
the special `_pry_` local variable which represents the Pry instance the special `_pry_` local variable which represents the Pry instance
managing the current session; inside the session we type: managing the current session; inside the session we type:
_pry_.input = StringIO.new("@x = 10\nexit") _pry_.input = StringIO.new("@x = 10\nexit")
Note we can also set the input object for the parent Pry session (if
the current session is nested) like so:
_pry_.parent.input = StringIO.new("@x = 10\nexit")
### Output ### Output
For output Pry accepts any object that implements the `puts` method. This For output Pry accepts any object that implements the `puts` method. This
@ -317,27 +324,27 @@ this output by default:
Pry.output = StringIO.new Pry.output = StringIO.new
Object.pry Object.pry
Object.instance_variable_get(:@x) #=> 10 Object.instance_variable_get(:@x) #=> 10
#### Example: Setting output for a specific session #### Example: Setting output for a specific session
As per Input, given above, we set the local output as follows: As per Input, given above, we set the local output as follows:
Here is the first case: ##### At session start
Pry.start(Object, :output => StringIO.new("@x = 10\nexit")) Pry.start(Object, :output => StringIO.new("@x = 10\nexit"))
Object.instance_variable_get(:@x) #=> 10 Object.instance_variable_get(:@x) #=> 10
And to change output from within the session itself: ##### At runtime
_pry_.output = StringIO.new _pry_.output = StringIO.new
### Commands ### Commands
Pry commands are not methods; they are commands that are intercepted Pry commands are not methods; they are commands that are intercepted
and executed before a Ruby eval takes place. Pry comes with a default and executed before a Ruby eval takes place. Pry comes with a default
command set, but these commands can be augmented or overriden by command set (`Pry::Commands`), but these commands can be augmented or overriden by
user-specified ones. user-specified ones.
A valid Pry command object must inherit from A valid Pry command object must inherit from
@ -359,7 +366,7 @@ A valid Pry command object must inherit from
Then inside a pry session: Then inside a pry session:
(pry)> hello john pry(main)> hello john
hello john! hello john!
=> nil => nil
@ -367,12 +374,12 @@ Then inside a pry session:
As in the case of `input` and `output`: As in the case of `input` and `output`:
At session start: ##### At session start:
Pry.start(self, :commands => MyCommands) Pry.start(self, :commands => MyCommands)
From within the session: ##### At runtime:
_pry_.commands = MyCommands _pry_.commands = MyCommands
#### The command API #### The command API
@ -415,8 +422,51 @@ 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 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. `help` with the command name will just return the description of that specific command.
### Hooks
Currently Pry supports just two hooks: `before_session` and
`after_session`. These hooks are invoked before a Pry session starts
and after a session ends respectively. The default hooks used are
stored in the `Pry::DEFAULT_HOOKS` and just output the text `"Beginning
Pry session for <obj>"` and `"Ending Pry session for <obj>"`.
#### Example: Setting global hooks
All subsequent Pry instances will use these hooks as default:
Pry.hooks = {
:before_session => proc { |out, obj| out.puts "Opened #{obj}" },
:after_session => proc { |out, obj| out.puts "Closed #{obj}" }
}
5.pry
Inside the session:
Opened 5
pry(5)> exit
Closed 5
Note that the `before_session` and `after_session` procs receive the
current session's output object and session receiver as parameters.
#### Example: Setting hooks for a specific session
Like all the other customization options, the global default (as
explained above) can be overriden for a specific session, either at
session start or during runtime.
##### At session start
Pry.start(self, :hooks => { :before_session => proc { puts "hello world!" },
:after_session => proc { puts "goodbye world!" }
})
##### At runtime
_pry_.hooks = { :before_session => proc { puts "puts "hello world!" } }
Contact Contact
------- -------

View file

@ -20,7 +20,7 @@ class Pry
# This method should not need to be accessed directly. # This method should not need to be accessed directly.
# @return [Pry] The active Pry instance. # @return [Pry] The active Pry instance.
attr_accessor :active_instance attr_accessor :active_instance
# Get/Set 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.
# @return [#readline] The object to use for input by default by all # @return [#readline] The object to use for input by default by all
# Pry instances. # Pry instances.
@ -57,6 +57,7 @@ class Pry
# prompts by default by all Pry instances. # prompts by default by all Pry instances.
attr_accessor :prompt attr_accessor :prompt
end end
# 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 [Hash] options # @param [Hash] options
@ -96,4 +97,11 @@ class Pry
def @nesting.level def @nesting.level
last.is_a?(Array) ? last.first : nil last.is_a?(Array) ? last.first : nil
end end
# Return all active Pry sessions.
# @return [Array<Pry>] Active Pry sessions.
def self.sessions
# last element in nesting array is the pry instance
nesting.map(&:last)
end
end end

View file

@ -12,7 +12,7 @@ class Pry
# @param [Hash] options The optional configuration parameters. # @param [Hash] options The optional configuration parameters.
# @option options [#readline] :input The object to use for input. (see input.rb) # @option options [#readline] :input The object to use for input. (see input.rb)
# @option options [#puts] :output The object to use for output. (see output.rb) # @option options [#puts] :output The object to use for output. (see output.rb)
# @option options [Pry::CommandBase] :commands The object to use for # @option options [Pry::CommandBase] :commands The object to use for
# 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
@ -45,13 +45,25 @@ class Pry
self.class.nesting = v self.class.nesting = v
end end
# Return parent of current Pry session.
# @return [Pry] The parent of the current Pry session.
def parent
idx = Pry.sessions.index(self)
if idx > 0
Pry.sessions[idx - 1]
else
nil
end
end
# Execute the hook `hook_name`, if it is defined. # Execute the hook `hook_name`, if it is defined.
# @param [Symbol] hook_name The hook to execute # @param [Symbol] hook_name The hook to execute
# @param [Array] args The arguments to pass to the hook. # @param [Array] args The arguments to pass to the hook.
def exec_hook(hook_name, *args, &block) def exec_hook(hook_name, *args, &block)
hooks[hook_name].call(*args, &block) if hooks[hook_name] hooks[hook_name].call(*args, &block) if hooks[hook_name]
end end
# Start a read-eval-print-loop. # Start a read-eval-print-loop.
# If no parameter is given, default to top-level (main). # If no parameter is given, default to top-level (main).
# @param [Object, Binding] target The receiver of the Pry session # @param [Object, Binding] target The receiver of the Pry session
@ -63,7 +75,7 @@ class Pry
target_self = target.eval('self') target_self = target.eval('self')
exec_hook :before_session, output, target_self exec_hook :before_session, output, target_self
# cannot rely on nesting.level as # cannot rely on nesting.level as
# nesting.level changes with new sessions # nesting.level changes with new sessions
nesting_level = nesting.size nesting_level = nesting.size
@ -73,26 +85,26 @@ class Pry
# Make sure special locals exist # Make sure special locals exist
target.eval("_pry_ = Pry.active_instance") target.eval("_pry_ = Pry.active_instance")
target.eval("_ = Pry.last_result") target.eval("_ = Pry.last_result")
break_level = catch(:breakout) do break_level = catch(:breakout) do
nesting.push [nesting.size, target_self] nesting.push [nesting.size, target_self, self]
loop do loop do
rep(target) rep(target)
end end
end end
nesting.pop nesting.pop
exec_hook :after_session, output, target_self exec_hook :after_session, output, target_self
# keep throwing until we reach the desired nesting level # keep throwing until we reach the desired nesting level
if nesting_level != break_level if nesting_level != break_level
throw :breakout, break_level throw :breakout, break_level
end end
target_self target_self
end end
# Perform a read-eval-print. # Perform a read-eval-print.
# If no parameter is given, default to top-level (main). # If no parameter is given, default to top-level (main).
# @param [Object, Binding] target The receiver of the read-eval-print # @param [Object, Binding] target The receiver of the read-eval-print
@ -152,11 +164,11 @@ class Pry
process_commands(val, eval_string, target) process_commands(val, eval_string, target)
eval_string << "#{val}\n" eval_string << "#{val}\n"
break eval_string if valid_expression?(eval_string) break eval_string if valid_expression?(eval_string)
end end
end end
# Process Pry commands. Pry commands are not Ruby methods and are evaluated # Process Pry commands. Pry commands are not Ruby methods and are evaluated
# 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`
@ -174,7 +186,7 @@ class Pry
if pattern if pattern
last_match = Regexp.last_match last_match = Regexp.last_match
options = { options = {
:captures => last_match ? last_match.captures : nil, :captures => last_match ? last_match.captures : nil,
:eval_string => eval_string, :eval_string => eval_string,
@ -208,7 +220,7 @@ class Pry
input.readline input.readline
end end
end end
end end
# Returns the appropriate prompt to use. # Returns the appropriate prompt to use.
# This method should not need to be invoked directly. # This method should not need to be invoked directly.
@ -217,7 +229,7 @@ class Pry
# @param [Object] target_self The receiver of the Pry session. # @param [Object] target_self The receiver of the Pry session.
# @return [String] The prompt. # @return [String] The prompt.
def select_prompt(first_line, target_self) def select_prompt(first_line, target_self)
if first_line if first_line
Array(prompt).first.call(target_self, nesting.level) Array(prompt).first.call(target_self, nesting.level)
else else
@ -238,10 +250,10 @@ class Pry
def valid_expression?(code) def valid_expression?(code)
!!Ripper::SexpBuilder.new(code).parse !!Ripper::SexpBuilder.new(code).parse
end end
else else
require 'ruby_parser' require 'ruby_parser'
# Determine if a string of code is a valid Ruby expression. # Determine if a string of code is a valid Ruby expression.
# Ruby 1.9 uses Ripper, Ruby 1.8 uses RubyParser. # Ruby 1.9 uses Ripper, Ruby 1.8 uses RubyParser.
# @param [String] code The code to validate. # @param [String] code The code to validate.
@ -257,7 +269,7 @@ class Pry
true true
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`