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 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"