pry 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3 -0
- data/README.markdown +133 -0
- data/Rakefile +58 -0
- data/lib/pry.rb +101 -0
- data/lib/pry/version.rb +3 -0
- metadata +82 -0
data/CHANGELOG
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
Pry
|
2
|
+
=============
|
3
|
+
|
4
|
+
(C) John Mair (banisterfiend) 2010
|
5
|
+
|
6
|
+
_attach an irb-like session to any object_
|
7
|
+
|
8
|
+
Pry is a simple Ruby REPL that specializes in the interactive
|
9
|
+
manipulation of objects during the running of a program.
|
10
|
+
|
11
|
+
* Install the [gem](https://rubygems.org/gems/pry): `gem install pry`
|
12
|
+
* Read the [documentation](http://rdoc.info/github/banister/pry/master/file/README.markdown)
|
13
|
+
* See the [source code](http://github.com/banister/pry)
|
14
|
+
|
15
|
+
example: prying on an object at runtime
|
16
|
+
---------------------------------------
|
17
|
+
|
18
|
+
With the `Pry.into()` method we can pry (open an irb-like session) on
|
19
|
+
an object. In the example below we open a Pry session for the `Test` class and execute a method and add
|
20
|
+
an instance variable. The program is halted for the duration of the session.
|
21
|
+
|
22
|
+
require 'pry'
|
23
|
+
|
24
|
+
class Test
|
25
|
+
def self.hello() "hello world" end
|
26
|
+
end
|
27
|
+
|
28
|
+
Pry.into(Test)
|
29
|
+
|
30
|
+
# Pry session begins on stdin
|
31
|
+
Beginning Pry session for Test
|
32
|
+
pry(Test)> self
|
33
|
+
=> Test
|
34
|
+
pry(Test)> hello
|
35
|
+
=> "hello world"
|
36
|
+
pry(Test)> @y = 20
|
37
|
+
=> 20
|
38
|
+
pry(Test)> exit
|
39
|
+
Ending Pry session for Test
|
40
|
+
|
41
|
+
# program resumes here
|
42
|
+
|
43
|
+
If we now inspect the `Test` object we can see our changes have had
|
44
|
+
effect:
|
45
|
+
|
46
|
+
Test.instance_variable_get(:@y) #=> 20
|
47
|
+
|
48
|
+
|
49
|
+
example: Pry sessions can nest arbitrarily deep so we can pry on objects inside objects:
|
50
|
+
----------------------------------------------------------------------------------------
|
51
|
+
|
52
|
+
Here we will begin Pry at top-level, then pry on a class and then on
|
53
|
+
an instance variable inside that class:
|
54
|
+
|
55
|
+
# Pry.into() without parameters begins a Pry session on top-level (main)
|
56
|
+
Pry.into
|
57
|
+
Beginning Pry session for main
|
58
|
+
pry(main)> class Hello
|
59
|
+
pry(main)* @x = 20
|
60
|
+
pry(main)* end
|
61
|
+
=> 20
|
62
|
+
pry(main)> Pry.into Hello
|
63
|
+
Beginning Pry session for Hello
|
64
|
+
pry(Hello)> instance_variables
|
65
|
+
=> [:@x]
|
66
|
+
pry(Hello)> Pry.into @x
|
67
|
+
Beginning Pry session for 20
|
68
|
+
pry(20)> self + 10
|
69
|
+
=> 30
|
70
|
+
pry(20)> exit
|
71
|
+
Ending Pry session for 20
|
72
|
+
pry(Hello)> exit
|
73
|
+
Ending Pry session for Hello
|
74
|
+
pry(main)> exit
|
75
|
+
Ending Pry session for main
|
76
|
+
|
77
|
+
# program resumes here
|
78
|
+
|
79
|
+
|
80
|
+
example: Spawn a separate thread so you can use `Pry` to manipulate an
|
81
|
+
object without halting the program.
|
82
|
+
---------------------------------------------------------------------------------------------------
|
83
|
+
|
84
|
+
If we embed our `Pry.into` method inside its own thread we can examine
|
85
|
+
and manipulate objects without halting the program.
|
86
|
+
|
87
|
+
# Pry.into() without parameters opens up the top-level (main)
|
88
|
+
Thread.new { Pry.into }
|
89
|
+
|
90
|
+
|
91
|
+
Features and limitations
|
92
|
+
------------------------
|
93
|
+
|
94
|
+
Pry is an irb-like clone with an emphasis on interactively examining
|
95
|
+
and manipulating objects during the running of a program.
|
96
|
+
|
97
|
+
Its primary utility is probably in debugging, though it may have other
|
98
|
+
uses (such as implementing a quake-like console for games, for example). Here is a
|
99
|
+
list of Pry's features along with some of its limitations given at the
|
100
|
+
end.
|
101
|
+
|
102
|
+
Features:
|
103
|
+
|
104
|
+
* Pry can be invoked at any time and on any object in the running program.
|
105
|
+
* Pry sessions can nest arbitrarily deeply -- to go back one level of nesting type 'exit' or 'quit'
|
106
|
+
* Pry has multi-line support built in.
|
107
|
+
* Pry implements all the methods in the REPL chain separately: `Pry.r`
|
108
|
+
for reading; `Pry.re` for eval; `Pry.rep` for printing; and `Pry.repl`
|
109
|
+
for the loop (`Pry.into` is simply an alias for `Pry.repl`). You can
|
110
|
+
invoke any of these methods directly depending on exactly what aspect of the functionality you need.
|
111
|
+
|
112
|
+
Limitations:
|
113
|
+
|
114
|
+
* Pry does not pretend to be a replacement for `irb`,
|
115
|
+
and so does not have an executable. It is designed to be used by
|
116
|
+
other programs, not on its own. For a full-featured `irb` replacement
|
117
|
+
see [ripl](https://github.com/cldwalker/ripl)
|
118
|
+
* Although Pry works fine in Ruby 1.9, only Ruby 1.8 syntax is
|
119
|
+
supported. This is because Pry uses the
|
120
|
+
[RubyParser](https://github.com/seattlerb/ruby_parser)
|
121
|
+
gem internally to validate expressions, and RubyParser, as yet, only parses Ruby 1.8
|
122
|
+
code. In practice this usually just means you cannot use the new
|
123
|
+
hash literal syntax (this: syntax) or the 'stabby lambda' syntax
|
124
|
+
(->).
|
125
|
+
|
126
|
+
|
127
|
+
Contact
|
128
|
+
-------
|
129
|
+
|
130
|
+
Problems or questions contact me at [github](http://github.com/banister)
|
131
|
+
|
132
|
+
|
133
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
dlext = Config::CONFIG['DLEXT']
|
2
|
+
direc = File.dirname(__FILE__)
|
3
|
+
|
4
|
+
require 'rake/clean'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
require "#{direc}/lib/pry/version"
|
7
|
+
|
8
|
+
CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o")
|
9
|
+
CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o",
|
10
|
+
"ext/**/*~", "ext/**/*#*", "ext/**/*.obj",
|
11
|
+
"ext/**/*.def", "ext/**/*.pdb", "**/*_flymake*.*", "**/*_flymake")
|
12
|
+
|
13
|
+
def apply_spec_defaults(s)
|
14
|
+
s.name = "pry"
|
15
|
+
s.summary = "attach an irb-like session to any object"
|
16
|
+
s.version = Pry::VERSION
|
17
|
+
s.date = Time.now.strftime '%Y-%m-%d'
|
18
|
+
s.author = "John Mair (banisterfiend)"
|
19
|
+
s.email = 'jrmair@gmail.com'
|
20
|
+
s.description = s.summary
|
21
|
+
s.require_path = 'lib'
|
22
|
+
s.add_dependency("ruby_parser",">=2.0.5")
|
23
|
+
s.homepage = "http://banisterfiend.wordpress.com"
|
24
|
+
s.has_rdoc = 'yard'
|
25
|
+
s.files = Dir["ext/**/extconf.rb", "ext/**/*.h", "ext/**/*.c", "lib/**/*.rb",
|
26
|
+
"test/*.rb", "CHANGELOG", "README.markdown", "Rakefile"]
|
27
|
+
end
|
28
|
+
|
29
|
+
task :test do
|
30
|
+
sh "bacon -k #{direc}/test/test.rb"
|
31
|
+
end
|
32
|
+
|
33
|
+
namespace :ruby do
|
34
|
+
spec = Gem::Specification.new do |s|
|
35
|
+
apply_spec_defaults(s)
|
36
|
+
s.platform = Gem::Platform::RUBY
|
37
|
+
end
|
38
|
+
|
39
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
40
|
+
pkg.need_zip = false
|
41
|
+
pkg.need_tar = false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "build all platform gems at once"
|
46
|
+
task :gems => [:rmgems, "ruby:gem"]
|
47
|
+
|
48
|
+
desc "remove all platform gems"
|
49
|
+
task :rmgems => ["ruby:clobber_package"]
|
50
|
+
|
51
|
+
desc "build and push latest gems"
|
52
|
+
task :pushgems => :gems do
|
53
|
+
chdir("#{direc}/pkg") do
|
54
|
+
Dir["*.gem"].each do |gemfile|
|
55
|
+
sh "gem push #{gemfile}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/pry.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'readline'
|
3
|
+
require 'ruby_parser'
|
4
|
+
|
5
|
+
module Pry
|
6
|
+
class << self
|
7
|
+
attr_accessor :default_prompt, :wait_prompt,
|
8
|
+
:session_start_msg, :session_end_msg
|
9
|
+
end
|
10
|
+
|
11
|
+
@default_prompt = proc { |v| "pry(#{v})> " }
|
12
|
+
@wait_prompt = proc { |v| "pry(#{v})* " }
|
13
|
+
@session_start_msg = proc { |v| "Beginning Pry session for #{v}" }
|
14
|
+
@session_end_msg = proc { |v| "Ending Pry session for #{v}" }
|
15
|
+
|
16
|
+
# loop
|
17
|
+
def self.repl(target=TOPLEVEL_BINDING)
|
18
|
+
if !target.is_a?(Binding)
|
19
|
+
target = target.instance_eval { binding }
|
20
|
+
end
|
21
|
+
|
22
|
+
puts session_start_msg.call(target.eval('self'))
|
23
|
+
|
24
|
+
loop do
|
25
|
+
if catch(:pop) { rep(target) } == :return
|
26
|
+
break target.eval('self')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
puts session_end_msg.call(target.eval('self'))
|
31
|
+
end
|
32
|
+
|
33
|
+
class << self
|
34
|
+
alias_method :into, :repl
|
35
|
+
alias_method :start, :repl
|
36
|
+
end
|
37
|
+
|
38
|
+
# print
|
39
|
+
def self.rep(target=TOPLEVEL_BINDING)
|
40
|
+
if !target.is_a?(Binding)
|
41
|
+
target = target.instance_eval { binding }
|
42
|
+
end
|
43
|
+
|
44
|
+
value = re(target)
|
45
|
+
case value
|
46
|
+
when Exception
|
47
|
+
puts "#{value.class}: #{value.message}"
|
48
|
+
else
|
49
|
+
puts "=> #{value.inspect}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# eval
|
54
|
+
def self.re(target=TOPLEVEL_BINDING)
|
55
|
+
target.eval r(target)
|
56
|
+
rescue StandardError => e
|
57
|
+
e
|
58
|
+
end
|
59
|
+
|
60
|
+
# read
|
61
|
+
def self.r(target=TOPLEVEL_BINDING)
|
62
|
+
eval_string = ""
|
63
|
+
loop do
|
64
|
+
val = Readline.readline(prompt(eval_string, target), true)
|
65
|
+
eval_string += "#{val}\n"
|
66
|
+
process_commands(val, eval_string, target)
|
67
|
+
|
68
|
+
break eval_string if valid_expression?(eval_string)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.process_commands(val, eval_string, target)
|
73
|
+
case val
|
74
|
+
when "#exit", "#quit"
|
75
|
+
exit
|
76
|
+
when "!"
|
77
|
+
eval_string.replace("")
|
78
|
+
puts "Refreshed REPL."
|
79
|
+
when "exit", "quit"
|
80
|
+
throw(:pop, :return)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.prompt(eval_string, target)
|
85
|
+
context = target.eval('self')
|
86
|
+
|
87
|
+
if eval_string.empty?
|
88
|
+
default_prompt.call(context)
|
89
|
+
else
|
90
|
+
wait_prompt.call(context)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.valid_expression?(code)
|
95
|
+
RubyParser.new.parse(code)
|
96
|
+
rescue Racc::ParseError
|
97
|
+
false
|
98
|
+
else
|
99
|
+
true
|
100
|
+
end
|
101
|
+
end
|
data/lib/pry/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pry
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- John Mair (banisterfiend)
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-12-09 00:00:00 +13:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: ruby_parser
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 2
|
30
|
+
- 0
|
31
|
+
- 5
|
32
|
+
version: 2.0.5
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description: attach an irb-like session to any object
|
36
|
+
email: jrmair@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- lib/pry/version.rb
|
45
|
+
- lib/pry.rb
|
46
|
+
- CHANGELOG
|
47
|
+
- README.markdown
|
48
|
+
- Rakefile
|
49
|
+
has_rdoc: yard
|
50
|
+
homepage: http://banisterfiend.wordpress.com
|
51
|
+
licenses: []
|
52
|
+
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
version: "0"
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
requirements: []
|
75
|
+
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.3.7
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: attach an irb-like session to any object
|
81
|
+
test_files: []
|
82
|
+
|