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

changed get_prompt to select_prompt

This commit is contained in:
John Mair 2011-01-10 00:51:45 +13:00
parent 878ca414d7
commit 70bc1222e2
8 changed files with 197 additions and 128 deletions

7
.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile
*.so
*.o
*.def
doc/
pkg/
.yardoc/

View file

@ -18,7 +18,7 @@ commands such as `show_method` and `jump_to`
Example: Interacting with an object at runtime
---------------------------------------
With the `Pry.start()` method we can pry (open an irb-like session) on
With the `Object#pry` method we can pry (open an irb-like session) on
an object. In the example below we open a Pry session for the `Test` class and execute a method and add
an instance variable. The current thread is halted for the duration of the session.
@ -28,7 +28,7 @@ an instance variable. The current thread is halted for the duration of the sessi
def self.hello() "hello world" end
end
Pry.start(Test)
Test.pry
# Pry session begins on stdin
Beginning Pry session for Test
@ -50,10 +50,10 @@ effect:
#### Alternative Syntax
You can also use the `obj.pry` 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
5.pry
Pry.start 5
Beginning Pry session for 5
pry(5)>
@ -62,7 +62,7 @@ OR
pry 6
beginning Pry session for 6
pry(6)>
Example: Pry sessions can nest arbitrarily deep so we can pry on objects inside objects:
----------------------------------------------------------------------------------------
@ -76,11 +76,11 @@ an instance variable inside that class:
pry(main)* @x = 20
pry(main)* end
=> 20
pry(main)> Pry.start Hello
pry(main)> Hello.pry
Beginning Pry session for Hello
pry(Hello):1> instance_variables
=> [:@x]
pry(Hello):1> Pry.start @x
pry(Hello):1> @x.pry
Beginning Pry session for 20
pry(20:2)> self + 10
=> 30
@ -143,8 +143,9 @@ end.
* Pry can be invoked at any time and on any object in the running program.
* Pry sessions can nest arbitrarily deeply -- to go back one level of nesting type 'exit' or 'quit' or 'back'
* Use `_` to recover last result.
* Use `_pry_` to reference the Pry instance managing the current session.
* Pry has multi-line support built in.
* Pry has unique commands not found in any other REPL: `show_method`, `show_doc`
* Pry has special commands not found in many other Ruby REPLs: `show_method`, `show_doc`
`jump_to`, `ls`, `cd`, `cat`
* Pry gives good control over nested sessions (important when exploring complicated runtime state)
* Pry is not based on the IRB codebase.
@ -173,7 +174,22 @@ Commands
receives as a parameter. In the case of no parameter it operates on
top-level (main). It can receive any object or a `Binding`
object as parameter. `Pry.start()` is implemented as `Pry.new.repl()`
* `obj.pry` and `pry(obj)` may also be used as alternative syntax to `Pry.start(obj)`
* `obj.pry` and `pry(obj)` may also be used as alternative syntax to
`Pry.start(obj)`.
However there are some differences. `obj.pry` opens
a Pry session on the receiver whereas `Pry.start` (with no parameter)
will start a Pry session on top-level. The other form of the `pry`
method: `pry(obj)` will also start a Pry session on its parameter.
The `pry` method invoked by itself, with no explict receiver and no
parameter will start a Pry session on the implied receiver. It is
perhaps more useful to invoke it in this form `pry(binding)` or
`binding.pry` so as to get access to locals in the current context.
Another difference is that `Pry.start()` accepts a second parameter
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
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
@ -202,8 +218,8 @@ If you want to access a method of the same name, prefix the invocation by whites
are nested sessions).
* `ls` returns a list of local variables and instance variables in the
current scope
* `cat <var>` calls `inspect` on `<var>`
* `cd <var>` starts a `Pry` session on the variable <var>. E.g `cd @x`
* `cat <var>` Calls `inspect` on `<var>`
* `cd <var>` Starts a `Pry` session on the variable <var>. E.g `cd @x`
* `show_method <methname>` Displays the sourcecode for the method
<methname>. E.g `show_method hello`
* `show_imethod <methname>` Displays the sourcecode for the
@ -213,8 +229,10 @@ If you want to access a method of the same name, prefix the invocation by whites
method `<methname>`
* `exit_program` or `quit_program` will end the currently running
program.
* `nesting` shows Pry nesting information.
* `jump_to <nest_level>` unwinds the Pry stack (nesting level) until the appropriate nesting level is reached
* `nesting` Shows Pry nesting information.
* `!pry` Starts a Pry session on the implied receiver; this can be
used in the middle of an expression in multi-line input.
* `jump_to <nest_level>` Unwinds the Pry stack (nesting level) until the appropriate nesting level is reached
-- as per the output of `nesting`
* `exit_all` breaks out of all Pry nesting levels and returns to the
calling process.
@ -222,6 +240,33 @@ If you want to access a method of the same name, prefix the invocation by whites
current one with `obj` as the receiver of the new session. Very useful
when exploring large or complicated runtime state.
Customizing Pry
---------------
Pry supports customization of the input, the output, the commands,
the hooks, the prompt, and 'print' (the "P" in REPL).
Global customization, which applies to all Pry sessions, is done
through invoking class accessors on the `Pry` class, the accessors
are:
* `Pry.input=`
* `Pry.output=`
* `Pry.commands=`
* `Pry.hooks=`
* `Pry.prompt=`
* `Pry.print=`
Local customization (applied to a single Pry session) is done by
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
Pry instance.
### Input:
Contact
-------

View file

@ -1,22 +1,60 @@
require 'readline'
class Pry
# default input class - uses Readline.
class Input
trap('INT') { exit }
def read(prompt)
def readline(prompt)
Readline.readline(prompt, true)
end
end
# read from any IO-alike
class IOInput
def initialize(io)
@io = io
end
def readline
@io.readline
end
def close
@io.close
end
end
# file input class
class FileInput
def initialize(file, line = 1)
@f = File.open(file)
(line - 1).times { @f.readline }
end
def read(prompt)
def readline(prompt)
@f.readline
end
def close
@f.close
end
end
# preset input class
class PresetInput
def initialize(*actions)
@orig_actions = actions.dup
@actions = actions
end
def readline(*)
@actions.shift
end
def rewind
@actions = @orig_actions.dup
end
end
end

View file

@ -1,4 +1,6 @@
class Pry
# default output class - just writes to STDOUT
class Output
attr_reader :out
@ -11,8 +13,8 @@ class Pry
end
end
# null output class - doesn't write anywwhere.
class NullOutput
def puts(*) end
end
end

View file

@ -81,8 +81,8 @@ class Pry
# Set all the configurable options back to their default values
def self.reset_defaults
@input = Input.new
@output = Output.new
@input = Readline
@output = $stdout
@commands = Commands.new
@prompt = DEFAULT_PROMPT
@print = DEFAULT_PRINT

View file

@ -138,9 +138,21 @@ class Pry
target = binding_for(target)
eval_string = ""
loop do
val = input.read(get_prompt(eval_string.empty?, target.eval('self')))
val = if input == Readline
input.readline(select_prompt(eval_string.empty?, target.eval('self')), true)
else
if input.method(:readline).arity == 1
input.readline(select_prompt(eval_string.empty?, target.eval('self')))
else
input.readline
end
end
val.chomp!
process_commands(val, eval_string, target)
eval_string << "#{val.chomp}\n"
eval_string << "#{val}\n"
break eval_string if valid_expression?(eval_string)
end
@ -154,9 +166,9 @@ class Pry
# @param [String] val The current line of input.
# @param [String] eval_string The cumulative lines of input for
# multi-line input.
# @param [Object] target The receiver of the commands.
# @param [Binding] target The receiver of the commands.
def process_commands(val, eval_string, target)
def eval_string.clear() replace("") end
def val.clear() replace("") end
pattern, action = commands.commands.find { |k, v| Array(k).any? { |a| a === val } }
@ -182,7 +194,7 @@ class Pry
# (and not multi-line input).
# @param [Object] target_self The receiver of the Pry session.
# @return [String] The prompt.
def get_prompt(first_line, target_self)
def select_prompt(first_line, target_self)
if first_line
Array(prompt).first.call(target_self, nesting.level)

View file

@ -68,8 +68,7 @@ describe Pry do
o = Object.new
pry_tester = Pry.new(:input => input, :output => Pry::NullOutput.new)
pry_tester.repl(o)
pry_tester = Pry.start(o, :input => input, :output => Pry::NullOutput.new)
o.instance_variable_get(:@x).should == 10
end
@ -79,8 +78,7 @@ describe Pry do
str_output = StringIO.new
o = Object.new
pry_tester = Pry.new(:input => input, :output => Pry::Output.new(str_output))
pry_tester.repl(o)
pry_tester = Pry.start(o, :input => input, :output => Pry::Output.new(str_output))
str_output.string.should =~ /Beginning.*#{o}/
str_output.string.should =~ /Ending.*#{o}/
end
@ -95,8 +93,7 @@ describe Pry do
o = Object.new
pry_tester = Pry.new
pry_tester.repl(o)
pry_tester = o.pry
str_output.string.should =~ /nest:3/
Pry.input = Pry::Input.new
@ -134,7 +131,55 @@ describe Pry do
end
end
describe "Object#pry" do
after do
Pry.reset_defaults
end
it "should start a pry session on the receiver (first form)" do
Pry.input = InputTester.new("self", "exit")
str_output = StringIO.new
Pry.output = Pry::Output.new(str_output)
20.pry
str_output.string.should =~ /20/
end
it "should start a pry session on the receiver (second form)" do
Pry.input = InputTester.new("self", "exit")
str_output = StringIO.new
Pry.output = Pry::Output.new(str_output)
pry 20
str_output.string.should =~ /20/
end
it "should error if more than one argument is passed to Object#pry" do
lambda { pry(20, :input => Pry::Input.new) }.should.raise ArgumentError
end
end
describe "Pry#binding_for" do
it 'should return TOPLEVEL_BINDING if parameter self is main' do
_main_ = lambda { TOPLEVEL_BINDING.eval('self') }
Pry.new.binding_for(_main_.call).is_a?(Binding).should == true
Pry.new.binding_for(_main_.call).should == TOPLEVEL_BINDING
Pry.new.binding_for(_main_.call).should == Pry.new.binding_for(_main_.call)
end
end
describe "test Pry defaults" do
after do
Pry.reset_defaults
end
it 'should set the input default, and the default should be overridable' do
Pry.input = InputTester.new("5")
@ -145,8 +190,6 @@ describe Pry do
Pry.new(:input => InputTester.new("6")).rep
str_output.string.should =~ /6/
Pry.reset_defaults
end
it 'should set the output default, and the default should be overridable' do
@ -165,13 +208,9 @@ describe Pry do
Pry.new(:output => Pry::Output.new(str_output2)).rep
str_output2.string.should.not =~ /5\n.*6/
str_output2.string.should =~ /7/
Pry.reset_defaults
end
it 'should set the commands default, and the default should be overridable' do
Pry.reset_defaults
commands = {
"hello" => proc { |opts| opts[:output].puts "hello world"; opts[:val].clear }
}
@ -193,8 +232,6 @@ describe Pry do
Pry.new(:input => InputTester.new("goodbye"), :output => Pry::Output.new(str_output), :commands => commands).rep
str_output.string.should =~ /goodbye world/
Pry.reset_defaults
end
@ -216,8 +253,6 @@ describe Pry do
str_output = StringIO.new
Pry.new(:input => InputTester.new("\"test\""), :output => str_output).rep
str_output.string.should == "test\n"
Pry.reset_defaults
end
describe "prompts" do
@ -226,18 +261,18 @@ describe Pry do
Pry.prompt = new_prompt
Pry.new.prompt.should == Pry.prompt
Pry.new.get_prompt(true, 0).should == "test prompt> "
Pry.new.get_prompt(false, 0).should == "test prompt> "
Pry.new.select_prompt(true, 0).should == "test prompt> "
Pry.new.select_prompt(false, 0).should == "test prompt> "
new_prompt = proc { "A" }
pry_tester = Pry.new(:prompt => new_prompt)
pry_tester.prompt.should == new_prompt
pry_tester.get_prompt(true, 0).should == "A"
pry_tester.get_prompt(false, 0).should == "A"
pry_tester.select_prompt(true, 0).should == "A"
pry_tester.select_prompt(false, 0).should == "A"
Pry.new.prompt.should == Pry.prompt
Pry.new.get_prompt(true, 0).should == "test prompt> "
Pry.new.get_prompt(false, 0).should == "test prompt> "
Pry.new.select_prompt(true, 0).should == "test prompt> "
Pry.new.select_prompt(false, 0).should == "test prompt> "
end
it 'should set the prompt default, and the default should be overridable (multi prompt)' do
@ -245,26 +280,26 @@ describe Pry do
Pry.prompt = new_prompt
Pry.new.prompt.should == Pry.prompt
Pry.new.get_prompt(true, 0).should == "test prompt> "
Pry.new.get_prompt(false, 0).should == "test prompt* "
Pry.new.select_prompt(true, 0).should == "test prompt> "
Pry.new.select_prompt(false, 0).should == "test prompt* "
new_prompt = [proc { "A" }, proc { "B" }]
pry_tester = Pry.new(:prompt => new_prompt)
pry_tester.prompt.should == new_prompt
pry_tester.get_prompt(true, 0).should == "A"
pry_tester.get_prompt(false, 0).should == "B"
pry_tester.select_prompt(true, 0).should == "A"
pry_tester.select_prompt(false, 0).should == "B"
Pry.new.prompt.should == Pry.prompt
Pry.new.get_prompt(true, 0).should == "test prompt> "
Pry.new.get_prompt(false, 0).should == "test prompt* "
Pry.new.select_prompt(true, 0).should == "test prompt> "
Pry.new.select_prompt(false, 0).should == "test prompt* "
end
end
it 'should set the hooks default, and the default should be overridable' do
Pry.input = InputTester.new("exit")
Pry.hooks = {
:before_session => proc { |out| out.puts "HELLO" },
:after_session => proc { |out| out.puts "BYE" }
:before_session => proc { |out,_| out.puts "HELLO" },
:after_session => proc { |out,_| out.puts "BYE" }
}
str_output = StringIO.new
@ -277,8 +312,8 @@ describe Pry do
str_output = StringIO.new
Pry.new(:output => Pry::Output.new(str_output),
:hooks => {
:before_session => proc { |out| out.puts "MORNING" },
:after_session => proc { |out| out.puts "EVENING" }
:before_session => proc { |out,_| out.puts "MORNING" },
:after_session => proc { |out,_| out.puts "EVENING" }
}
).repl
@ -290,7 +325,7 @@ describe Pry do
str_output = StringIO.new
Pry.new(:output => Pry::Output.new(str_output),
:hooks => {
:before_session => proc { |out| out.puts "OPEN" }
:before_session => proc { |out,_| out.puts "OPEN" }
}
).repl
@ -300,7 +335,7 @@ describe Pry do
str_output = StringIO.new
Pry.new(:output => Pry::Output.new(str_output),
:hooks => {
:after_session => proc { |out| out.puts "CLOSE" }
:after_session => proc { |out,_| out.puts "CLOSE" }
}
).repl
@ -308,77 +343,7 @@ describe Pry do
Pry.reset_defaults
end
end
# commands = {
# "!" => "refresh",
# "help" => "show_help",
# "nesting" => "show_nesting",
# "status" => "show_status",
# "cat dummy" => "cat",
# "cd 3" => "cd",
# "ls" => "ls",
# "jump_to 0" => "jump_to",
# "show_method test_method" => "show_method",
# "show_imethod test_method" => "show_method",
# "show_doc test_method" => "show_doc",
# "show_idoc test_method" => "show_doc"
# }
# commands.each do |command, meth|
# if RUBY_VERSION =~ /1.8/ && NOT_FOR_RUBY_18.any? { |v| v =~ command }
# next
# end
# eval %{
# it "should invoke output##{meth} when #{command} command entered" do
# input_strings = ["#{command}", "exit"]
# input = InputTester.new(*input_strings)
# output = OutputTester.new
# o = Class.new
# pry_tester = Pry.new(:input => input, :output => output)
# pry_tester.repl(o)
# output.#{meth}_invoked.should == true
# output.session_end_invoked.should == true
# end
# }
# end
# commands.each do |command, meth|
# if RUBY_VERSION =~ /1.8/ && NOT_FOR_RUBY_18.include?(command)
# next
# end
# eval %{
# it "should raise when trying to invoke #{command} command with preceding whitespace" do
# input_strings = [" #{command}", "exit"]
# input = InputTester.new(*input_strings)
# output = OutputTester.new
# o = Class.new
# pry_tester = Pry.new(:input => input, :output => output)
# pry_tester.repl(o)
# if "#{command}" != "!"
# output.output_buffer.is_a?(NameError).should == true
# else
# # because entering " !" in pry doesnt cause error, it
# # just creates a wait prompt which the subsquent
# # "exit" escapes from
# output.output_buffer.should == ""
# end
# end
# }
# end
# end
end
end
end

View file

@ -9,7 +9,7 @@ class InputTester
@actions = actions
end
def read(*)
def readline(*)
@actions.shift
end