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 CHANGED
@@ -1,3 +1,5 @@
1
+ 9/12/2010 version 0.1.3
2
+ * Got rid of rubygems dependency, refactored some code.
1
3
  8/12/2010 version 0.1.2
2
4
  * now rescuing SyntaxError as well as Racc::Parser error in valid_expression?
3
5
  8/12/2010 version 0.1.0
@@ -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: prying on an object at runtime
17
+ example: Interacting with an object at runtime
16
18
  ---------------------------------------
17
19
 
18
- With the `Pry.into()` method we can pry (open an irb-like session) on
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.into(Test)
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.into() without parameters begins a Pry session on top-level (main)
56
- Pry.into
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.into Hello
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.into @x
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.into` is simply an alias for `Pry.repl`). You can
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.into()` and `Pry.start()` and `Pry.repl()` are all aliases of
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. It also takes the same parameters as `Pry.repl()`
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) or an Exception object in
131
- case of error. It takes the same parameters as all the others.
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
- Pry supports a few commands inside the session itself:
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
- * `exit` or `quit` will end the current Pry session. Note that it will
139
- not end any containing Pry sessions if the current session happens
140
- to be nested.
141
- * `#exit` or `#quit` will end the currently running program.
142
- * You can type `Pry.into(obj)` to nest another Pry session within the
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
- attr_accessor :default_prompt, :wait_prompt,
14
- :session_start_msg, :session_end_msg
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
- @default_prompt = proc { |v| "pry(#{v})> " }
18
- @wait_prompt = proc { |v| "pry(#{v})* " }
19
- @session_start_msg = proc { |v| "Beginning Pry session for #{v}" }
20
- @session_end_msg = proc { |v| "Ending Pry session for #{v}" }
39
+ @output = Output.new
40
+ @input = Input.new
41
+
42
+ @nesting = []
21
43
 
22
- # useful for ending all Pry sessions currently active
23
- @dead = false
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
- if !target.is_a?(Binding)
28
- target = target.instance_eval { binding }
29
- end
30
-
50
+ target = binding_for(target)
31
51
  target_self = target.eval('self')
32
- puts session_start_msg.call(target_self)
52
+ output.session_start(target_self)
33
53
 
34
- loop do
35
- if catch(:pop) { rep(target) } == :return || @dead
36
- break
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
- puts session_end_msg.call(target_self)
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
- if !target.is_a?(Binding)
53
- target = target.instance_eval { binding }
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.eval r(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 = Readline.readline(prompt(eval_string, target), true)
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 "#exit", "#quit"
114
+ when "exit_program", "quit_program"
115
+ output.exit_program
87
116
  exit
88
117
  when "!"
89
- eval_string.replace("")
90
- puts "Refreshed REPL."
91
- when "exit", "quit"
92
- throw(:pop, :return)
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
- context = target.eval('self')
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(context)
151
+ default_prompt.call(target_self, nest)
101
152
  else
102
- wait_prompt.call(context)
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.kill
115
- @dead = true
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
- def self.revive
119
- @dead = false
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
@@ -0,0 +1,9 @@
1
+ require 'readline'
2
+
3
+ module Pry
4
+ class Input
5
+ def read(prompt)
6
+ Readline.readline(prompt, true)
7
+ end
8
+ end
9
+ end
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Pry
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
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
- version: 0.1.2
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-09 00:00:00 +13:00
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"