pry 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2 -0
- data/README.markdown +96 -26
- data/lib/pry.rb +111 -46
- data/lib/pry/input.rb +9 -0
- data/lib/pry/output.rb +67 -0
- data/lib/pry/version.rb +1 -1
- metadata +9 -3
data/CHANGELOG
CHANGED
data/README.markdown
CHANGED
@@ -5,17 +5,19 @@ Pry
|
|
5
5
|
|
6
6
|
_attach an irb-like session to any object at runtime_
|
7
7
|
|
8
|
-
Pry is a simple Ruby REPL that specializes in the interactive
|
8
|
+
Pry is a simple Ruby REPL (Read-Eval-Print-Loop) that specializes in the interactive
|
9
9
|
manipulation of objects during the running of a program.
|
10
10
|
|
11
|
+
It is not based on the IRB codebase and is small, at around 260 LOC.
|
12
|
+
|
11
13
|
* Install the [gem](https://rubygems.org/gems/pry): `gem install pry`
|
12
14
|
* Read the [documentation](http://rdoc.info/github/banister/pry/master/file/README.markdown)
|
13
15
|
* See the [source code](http://github.com/banister/pry)
|
14
16
|
|
15
|
-
example:
|
17
|
+
example: Interacting with an object at runtime
|
16
18
|
---------------------------------------
|
17
19
|
|
18
|
-
With the `Pry.
|
20
|
+
With the `Pry.start()` method we can pry (open an irb-like session) on
|
19
21
|
an object. In the example below we open a Pry session for the `Test` class and execute a method and add
|
20
22
|
an instance variable. The current thread is halted for the duration of the session.
|
21
23
|
|
@@ -25,7 +27,7 @@ an instance variable. The current thread is halted for the duration of the sessi
|
|
25
27
|
def self.hello() "hello world" end
|
26
28
|
end
|
27
29
|
|
28
|
-
Pry.
|
30
|
+
Pry.start(Test)
|
29
31
|
|
30
32
|
# Pry session begins on stdin
|
31
33
|
Beginning Pry session for Test
|
@@ -44,36 +46,85 @@ If we now inspect the `Test` object we can see our changes have had
|
|
44
46
|
effect:
|
45
47
|
|
46
48
|
Test.instance_variable_get(:@y) #=> 20
|
47
|
-
|
48
49
|
|
50
|
+
#### Alternative Syntax
|
51
|
+
|
52
|
+
You can also use the `obj.pry` or `pry(obj)` syntax to start a pry session on
|
53
|
+
`obj`. e.g
|
54
|
+
|
55
|
+
5.pry
|
56
|
+
Beginning Pry session for 5
|
57
|
+
pry(5)>
|
58
|
+
|
59
|
+
OR
|
60
|
+
|
61
|
+
pry 6
|
62
|
+
beginning Pry session for 6
|
63
|
+
pry(6)>
|
64
|
+
|
49
65
|
example: Pry sessions can nest arbitrarily deep so we can pry on objects inside objects:
|
50
66
|
----------------------------------------------------------------------------------------
|
51
67
|
|
52
68
|
Here we will begin Pry at top-level, then pry on a class and then on
|
53
69
|
an instance variable inside that class:
|
54
70
|
|
55
|
-
# Pry.
|
56
|
-
Pry.
|
71
|
+
# Pry.start() without parameters begins a Pry session on top-level (main)
|
72
|
+
Pry.start
|
57
73
|
Beginning Pry session for main
|
58
74
|
pry(main)> class Hello
|
59
75
|
pry(main)* @x = 20
|
60
76
|
pry(main)* end
|
61
77
|
=> 20
|
62
|
-
pry(main)> Pry.
|
78
|
+
pry(main)> Pry.start Hello
|
63
79
|
Beginning Pry session for Hello
|
64
|
-
pry(Hello)> instance_variables
|
80
|
+
pry(Hello):1> instance_variables
|
65
81
|
=> [:@x]
|
66
|
-
pry(Hello)> Pry.
|
82
|
+
pry(Hello):1> Pry.start @x
|
67
83
|
Beginning Pry session for 20
|
68
|
-
pry(20)> self + 10
|
84
|
+
pry(20:2)> self + 10
|
69
85
|
=> 30
|
70
|
-
pry(20)> exit
|
86
|
+
pry(20:2)> exit
|
71
87
|
Ending Pry session for 20
|
72
|
-
pry(Hello)> exit
|
88
|
+
pry(Hello):1> exit
|
73
89
|
Ending Pry session for Hello
|
74
90
|
pry(main)> exit
|
75
91
|
Ending Pry session for main
|
92
|
+
|
93
|
+
The number after the `:` in the pry prompt indicates the nesting
|
94
|
+
level. To display more information about nesting, use the `nesting`
|
95
|
+
command. E.g
|
96
|
+
|
97
|
+
pry("friend":3)> nesting
|
98
|
+
Nesting status:
|
99
|
+
0. main (Pry top level)
|
100
|
+
1. Hello
|
101
|
+
2. 100
|
102
|
+
3. "friend"
|
103
|
+
=> nil
|
104
|
+
|
105
|
+
We can then jump back to any of the previous nesting levels by using
|
106
|
+
the `jump_to` command:
|
107
|
+
|
108
|
+
pry("friend":3)> jump_to 1
|
109
|
+
Ending Pry session for "friend"
|
110
|
+
Ending Pry session for 100
|
111
|
+
=> 100
|
112
|
+
pry(Hello):1>
|
113
|
+
|
114
|
+
If we just want to go back one level of nesting we can of course
|
115
|
+
use the `quit` or `exit` or `back` commands.
|
116
|
+
|
117
|
+
To break out of all levels of Pry nesting and return immediately to the
|
118
|
+
calling process use `exit_all`:
|
119
|
+
|
120
|
+
pry("friend":3)> exit_all
|
121
|
+
Ending Pry session for "friend"
|
122
|
+
Ending Pry session for 100
|
123
|
+
Ending Pry session for Hello
|
124
|
+
Ending Pry session for main
|
125
|
+
=> main
|
76
126
|
|
127
|
+
# program resumes here
|
77
128
|
|
78
129
|
Features and limitations
|
79
130
|
------------------------
|
@@ -89,11 +140,15 @@ end.
|
|
89
140
|
Features:
|
90
141
|
|
91
142
|
* Pry can be invoked at any time and on any object in the running program.
|
92
|
-
* Pry sessions can nest arbitrarily deeply -- to go back one level of nesting type 'exit' or 'quit'
|
143
|
+
* Pry sessions can nest arbitrarily deeply -- to go back one level of nesting type 'exit' or 'quit' or 'back'
|
144
|
+
* Use `_` to recover last result.
|
93
145
|
* Pry has multi-line support built in.
|
146
|
+
* Pry gives good control over nested sessions (important when exploring complicated runtime state)
|
147
|
+
* Pry is not based on the IRB codebase.
|
148
|
+
* Pry is small; around 260 LOC.
|
94
149
|
* Pry implements all the methods in the REPL chain separately: `Pry.r`
|
95
150
|
for reading; `Pry.re` for eval; `Pry.rep` for printing; and `Pry.repl`
|
96
|
-
for the loop (`Pry.
|
151
|
+
for the loop (`Pry.start` is simply an alias for `Pry.repl`). You can
|
97
152
|
invoke any of these methods directly depending on exactly what aspect of the functionality you need.
|
98
153
|
|
99
154
|
Limitations:
|
@@ -113,33 +168,48 @@ Limitations:
|
|
113
168
|
Commands
|
114
169
|
-----------
|
115
170
|
|
116
|
-
The Pry API:
|
171
|
+
### The Pry API:
|
117
172
|
|
118
|
-
* `Pry.
|
173
|
+
* `Pry.start()` and `Pry.into()` and `Pry.repl()` are all aliases of
|
119
174
|
oneanother. They all start a Read-Eval-Print-Loop on the object they
|
120
175
|
receive as a parameter. In the case of no parameter they operate on
|
121
176
|
top-level (main). They can receive any object or a `Binding`
|
122
177
|
object as parameter.
|
178
|
+
* `obj.pry` and `pry(obj)` may also be used as alternative syntax to `Pry.start(obj)`
|
123
179
|
* If, for some reason you do not want to 'loop' then use `Pry.rep()`; it
|
124
180
|
only performs the Read-Eval-Print section of the REPL - it ends the
|
125
181
|
session after just one line of input. It takes the same parameters as
|
126
182
|
`Pry.repl()`
|
127
183
|
* Likewise `Pry.re()` only performs the Read-Eval section of the REPL,
|
128
|
-
it returns the result of the evaluation
|
184
|
+
it returns the result of the evaluation or an Exception object in
|
185
|
+
case of error. It also takes the same parameters as `Pry.repl()`
|
129
186
|
* Similarly `Pry.r()` only performs the Read section of the REPL, only
|
130
|
-
returning the Ruby expression (as a string)
|
131
|
-
|
187
|
+
returning the Ruby expression (as a string). It takes the same parameters as all the others.
|
188
|
+
|
189
|
+
### Session commands
|
190
|
+
|
191
|
+
Pry supports a few commands inside the session itself. These commands are
|
192
|
+
not methods and must start at the beginning of a line, with no
|
193
|
+
whitespace in between.
|
132
194
|
|
133
|
-
|
195
|
+
If you want to access a method of the same name, prefix the invocation by whitespace.
|
134
196
|
|
135
197
|
* Typing `!` on a line by itself will refresh the REPL - useful for
|
136
198
|
getting you out of a situation if the parsing process
|
137
199
|
goes wrong.
|
138
|
-
* `
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
200
|
+
* `status` shows status information about the current session.
|
201
|
+
* `help` shows the list of session commands with brief explanations.
|
202
|
+
* `exit` or `quit` or `back` will end the current Pry session and go
|
203
|
+
back to the calling process or back one level of nesting (if there
|
204
|
+
are nested sessions).
|
205
|
+
* `exit_program` or `quit_program` will end the currently running
|
206
|
+
program.
|
207
|
+
* `nesting` shows Pry nesting information.
|
208
|
+
* `jump_to <nest_level>` unwinds the Pry stack (nesting level) until the appropriate nesting level is reached
|
209
|
+
-- as per the output of `nesting`
|
210
|
+
* `exit_all` breaks out of all Pry nesting levels and returns to the
|
211
|
+
calling process.
|
212
|
+
* You can type `Pry.start(obj)` or `obj.pry` to nest another Pry session within the
|
143
213
|
current one with `obj` as the receiver of the new session. Very useful
|
144
214
|
when exploring large or complicated runtime state.
|
145
215
|
|
data/lib/pry.rb
CHANGED
@@ -3,45 +3,77 @@
|
|
3
3
|
|
4
4
|
direc = File.dirname(__FILE__)
|
5
5
|
|
6
|
-
require 'rubygems'
|
7
|
-
require 'readline'
|
8
6
|
require 'ruby_parser'
|
9
7
|
require "#{direc}/pry/version"
|
8
|
+
require "#{direc}/pry/input"
|
9
|
+
require "#{direc}/pry/output"
|
10
10
|
|
11
11
|
module Pry
|
12
|
+
|
13
|
+
# class accessors
|
12
14
|
class << self
|
13
|
-
|
14
|
-
|
15
|
+
attr_reader :nesting
|
16
|
+
attr_reader :last_result
|
17
|
+
attr_accessor :default_prompt
|
18
|
+
attr_accessor :wait_prompt
|
19
|
+
attr_accessor :input
|
20
|
+
attr_accessor :output
|
21
|
+
end
|
22
|
+
|
23
|
+
@default_prompt = lambda do |v, nest|
|
24
|
+
if nest == 0
|
25
|
+
"pry(#{v.inspect})> "
|
26
|
+
else
|
27
|
+
"pry(#{v.inspect}):#{nest.inspect}> "
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
@wait_prompt = lambda do |v, nest|
|
32
|
+
if nest == 0
|
33
|
+
"pry(#{v.inspect})* "
|
34
|
+
else
|
35
|
+
"pry(#{v.inspect}):#{nest.inspect}* "
|
36
|
+
end
|
15
37
|
end
|
16
38
|
|
17
|
-
@
|
18
|
-
@
|
19
|
-
|
20
|
-
@
|
39
|
+
@output = Output.new
|
40
|
+
@input = Input.new
|
41
|
+
|
42
|
+
@nesting = []
|
21
43
|
|
22
|
-
|
23
|
-
|
44
|
+
def @nesting.level
|
45
|
+
last.is_a?(Array) ? last.first : nil
|
46
|
+
end
|
24
47
|
|
25
48
|
# loop
|
26
49
|
def self.repl(target=TOPLEVEL_BINDING)
|
27
|
-
|
28
|
-
target = target.instance_eval { binding }
|
29
|
-
end
|
30
|
-
|
50
|
+
target = binding_for(target)
|
31
51
|
target_self = target.eval('self')
|
32
|
-
|
52
|
+
output.session_start(target_self)
|
33
53
|
|
34
|
-
|
35
|
-
|
36
|
-
|
54
|
+
nesting_level = @nesting.size
|
55
|
+
|
56
|
+
# Make sure _ exists
|
57
|
+
target.eval("_ = Pry.last_result")
|
58
|
+
|
59
|
+
nesting_level_breakout = catch(:breakout) do
|
60
|
+
@nesting << [@nesting.size, target_self]
|
61
|
+
loop do
|
62
|
+
rep(target)
|
37
63
|
end
|
38
64
|
end
|
39
65
|
|
40
|
-
|
66
|
+
@nesting.pop
|
67
|
+
output.session_end(target_self)
|
41
68
|
|
69
|
+
# we only enter here if :breakout has been thrown
|
70
|
+
if nesting_level_breakout
|
71
|
+
throw :breakout, nesting_level_breakout if nesting_level != nesting_level_breakout
|
72
|
+
end
|
73
|
+
|
42
74
|
target_self
|
43
75
|
end
|
44
|
-
|
76
|
+
|
45
77
|
class << self
|
46
78
|
alias_method :into, :repl
|
47
79
|
alias_method :start, :repl
|
@@ -49,31 +81,25 @@ module Pry
|
|
49
81
|
|
50
82
|
# print
|
51
83
|
def self.rep(target=TOPLEVEL_BINDING)
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
value = re(target)
|
57
|
-
case value
|
58
|
-
when Exception
|
59
|
-
puts "#{value.class}: #{value.message}"
|
60
|
-
else
|
61
|
-
puts "=> #{value.inspect}"
|
62
|
-
end
|
84
|
+
target = binding_for(target)
|
85
|
+
output.print re(target)
|
63
86
|
end
|
64
87
|
|
65
88
|
# eval
|
66
89
|
def self.re(target=TOPLEVEL_BINDING)
|
67
|
-
target
|
90
|
+
target = binding_for(target)
|
91
|
+
@last_result = target.eval r(target)
|
92
|
+
target.eval("_ = Pry.last_result")
|
68
93
|
rescue StandardError => e
|
69
94
|
e
|
70
95
|
end
|
71
96
|
|
72
97
|
# read
|
73
98
|
def self.r(target=TOPLEVEL_BINDING)
|
99
|
+
target = binding_for(target)
|
74
100
|
eval_string = ""
|
75
101
|
loop do
|
76
|
-
val =
|
102
|
+
val = input.read(prompt(eval_string, target, nesting.level))
|
77
103
|
eval_string += "#{val}\n"
|
78
104
|
process_commands(val, eval_string, target)
|
79
105
|
|
@@ -82,24 +108,49 @@ module Pry
|
|
82
108
|
end
|
83
109
|
|
84
110
|
def self.process_commands(val, eval_string, target)
|
111
|
+
def eval_string.clear() replace("") end
|
112
|
+
|
85
113
|
case val
|
86
|
-
when "
|
114
|
+
when "exit_program", "quit_program"
|
115
|
+
output.exit_program
|
87
116
|
exit
|
88
117
|
when "!"
|
89
|
-
|
90
|
-
|
91
|
-
when "
|
92
|
-
|
118
|
+
output.refresh
|
119
|
+
eval_string.clear
|
120
|
+
when "help"
|
121
|
+
output.show_help
|
122
|
+
eval_string.clear
|
123
|
+
when "nesting"
|
124
|
+
output.show_nesting(nesting)
|
125
|
+
eval_string.clear
|
126
|
+
when "status"
|
127
|
+
output.show_status(nesting, target)
|
128
|
+
eval_string.clear
|
129
|
+
when "exit_all"
|
130
|
+
throw(:breakout, 0)
|
131
|
+
when "exit", "quit", "back"
|
132
|
+
output.exit
|
133
|
+
throw(:breakout, nesting.level)
|
134
|
+
when /jump_to\s*(\d*)/
|
135
|
+
nesting_level_breakout = ($~.captures).first.to_i
|
136
|
+
output.jump_to(nesting_level_breakout)
|
137
|
+
|
138
|
+
if nesting_level_breakout < 0 || nesting_level_breakout >= nesting.level
|
139
|
+
output.error_invalid_nest_level(nesting_level_breakout, nesting.level - 1)
|
140
|
+
eval_string.clear
|
141
|
+
else
|
142
|
+
throw(:breakout, nesting_level_breakout + 1)
|
143
|
+
end
|
93
144
|
end
|
94
145
|
end
|
95
146
|
|
96
|
-
def self.prompt(eval_string, target)
|
97
|
-
|
147
|
+
def self.prompt(eval_string, target, nest)
|
148
|
+
target_self = target.eval('self')
|
98
149
|
|
99
150
|
if eval_string.empty?
|
100
|
-
default_prompt.call(
|
151
|
+
default_prompt.call(target_self, nest)
|
101
152
|
else
|
102
|
-
wait_prompt.call(
|
153
|
+
wait_prompt.call(target_self, nest)
|
103
154
|
end
|
104
155
|
end
|
105
156
|
|
@@ -111,11 +162,25 @@ module Pry
|
|
111
162
|
true
|
112
163
|
end
|
113
164
|
|
114
|
-
def self.
|
115
|
-
|
165
|
+
def self.binding_for(target)
|
166
|
+
if target.is_a?(Binding)
|
167
|
+
target
|
168
|
+
else
|
169
|
+
if target == TOPLEVEL_BINDING.eval('self')
|
170
|
+
TOPLEVEL_BINDING
|
171
|
+
else
|
172
|
+
target.instance_eval { binding }
|
173
|
+
end
|
174
|
+
end
|
116
175
|
end
|
117
176
|
|
118
|
-
|
119
|
-
|
177
|
+
module ObjectExtensions
|
178
|
+
def pry(target=self)
|
179
|
+
Pry.start(Pry.binding_for(target))
|
180
|
+
end
|
120
181
|
end
|
121
182
|
end
|
183
|
+
|
184
|
+
class Object
|
185
|
+
include Pry::ObjectExtensions
|
186
|
+
end
|
data/lib/pry/input.rb
ADDED
data/lib/pry/output.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
module Pry
|
2
|
+
class Output
|
3
|
+
def refresh
|
4
|
+
puts "Refreshed REPL"
|
5
|
+
end
|
6
|
+
|
7
|
+
def session_start(obj)
|
8
|
+
puts "Beginning Pry session for #{obj.inspect}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def session_end(obj)
|
12
|
+
puts "Ending Pry session for #{obj.inspect}"
|
13
|
+
end
|
14
|
+
|
15
|
+
# the print component of READ-EVAL-PRINT-LOOP
|
16
|
+
def print(value)
|
17
|
+
case value
|
18
|
+
when Exception
|
19
|
+
puts "#{value.class}: #{value.message}"
|
20
|
+
else
|
21
|
+
puts "=> #{value.inspect}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def show_help
|
26
|
+
puts "Command list:"
|
27
|
+
puts "--"
|
28
|
+
puts "help This menu"
|
29
|
+
puts "status Show status information"
|
30
|
+
puts "! Refresh the REPL"
|
31
|
+
puts "nesting Show nesting information"
|
32
|
+
puts "exit/quit/back End the current Pry session"
|
33
|
+
puts "exit_all End all nested Pry sessions"
|
34
|
+
puts "exit_program/quit_program End the current program"
|
35
|
+
puts "jump_to <level> Jump to a Pry session further up the stack, exiting all sessions below"
|
36
|
+
end
|
37
|
+
|
38
|
+
def show_nesting(nesting)
|
39
|
+
puts "Nesting status:"
|
40
|
+
puts "--"
|
41
|
+
nesting.each do |level, obj|
|
42
|
+
if level == 0
|
43
|
+
puts "#{level}. #{obj.inspect} (Pry top level)"
|
44
|
+
else
|
45
|
+
puts "#{level}. #{obj.inspect}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def show_status(nesting, target)
|
51
|
+
puts "Status:"
|
52
|
+
puts "--"
|
53
|
+
puts "Receiver: #{target.eval('self').inspect}"
|
54
|
+
puts "Nesting level: #{nesting.level}"
|
55
|
+
puts "Local variables: #{target.eval("local_variables").inspect}"
|
56
|
+
puts "Last result: #{Pry.last_result.inspect}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def error_invalid_nest_level(nest_level, max_nest_level)
|
60
|
+
puts "Invalid nest level. Must be between 0 and #{max_nest_level}. Got #{nest_level}."
|
61
|
+
end
|
62
|
+
|
63
|
+
def exit() end
|
64
|
+
def jump_to(nesting_level_breakout) end
|
65
|
+
def exit_program() end
|
66
|
+
end
|
67
|
+
end
|
data/lib/pry/version.rb
CHANGED
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
- 1
|
8
8
|
- 2
|
9
|
-
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- John Mair (banisterfiend)
|
@@ -14,7 +15,7 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-12-
|
18
|
+
date: 2010-12-11 00:00:00 +13:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
@@ -25,6 +26,7 @@ dependencies:
|
|
25
26
|
requirements:
|
26
27
|
- - ">="
|
27
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 5
|
28
30
|
segments:
|
29
31
|
- 2
|
30
32
|
- 0
|
@@ -41,6 +43,8 @@ extensions: []
|
|
41
43
|
extra_rdoc_files: []
|
42
44
|
|
43
45
|
files:
|
46
|
+
- lib/pry/input.rb
|
47
|
+
- lib/pry/output.rb
|
44
48
|
- lib/pry/version.rb
|
45
49
|
- lib/pry.rb
|
46
50
|
- CHANGELOG
|
@@ -60,6 +64,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
60
64
|
requirements:
|
61
65
|
- - ">="
|
62
66
|
- !ruby/object:Gem::Version
|
67
|
+
hash: 3
|
63
68
|
segments:
|
64
69
|
- 0
|
65
70
|
version: "0"
|
@@ -68,6 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
68
73
|
requirements:
|
69
74
|
- - ">="
|
70
75
|
- !ruby/object:Gem::Version
|
76
|
+
hash: 3
|
71
77
|
segments:
|
72
78
|
- 0
|
73
79
|
version: "0"
|