updated README
This commit is contained in:
parent
2dc06b23c8
commit
62d1e31819
146
README.markdown
146
README.markdown
|
@ -5,96 +5,104 @@ Pry
|
|||
|
||||
_attach an irb-like session to any object_
|
||||
|
||||
Pry is a simple Ruby REPL that specializes in interactively manipulates objects during the running of the program.
|
||||
Pry is a simple Ruby REPL that specializes in the interactive
|
||||
manipulation of objects during the running of a program.
|
||||
|
||||
Based on some ideas found in this [Ruby-Forum thread](http://www.ruby-forum.com/topic/179060)
|
||||
* Install the [gem](https://rubygems.org/gems/pry): `gem install pry`
|
||||
* Read the [documentation](http://rdoc.info/github/banister/pry/master/file/README.markdown)
|
||||
* See the [source code](http://github.com/banister/pry)
|
||||
|
||||
`Tweak` provides the `using` method.
|
||||
example: prying on an object at runtime
|
||||
---------------------------------------
|
||||
|
||||
* Install the [gem](https://rubygems.org/gems/tweak): `gem install tweak`
|
||||
* Read the [documentation](http://rdoc.info/github/banister/tweak/master/file/README.markdown)
|
||||
* See the [source code](http://github.com/banister/tweak)
|
||||
With the `Pry.into()` 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 program is halted for the duration of the session.
|
||||
|
||||
example: using
|
||||
-------------------------
|
||||
|
||||
With the `using` method we can enhance a core class for the duration
|
||||
of a block:
|
||||
|
||||
module Tweaks
|
||||
|
||||
class String
|
||||
def hello
|
||||
:hello
|
||||
end
|
||||
end
|
||||
|
||||
class Fixnum
|
||||
Hello = :hello
|
||||
|
||||
def bye
|
||||
:bye
|
||||
end
|
||||
end
|
||||
require 'pry'
|
||||
|
||||
class Test
|
||||
def self.hello() "hello world" end
|
||||
end
|
||||
|
||||
using Tweaks do
|
||||
"john".hello #=> :hello
|
||||
5.bye #=> :bye
|
||||
Fixnum::Hello #=> :hello
|
||||
end
|
||||
Pry.into(Test)
|
||||
|
||||
"john".hello #=> NameError
|
||||
# Pry session begins on stdin
|
||||
Beginning Pry session for Test
|
||||
pry(Test)> self
|
||||
=> Test
|
||||
pry(Test)> hello
|
||||
=> "hello world"
|
||||
pry(Test)> @y = 20
|
||||
=> 20
|
||||
pry(Test)> exit
|
||||
Ending Pry session for Test
|
||||
|
||||
How it works
|
||||
--------------
|
||||
# program resumes here
|
||||
|
||||
Makes use of the `Remix` and `Object2module` libraries. Note that `Tweak`
|
||||
modifies core classes by what is effectively a module inclusion, this
|
||||
means you cannot use `Tweak` to override existing functionality but
|
||||
more to augment and supplement that functionality.
|
||||
If we now inspect the `Test` object we can see our changes have had
|
||||
effect:
|
||||
|
||||
`Tweak` works by doing the following:
|
||||
Test.instance_variable_get(:@y) #=> 20
|
||||
|
||||
* Looks for top-level classes and modules with the same name as those
|
||||
defined under the using-module.
|
||||
* Uses `Object2module` to include the corresponding class/module
|
||||
defined under the using-module into the top-level class/module of the
|
||||
same name.
|
||||
* Uses `Remix` to uninclude that functionality at the end of the
|
||||
`using` block.
|
||||
example: Pry sessions can nest arbitrarily deep so we can pry on
|
||||
objects inside objects:
|
||||
----------------------------------------------------------------
|
||||
|
||||
Also look at the [Remix](http://github.com/banister/remix) library's
|
||||
`temp_include` and `temp_extend` methods for a more general solution than `Tweak`.
|
||||
Here we will begin Pry at top-level, then pry on a class and then on
|
||||
an instance variable inside that class:
|
||||
|
||||
Thread Safety
|
||||
--------------
|
||||
Pry.into
|
||||
Beginning Pry session for main
|
||||
pry(main)> class Hello
|
||||
pry(main)* @x = 20
|
||||
pry(main)* end
|
||||
=> 20
|
||||
pry(main)> Pry.into Hello
|
||||
Beginning Pry session for Hello
|
||||
pry(Hello)> instance_variables
|
||||
=> [:@x]
|
||||
pry(Hello)> Pry.into @x
|
||||
Beginning Pry session for 20
|
||||
pry(20)> self + 10
|
||||
=> 30
|
||||
pry(20)> exit
|
||||
Ending Pry session for 20
|
||||
pry(Hello)> exit
|
||||
Ending Pry session for Hello
|
||||
pry(main)> exit
|
||||
Ending Pry session for main
|
||||
|
||||
`Tweak` is not threadsafe.
|
||||
# program resumes here
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
example: Spawn a separate thread so you can use `Pry` to manipulate an object without halting
|
||||
the program.
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Does not work with nested modules, e.g `class String::SomethingElse`
|
||||
If we embed our `Pry.into` method inside its own thread we can examine
|
||||
and manipulate objects without halting the program.
|
||||
|
||||
This is not intended to be a robust or serious solution, it's just a
|
||||
little experiment. :)
|
||||
# Pry.into() without parameters opens up the top-level (main)
|
||||
Thread.new { Pry.into }
|
||||
|
||||
Companion Libraries
|
||||
--------------------
|
||||
|
||||
Tweak is one of a series of experimental libraries that mess with
|
||||
the internals of Ruby to bring new and interesting functionality to
|
||||
the language, see also:
|
||||
Features and limitations
|
||||
------------------------
|
||||
|
||||
* [Remix](http://github.com/banister/remix) - Makes ancestor chains read/write
|
||||
* [Object2module](http://github.com/banister/object2module) - Enables you to include/extend Object/Classes.
|
||||
* [Include Complete](http://github.com/banister/include_complete) - Brings in
|
||||
module singleton classes during an include. No more ugly ClassMethods and included() hook hacks.
|
||||
* [Prepend](http://github.com/banister/prepend) - Prepends modules in front of a class; so method lookup starts with the module
|
||||
* [GenEval](http://github.com/banister/gen_eval) - A strange new breed of instance_eval
|
||||
* [LocalEval](http://github.com/banister/local_eval) - instance_eval without changing self
|
||||
Pry is an irb-like clone with an emphasis on interactively examining
|
||||
and manipulating objects during the running of a program.
|
||||
|
||||
Its primary utility is probably in debugging, though it may have other
|
||||
uses (such as implementing a quake-like console for games, for example). Here is a
|
||||
list of Pry's features along with some of its limitations given at the
|
||||
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'
|
||||
* Pry has multi-line support built in.
|
||||
* Pry implements all the methods in the REPL chain separately: `Pry.r`
|
||||
for reading; `Pry.re` for eval; `Pry.rep` for printing; and `Pry.repl`
|
||||
for the loop (`Pry.into` is simply an alias for `Pry.repl`)
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
|
36
lib/pry.rb
36
lib/pry.rb
|
@ -3,8 +3,15 @@ require 'readline'
|
|||
require 'ruby_parser'
|
||||
|
||||
module Pry
|
||||
DEFAULT_PROMPT = proc { |v| "pry(#{v})> " }
|
||||
DEFAULT_WAIT_PROMPT = proc { |v| "pry(#{v})* " }
|
||||
class << self
|
||||
attr_accessor :default_prompt, :wait_prompt,
|
||||
:session_start_msg, :session_end_msg
|
||||
end
|
||||
|
||||
@default_prompt = proc { |v| "pry(#{v})> " }
|
||||
@wait_prompt = proc { |v| "pry(#{v})* " }
|
||||
@session_start_msg = proc { |v| "Beginning Pry session for #{v}" }
|
||||
@session_end_msg = proc { |v| "Ending Pry session for #{v}" }
|
||||
|
||||
# loop
|
||||
def self.repl(target=TOPLEVEL_BINDING)
|
||||
|
@ -12,11 +19,20 @@ module Pry
|
|||
target = target.instance_eval { binding }
|
||||
end
|
||||
|
||||
puts session_start_msg.call(target.eval('self'))
|
||||
|
||||
loop do
|
||||
if catch(:pop) { rep(target) } == :return
|
||||
return target.eval('self')
|
||||
break target.eval('self')
|
||||
end
|
||||
end
|
||||
|
||||
puts session_end_msg.call(target.eval('self'))
|
||||
end
|
||||
|
||||
class << self
|
||||
alias_method :into, :repl
|
||||
alias_method :start, :repl
|
||||
end
|
||||
|
||||
# print
|
||||
|
@ -32,7 +48,6 @@ module Pry
|
|||
else
|
||||
puts "=> #{value.inspect}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# eval
|
||||
|
@ -48,21 +63,20 @@ module Pry
|
|||
loop do
|
||||
val = Readline.readline(prompt(eval_string, target), true)
|
||||
eval_string += "#{val}\n"
|
||||
process_commands(val, eval_string)
|
||||
process_commands(val, eval_string, target)
|
||||
|
||||
break eval_string if valid_expression?(eval_string)
|
||||
end
|
||||
end
|
||||
|
||||
def self.process_commands(val, eval_string)
|
||||
def self.process_commands(val, eval_string, target)
|
||||
case val
|
||||
when "exit", "quit"
|
||||
when "#exit", "#quit"
|
||||
exit
|
||||
when "!"
|
||||
eval_string.replace("")
|
||||
puts "Refreshed REPL."
|
||||
when "#pop"
|
||||
puts "Popping up a context."
|
||||
when "exit", "quit"
|
||||
throw(:pop, :return)
|
||||
end
|
||||
end
|
||||
|
@ -71,9 +85,9 @@ module Pry
|
|||
context = target.eval('self')
|
||||
|
||||
if eval_string.empty?
|
||||
DEFAULT_PROMPT.call(context)
|
||||
default_prompt.call(context)
|
||||
else
|
||||
DEFAULT_WAIT_PROMPT.call(context)
|
||||
wait_prompt.call(context)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue