pry 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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"
|