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

Ripper for 1.9, RubyParser for 1.8. Fixed 1.8 inspect difficulties, added help for new commands, using method_source gem, updated README

This commit is contained in:
John Mair 2010-12-17 17:56:50 +13:00
parent a31d9e31c1
commit c6ee635460
5 changed files with 62 additions and 52 deletions

View file

@ -8,13 +8,14 @@ _attach an irb-like session to any object at runtime_
Pry is a simple Ruby REPL (Read-Eval-Print-Loop) that specializes in the interactive Pry is a simple Ruby REPL (Read-Eval-Print-Loop) that specializes in the interactive
manipulation of objects during the running of a program. manipulation of objects during the running of a program.
It is not based on the IRB codebase and is small, at around 260 LOC. It is not based on the IRB codebase, and implements some unique REPL
commands such as `show_method` and `jump_to`
* Install the [gem](https://rubygems.org/gems/pry): `gem install pry` * Install the [gem](https://rubygems.org/gems/pry): `gem install pry`
* 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 `Pry.start()` method we can pry (open an irb-like session) on With the `Pry.start()` method we can pry (open an irb-like session) on
@ -62,7 +63,7 @@ OR
beginning Pry session for 6 beginning Pry session for 6
pry(6)> pry(6)>
example: Pry sessions can nest arbitrarily deep so we can pry on objects inside objects: Example: Pry sessions can nest arbitrarily deep so we can pry on objects inside objects:
---------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------
Here we will begin Pry at top-level, then pry on a class and then on Here we will begin Pry at top-level, then pry on a class and then on
@ -137,7 +138,7 @@ uses (such as implementing a quake-like console for games, for example). Here is
list of Pry's features along with some of its limitations given at the list of Pry's features along with some of its limitations given at the
end. end.
Features: ####Features:
* Pry can be invoked at any time and on any object in the running program. * 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' * Pry sessions can nest arbitrarily deeply -- to go back one level of nesting type 'exit' or 'quit' or 'back'
@ -145,45 +146,40 @@ Features:
* Pry has multi-line support built in. * Pry has multi-line support built in.
* Pry gives good control over nested sessions (important when exploring complicated runtime state) * Pry gives good control over nested sessions (important when exploring complicated runtime state)
* Pry is not based on the IRB codebase. * Pry is not based on the IRB codebase.
* Pry is small; around 260 LOC. * Pry uses [RubyParser](https://github.com/seattlerb/ruby_parser) to
* Pry implements all the methods in the REPL chain separately: `Pry.r` validate expressions in 1.8, and [Ripper](http://rdoc.info/docs/ruby-core/1.9.2/Ripper) for 1.9.
for reading; `Pry.re` for eval; `Pry.rep` for printing; and `Pry.repl` * Pry implements all the methods in the REPL chain separately: `Pry#r`
for the loop (`Pry.start` is simply an alias for `Pry.repl`). You can for reading; `Pry#re` for eval; `Pry#rep` for printing; and `Pry#repl`
for the loop (`Pry.start` simply wraps `Pry.new.repl`). You can
invoke any of these methods directly depending on exactly what aspect of the functionality you need. invoke any of these methods directly depending on exactly what aspect of the functionality you need.
Limitations: ####Limitations:
* Pry does not pretend to be a replacement for `irb`, * Pry does not pretend to be a replacement for `irb`,
and so does not have an executable. It is designed to be used by and so does not have an executable. It is designed to be used by
other programs, not on its own. For a full-featured `irb` replacement other programs, not on its own. For a full-featured `irb` replacement
see [ripl](https://github.com/cldwalker/ripl) see [ripl](https://github.com/cldwalker/ripl)
* Although Pry works fine in Ruby 1.9, only Ruby 1.8 syntax is * Pry's `show_method` and `show_instance_method` commands do not work
supported. This is because Pry uses the in Ruby 1.8.
[RubyParser](https://github.com/seattlerb/ruby_parser)
gem internally to validate expressions, and RubyParser, as yet, only parses Ruby 1.8
code. In practice this usually just means you cannot use the new
hash literal syntax (this: syntax) or the 'stabby lambda' syntax
(->).
Commands Commands
----------- -----------
### The Pry API: ### The Pry API:
* `Pry.start()` and `Pry.into()` and `Pry.repl()` are all aliases of * `Pry.start()` Starts a Read-Eval-Print-Loop on the object it
oneanother. They all start a Read-Eval-Print-Loop on the object they receives as a parameter. In the case of no parameter it operates on
receive as a parameter. In the case of no parameter they operate on top-level (main). It can receive any object or a `Binding`
top-level (main). They can receive any object or a `Binding` object as parameter. `Pry.start()` is implemented as `Pry.new.repl()`
object as parameter.
* `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)`
* If, for some reason you do not want to 'loop' then use `Pry.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()`
* Similarly `Pry.r()` only performs the Read section of the REPL, only * Similarly `Pry#r()` only performs the Read section of the REPL, only
returning the Ruby expression (as a string). It takes the same parameters as all the others. returning the Ruby expression (as a string). It takes the same parameters as all the others.
### Session commands ### Session commands
@ -202,6 +198,13 @@ If you want to access a method of the same name, prefix the invocation by whites
* `exit` or `quit` or `back` will end the current Pry session and go * `exit` or `quit` or `back` will end the current Pry session and go
back to the calling process or back one level of nesting (if there back to the calling process or back one level of nesting (if there
are nested sessions). are nested sessions).
* `ls` returns a list of local variables and instance variables in the
current scope
* `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_instance_method <methname>` Displays the sourcecode for the
instance method <methname>. E.g `show_instance_method goodbye`
* `exit_program` or `quit_program` will end the currently running * `exit_program` or `quit_program` will end the currently running
program. program.
* `nesting` shows Pry nesting information. * `nesting` shows Pry nesting information.

View file

@ -7,7 +7,7 @@ require "#{direc}/lib/pry/version"
CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o") CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o")
CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o", CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o",
"ext/**/*~", "ext/**/*#*", "ext/**/*.obj", "ext/**/*~", "ext/**/*#*", "ext/**/*.obj", "**/*#*", "**/*#*.*",
"ext/**/*.def", "ext/**/*.pdb", "**/*_flymake*.*", "**/*_flymake") "ext/**/*.def", "ext/**/*.pdb", "**/*_flymake*.*", "**/*_flymake")
def apply_spec_defaults(s) def apply_spec_defaults(s)
@ -20,6 +20,7 @@ def apply_spec_defaults(s)
s.description = s.summary s.description = s.summary
s.require_path = 'lib' s.require_path = 'lib'
s.add_dependency("ruby_parser",">=2.0.5") s.add_dependency("ruby_parser",">=2.0.5")
s.add_dependency("method_source",">=0.1.4")
s.homepage = "http://banisterfiend.wordpress.com" s.homepage = "http://banisterfiend.wordpress.com"
s.has_rdoc = 'yard' s.has_rdoc = 'yard'
s.files = Dir["ext/**/extconf.rb", "ext/**/*.h", "ext/**/*.c", "lib/**/*.rb", s.files = Dir["ext/**/extconf.rb", "ext/**/*.h", "ext/**/*.c", "lib/**/*.rb",

View file

@ -4,6 +4,8 @@
direc = File.dirname(__FILE__) direc = File.dirname(__FILE__)
require 'ruby_parser' require 'ruby_parser'
require 'method_source'
require 'stringio'
require "#{direc}/pry/version" require "#{direc}/pry/version"
require "#{direc}/pry/input" require "#{direc}/pry/input"
require "#{direc}/pry/output" require "#{direc}/pry/output"
@ -15,7 +17,7 @@ class Pry
def self.view(obj) def self.view(obj)
case obj case obj
when String, Symbol, nil when String, Array, Hash, Symbol, nil
obj.inspect obj.inspect
else else
obj.to_s obj.to_s
@ -150,7 +152,8 @@ class Pry
output.exit output.exit
throw(:breakout, nesting.level) throw(:breakout, nesting.level)
when "ls" when "ls"
eval_string.replace("local_variables + instance_variables") output.ls(target)
eval_string.clear
when /^cd\s+(.+)/ when /^cd\s+(.+)/
obj = $~.captures.first obj = $~.captures.first
target.eval("#{obj}.pry") target.eval("#{obj}.pry")
@ -184,8 +187,7 @@ class Pry
end end
def get_method_source(target, meth_name, kind) def get_method_source(target, meth_name, kind)
file, line = target.eval("#{kind}(:#{meth_name}).source_location") target.eval("#{kind}(:#{meth_name}).source")
Pry.new.tap { |v| v.input = SourceInput.new(file, line) }.r
end end
def prompt(eval_string, target, nest) def prompt(eval_string, target, nest)
@ -198,27 +200,23 @@ class Pry
end end
end end
def valid_expression?(code) if RUBY_VERSION =~ /1.9/
test_bed = Object.new.instance_eval { binding } require 'ripper'
begin def valid_expression?(code)
test_bed.eval(code) !!Ripper::SexpBuilder.new(code).parse
rescue SyntaxError => e
case e.message
when /(parse|syntax) error.*?\$end/i, /unterminated/i
return false
end
rescue Exception
end end
true
end
def old_valid_expression?(code)
RubyParser.new.parse(code)
rescue Racc::ParseError, SyntaxError
false
else else
true
def valid_expression?(code)
RubyParser.new.parse(code)
rescue Racc::ParseError, SyntaxError
false
else
true
end
end end
def binding_for(target) def binding_for(target)

View file

@ -29,6 +29,10 @@ class Pry
puts "status Show status information" puts "status Show status information"
puts "! Refresh the REPL" puts "! Refresh the REPL"
puts "nesting Show nesting information" puts "nesting Show nesting information"
puts "ls Show the list of variables in the current scope"
puts "cd <var> Start a Pry session on <var> (use `cd ..` to go back)"
puts "show_method <methname> Show the sourcecode for the method <method_name>"
puts "show_instance_method <methname> Show the sourcecode for the instance method <method_name>"
puts "exit/quit/back End the current Pry session" puts "exit/quit/back End the current Pry session"
puts "exit_all End all nested Pry sessions" puts "exit_all End all nested Pry sessions"
puts "exit_program/quit_program End the current program" puts "exit_program/quit_program End the current program"
@ -52,10 +56,14 @@ class Pry
puts "--" puts "--"
puts "Receiver: #{Pry.view(target.eval('self'))}" puts "Receiver: #{Pry.view(target.eval('self'))}"
puts "Nesting level: #{nesting.level}" puts "Nesting level: #{nesting.level}"
puts "Local variables: #{Pry.view(target.eval("local_variables"))}" puts "Local variables: #{target.eval('Pry.view(local_variables)')}"
puts "Last result: #{Pry.view(Pry.last_result)}" puts "Last result: #{Pry.view(Pry.last_result)}"
end end
def ls(target)
puts "#{target.eval('Pry.view(local_variables + instance_variables)')}"
end
def show_method(code) def show_method(code)
code.display code.display
end end

View file

@ -1,3 +1,3 @@
class Pry class Pry
VERSION = "0.2.5pre2" VERSION = "0.2.6"
end end