pry-stack_explorer 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -5,9 +5,9 @@ pry-stack_explorer
5
5
 
6
6
  _Walk the stack in a Pry session_
7
7
 
8
- **Please note, pry-stack_explorer has not been officially released yet and the prerelease gem that is available is NOT compatible with the current Pry gem (0.9.7.4).
9
- The prerelease gem only exists for testing purposes among Pry core committers. This gem will be fully available soon, when the next Pry version (0.9.8) is released.**
10
-
8
+ **Please note, this is a first release for `pry-stack_explorer` and as
9
+ such it may still have teething problems. If you encounter any
10
+ quirks or crashes please [file an issue](https://github.com/pry/pry-stack_explorer/issues)**
11
11
 
12
12
  pry-stack_explorer is a plugin for the [Pry](http://pry.github.com)
13
13
  REPL that enables the user to navigate the call-stack.
@@ -19,17 +19,25 @@ Unlike `ruby-debug`, pry-stack_explorer incurs no runtime cost and
19
19
  enables navigation right up the call-stack to the birth of the
20
20
  program.
21
21
 
22
- pry-stack_explorer is currently designed to work on MRI and
23
- Ruby 1.9.2+ (including 1.9.3). Support for other Ruby versions and
22
+ pry-stack_explorer is currently designed to work on **MRI and
23
+ Ruby 1.9.2+ (including 1.9.3)**. Support for other Ruby versions and
24
24
  implementations is planned for the future.
25
25
 
26
- The `up`, `down`, `frame` and `show-stack` commands are provided.
26
+ The `up`, `down`, `frame` and `show-stack` commands are provided. See
27
+ Pry's in-session help for more information on any of these commands.
28
+
29
+ **How to use:**
27
30
 
28
- Please note that this is a first release and may have some teething problems, feel free to file an [issue](https://github.com/banister/pry-stack_explorer) if you encounter any problems.
31
+ After installing `pry-stack_explorer`, just start Pry as normal (typically via a `binding.pry`), the stack_explorer plugin will be detected and used automatically.
29
32
 
30
33
  * Install the [gem](https://rubygems.org/gems/pry-stack_explorer): `gem install pry-stack_explorer`
31
34
  * Read the [documentation](http://rdoc.info/github/banister/pry-stack_explorer/master/file/README.md)
32
- * See the [source code](http://github.com/banister/pry-stack_explorer)
35
+ * See the [source code](http://github.com/pry/pry-stack_explorer)
36
+
37
+ **Caveats:**
38
+
39
+ Does not yet play nicely with [pry-nav](https://github.com/nixme/pry-nav) plugin. It is not recommend to use them both
40
+ at the same time. Compatibility with `pry-nav` will be provided soon.
33
41
 
34
42
  Example: Moving around between frames
35
43
  --------
@@ -43,10 +51,10 @@ Showing all accessible frames in stack:
43
51
  #1 [block] block in b <Object#b()>
44
52
  #2 [method] b <Object#b()>
45
53
  #3 [method] alphabet <Object#alphabet(y)>
46
- #4 [class] <class:J>
47
- #5 [block] block in <main>
48
- #6 [eval] <main>
49
- #7 [top] <main>
54
+ #4 [class] <class:J>
55
+ #5 [block] block in <main>
56
+ #6 [eval] <main>
57
+ #7 [top] <main>
50
58
  [9] pry(J)> frame 3
51
59
 
52
60
  Frame number: 3/7
@@ -54,14 +62,14 @@ Frame type: method
54
62
 
55
63
  From: /Users/john/ruby/projects/pry-stack_explorer/examples/example.rb @ line 10 in Object#alphabet:
56
64
 
57
- 5:
65
+ 5:
58
66
  6: require 'pry-stack_explorer'
59
- 7:
67
+ 7:
60
68
  8: def alphabet(y)
61
69
  9: x = 20
62
70
  => 10: b
63
71
  11: end
64
- 12:
72
+ 12:
65
73
  13: def b
66
74
  14: x = 30
67
75
  15: proc {
@@ -81,11 +89,11 @@ From: /Users/john/ruby/projects/pry-stack_explorer/examples/example2.rb @ line 1
81
89
  10: beta
82
90
  11: puts x
83
91
  12: end
84
- 13:
92
+ 13:
85
93
  14: def beta
86
94
  => 15: binding.pry
87
95
  16: end
88
- 17:
96
+ 17:
89
97
  18: alpha
90
98
  [1] pry(main)> show-stack
91
99
 
@@ -93,8 +101,8 @@ Showing all accessible frames in stack:
93
101
  --
94
102
  => #0 [method] beta <Object#beta()>
95
103
  #1 [method] alpha <Object#alpha()>
96
- #2 [eval] <main>
97
- #3 [top] <main>
104
+ #2 [eval] <main>
105
+ #3 [top] <main>
98
106
  [2] pry(main)> up
99
107
 
100
108
  Frame number: 1/3
@@ -102,15 +110,15 @@ Frame type: method
102
110
 
103
111
  From: /Users/john/ruby/projects/pry-stack_explorer/examples/example2.rb @ line 10 in Object#alpha:
104
112
 
105
- 5:
106
- 6:
107
- 7:
113
+ 5:
114
+ 6:
115
+ 7:
108
116
  8: def alpha
109
117
  9: x = "hello"
110
118
  => 10: beta
111
119
  11: puts x
112
120
  12: end
113
- 13:
121
+ 13:
114
122
  14: def beta
115
123
  15: binding.pry
116
124
  [3] pry(main)> x = "goodbye"
@@ -10,6 +10,9 @@ require "binding_of_caller"
10
10
 
11
11
  module PryStackExplorer
12
12
 
13
+ # short-hand for `PryStackExplorer`
14
+ ::SE = self
15
+
13
16
  class << self
14
17
  # @return [Hash] The hash storing all frames for all Pry instances for
15
18
  # the current thread.
@@ -159,17 +159,17 @@ module PryStackExplorer
159
159
 
160
160
  end
161
161
 
162
- # TODO: currently using `arg_string` as a work-around for a Slop
163
- # bug where `-2` (negative number) is interpreted as a
164
- # non-existent option rather than a non-option
165
162
  create_command "frame", "Switch to a particular frame. Accepts numeric parameter for the target frame to switch to (use with show-stack). Negative frame numbers allowed." do
166
163
  include FrameHelpers
167
164
 
168
165
  banner <<-BANNER
169
166
  Usage: frame [OPTIONS]
170
167
  Switch to a particular frame. Accepts numeric parameter for the target frame to switch to (use with show-stack). Negative frame numbers allowed.
171
- e.g: frame 4
172
- e.g: frame -2
168
+ When given no parameter show information about the current frame.
169
+
170
+ e.g: frame 4 #=> jump to the 4th frame
171
+ e.g: frame -2 #=> jump to the second-to-last frame
172
+ e.g: frame #=> show information info about current frame
173
173
  BANNER
174
174
 
175
175
  def process
@@ -1,3 +1,3 @@
1
1
  module PryStackExplorer
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.2"
3
3
  end
@@ -2,13 +2,31 @@ module PryStackExplorer
2
2
  class WhenStartedHook
3
3
 
4
4
  def caller_bindings(target)
5
- if binding.of_caller(8).eval('__method__') == :pry
6
- drop_number = 9
7
- else
8
- drop_number = 8
5
+ bindings = binding.callers
6
+
7
+ start_frames = bindings.each_with_index.select do |b, i|
8
+ b.frame_type == :method &&
9
+ b.eval("self") == Pry &&
10
+ b.eval("__method__") == :start
9
11
  end
10
12
 
11
- bindings = binding.callers.drop(drop_number)
13
+ start_frame_index = start_frames.first.last
14
+
15
+ if start_frames.size >= 2
16
+ idx1, idx2 = start_frames.take(2).map(&:last)
17
+
18
+ is_nested_session = bindings[idx1..idx2].detect do |b|
19
+ b.eval("__method__") == :re &&
20
+ b.eval("self.class") == Pry
21
+ end
22
+
23
+ start_frame_index = idx2 if !is_nested_session
24
+ end
25
+
26
+ bindings = bindings.drop(start_frame_index + 1)
27
+
28
+ bindings = bindings.drop(1) if bindings.first.eval("__method__") == :pry
29
+ bindings = bindings.drop_while { |b| b.eval("self.inspect") =~ /PryNav/ }
12
30
 
13
31
  # Use the binding returned by #of_caller if possible (as we get
14
32
  # access to frame_type).
@@ -2,18 +2,18 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "pry-stack_explorer"
5
- s.version = "0.3.1"
5
+ s.version = "0.3.2"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["John Mair (banisterfiend)"]
9
- s.date = "2012-01-25"
9
+ s.date = "2012-02-04"
10
10
  s.description = "Walk the stack in a Pry session"
11
11
  s.email = "jrmair@gmail.com"
12
12
  s.files = [".gemtest", ".gitignore", ".travis.yml", ".yardopts", "CHANGELOG", "Gemfile", "LICENSE", "README.md", "Rakefile", "examples/example.rb", "examples/example2.rb", "lib/pry-stack_explorer.rb", "lib/pry-stack_explorer/commands.rb", "lib/pry-stack_explorer/frame_manager.rb", "lib/pry-stack_explorer/version.rb", "lib/pry-stack_explorer/when_started_hook.rb", "pry-stack_explorer.gemspec", "test/helper.rb", "test/test_commands.rb", "test/test_frame_manager.rb", "test/test_stack_explorer.rb", "tester.rb"]
13
13
  s.homepage = "https://github.com/banister"
14
14
  s.require_paths = ["lib"]
15
15
  s.required_ruby_version = Gem::Requirement.new(">= 1.9.2")
16
- s.rubygems_version = "1.8.10"
16
+ s.rubygems_version = "1.8.15"
17
17
  s.summary = "Walk the stack in a Pry session"
18
18
  s.test_files = ["test/helper.rb", "test/test_commands.rb", "test/test_frame_manager.rb", "test/test_stack_explorer.rb"]
19
19
 
@@ -1,353 +1,381 @@
1
- require 'helper'
2
-
3
- describe PryStackExplorer do
4
-
5
- describe "Pry.start" do
6
- before do
7
- Pry.config.hooks.add_hook(:when_started, :save_caller_bindings, WhenStartedHook)
8
- Pry.config.hooks.add_hook(:after_session, :delete_frame_manager, AfterSessionHook)
9
-
10
- @o = Object.new
11
- class << @o; attr_reader :frame; end
12
- def @o.bing() bong end
13
- def @o.bong() bang end
14
- def @o.bang() Pry.start(binding) end
15
- end
16
-
17
- after do
18
- Pry.config.hooks.delete_hook(:when_started, :save_caller_bindings)
19
- Pry.config.hooks.delete_hook(:after_session, :delete_frame_manager)
20
- end
21
-
22
- describe ":initial_frame option" do
23
- it 'should default to first frame when no option provided' do
24
- redirect_pry_io(StringIO.new("@frame = __method__\nexit\n"), out=StringIO.new) do
25
- @o.bing
26
- end
27
-
28
- @o.frame.should == :bang
29
- end
30
-
31
- it 'should begin session at specified frame' do
32
- o = Object.new
33
- class << o; attr_reader :frame; end
34
- def o.bing() bong end
35
- def o.bong() bang end
36
- def o.bang() Pry.start(binding, :initial_frame => 1) end #*
37
-
38
- redirect_pry_io(StringIO.new("@frame = __method__\nexit-all\n"), out=StringIO.new) do
39
- o.bing
40
- end
41
-
42
- o.frame.should == :bong
43
- end
44
-
45
- it 'should begin session at specified frame when using :call_stack' do
46
- o = Object.new
47
- class << o; attr_accessor :frame; end
48
- def o.alpha() binding end
49
- def o.beta() binding end
50
- def o.gamma() binding end
51
-
52
- redirect_pry_io(StringIO.new("@frame = __method__\nexit\n"), out=StringIO.new) do
53
- Pry.start(binding, :call_stack => [o.gamma, o.beta, o.alpha], :initial_frame => 1)
54
- end
55
-
56
- o.frame.should == :beta
57
- end
58
-
59
- end
60
-
61
- describe ":call_stack option" do
62
- it 'should invoke a session with the call stack set' do
63
- redirect_pry_io(StringIO.new("show-stack\nexit\n"), out=StringIO.new) do
64
- @o.bing
65
- end
66
-
67
- out.string.should =~ /bang.*?bong.*?bing/m
68
- end
69
-
70
- it 'should set no call stack when :call_stack => false' do
71
- o = Object.new
72
- def o.bing() bong end
73
- def o.bong() bang end
74
- def o.bang() Pry.start(binding, :call_stack => false) end
75
-
76
- redirect_pry_io(StringIO.new("show-stack\nexit\n"), out=StringIO.new) do
77
- o.bing
78
- end
79
-
80
- out.string.should =~ /No caller stack/
81
- end
82
-
83
- it 'should set custom call stack when :call_stack => [b1, b2]' do
84
- o = Object.new
85
- def o.alpha() binding end
86
- def o.beta() binding end
87
- def o.gamma() binding end
88
-
89
- redirect_pry_io(StringIO.new("show-stack\nexit\n"), out=StringIO.new) do
90
- Pry.start(binding, :call_stack => [o.beta, o.gamma, o.alpha])
91
- end
92
-
93
- out.string.should =~ /beta.*?gamma.*?alpha/m
94
- end
95
-
96
- it 'should raise if custom call stack does not contain bindings' do
97
- o = OpenStruct.new
98
- redirect_pry_io(StringIO.new("self.errors = _pry_.hooks.errors\nexit\n")) do
99
- Pry.start(o, :call_stack => [1, 2, 3])
100
- end
101
- o.errors.first.is_a?(ArgumentError).should == true
102
- end
103
-
104
- it 'should raise if custom call stack is empty' do
105
- o = OpenStruct.new
106
- redirect_pry_io(StringIO.new("self.errors = _pry_.hooks.errors\nexit\n")) do
107
- Pry.start o, :call_stack => []
108
- end
109
- o.errors.first.is_a?(ArgumentError).should == true
110
- end
111
- end
112
- end
113
-
114
- describe "unit tests for PryStackExplorer class methods" do
115
- before do
116
- @pry_instance = Pry.new
117
- @bindings = [binding, binding]
118
- end
119
-
120
- after do
121
- PE.clear_frame_managers(@pry_instance)
122
- end
123
-
124
- describe "PryStackExplorer.create_and_push_frame_manager" do
125
-
126
- it "should create and push one new FrameManager" do
127
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
128
- PE.frame_manager(@pry_instance).is_a?(PE::FrameManager).should == true
129
- PE.frame_managers(@pry_instance).count.should == 1
130
- end
131
-
132
- it "should refresh Pry instance to use FrameManager's active binding" do
133
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
134
- @pry_instance.binding_stack.size.should == 1
135
- @pry_instance.binding_stack.first.should == @bindings.first
136
- end
137
-
138
- it 'should save prior binding in FrameManager instance' do
139
- _pry_ = Pry.new
140
- _pry_.binding_stack.push(b=binding)
141
- PryStackExplorer.create_and_push_frame_manager(@bindings, _pry_)
142
- PryStackExplorer.frame_manager(_pry_).prior_binding.should == b
143
- end
144
-
145
- describe ":initial_frame option" do
146
- it 'should start on specified frame' do
147
- PE.create_and_push_frame_manager(@bindings, @pry_instance, :initial_frame => 1)
148
- @pry_instance.binding_stack.size.should == 1
149
- @pry_instance.binding_stack.first.should == @bindings.last
150
- end
151
-
152
- describe "negative numbers" do
153
- it 'should work with negative frame number (-1)' do
154
- PE.create_and_push_frame_manager(@bindings, @pry_instance, :initial_frame => -1)
155
- @pry_instance.binding_stack.size.should == 1
156
- @pry_instance.binding_stack.first.should == @bindings.last
157
- end
158
-
159
- it 'should work with negative frame number (-2)' do
160
- PE.create_and_push_frame_manager(@bindings, @pry_instance, :initial_frame => -2)
161
- @pry_instance.binding_stack.size.should == 1
162
- @pry_instance.binding_stack.first.should == @bindings.first
163
- end
164
- end
165
- end
166
-
167
- it 'should save prior backtrace in FrameManager instance' do
168
- _pry_ = Pry.new
169
- _pry_.backtrace = ["my backtrace"]
170
- PryStackExplorer.create_and_push_frame_manager(@bindings, _pry_)
171
- PryStackExplorer.frame_manager(_pry_).prior_backtrace.should == _pry_.backtrace
172
- end
173
-
174
- it "should create and push multiple FrameManagers" do
175
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
176
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
177
- PE.frame_managers(@pry_instance).count.should == 2
178
- end
179
-
180
- it 'should push FrameManagers to stacks based on Pry instance' do
181
- p2 = Pry.new
182
- bindings = [binding, binding]
183
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
184
- PE.create_and_push_frame_manager(bindings, p2)
185
- PE.frame_managers(@pry_instance).count.should == 1
186
- PE.frame_managers(p2).count.should == 1
187
- end
188
- end
189
-
190
- describe "PryStackExplorer.frame_manager" do
191
- it "should have the correct bindings" do
192
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
193
- PE.frame_manager(@pry_instance).bindings.should == @bindings
194
- end
195
-
196
- it "should return the last pushed FrameManager" do
197
- bindings = [binding, binding]
198
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
199
- PE.create_and_push_frame_manager(bindings, @pry_instance)
200
- PE.frame_manager(@pry_instance).bindings.should == bindings
201
- end
202
-
203
- it "should return the correct FrameManager for the given Pry instance" do
204
- bindings = [binding, binding]
205
- p2 = Pry.new
206
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
207
- PE.create_and_push_frame_manager(bindings, p2)
208
- PE.frame_manager(@pry_instance).bindings.should == @bindings
209
- PE.frame_manager(p2).bindings.should == bindings
210
- end
211
- end
212
-
213
- describe "PryStackExplorer.pop_frame_manager" do
214
- it "should remove FrameManager from stack" do
215
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
216
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
217
- PE.pop_frame_manager(@pry_instance)
218
- PE.frame_managers(@pry_instance).count.should == 1
219
- end
220
-
221
- it "should return the most recently added FrameManager" do
222
- bindings = [binding, binding]
223
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
224
- PE.create_and_push_frame_manager(bindings, @pry_instance)
225
- PE.pop_frame_manager(@pry_instance).bindings.should == bindings
226
- end
227
-
228
- it "should remove FrameManager from the appropriate stack based on Pry instance" do
229
- p2 = Pry.new
230
- bindings = [binding, binding]
231
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
232
- PE.create_and_push_frame_manager(bindings, p2)
233
- PE.pop_frame_manager(@pry_instance)
234
- PE.frame_managers(@pry_instance).count.should == 0
235
- PE.frame_managers(p2).count.should == 1
236
- end
237
-
238
- it "should remove key when no frames remaining for Pry instance" do
239
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
240
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
241
- PE.pop_frame_manager(@pry_instance)
242
- PE.pop_frame_manager(@pry_instance)
243
- PE.frame_hash.has_key?(@pry_instance).should == false
244
- end
245
-
246
- it 'should not change size of binding_stack when popping' do
247
- bindings = [bindings, bindings]
248
- PE.create_and_push_frame_manager(bindings, @pry_instance)
249
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
250
- PE.pop_frame_manager(@pry_instance)
251
- @pry_instance.binding_stack.size.should == 1
252
- end
253
-
254
- it 'should return nil when popping non-existent frame manager' do
255
- PE.pop_frame_manager(@pry_instance).should == nil
256
- end
257
-
258
- describe "restoring previous binding" do
259
- it 'should restore previous binding for Pry instance on pop, where previous binding is not first frame' do
260
- bindings = [binding, binding]
261
- PE.create_and_push_frame_manager(bindings, @pry_instance).binding_index = 1
262
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
263
- PE.pop_frame_manager(@pry_instance)
264
- @pry_instance.binding_stack.first.should == bindings[1]
265
- end
266
-
267
- it 'should restore previous binding for Pry instance on pop (previous frame frame manager)' do
268
- bindings = [binding, binding]
269
- PE.create_and_push_frame_manager(bindings, @pry_instance)
270
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
271
- PE.pop_frame_manager(@pry_instance)
272
- @pry_instance.binding_stack.first.should == bindings.first
273
- end
274
-
275
- it 'should restore previous binding for Pry instance on pop (no previous frame manager)' do
276
- b = binding
277
- @pry_instance.binding_stack = [b]
278
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
279
- PE.pop_frame_manager(@pry_instance)
280
- @pry_instance.binding_stack.first.should == b
281
- end
282
-
283
- it 'should restore previous binding for Pry instance on pop (no previous frame manager AND no empty binding_stack)' do
284
- b = binding
285
- @pry_instance.binding_stack = [b]
286
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
287
- @pry_instance.binding_stack.clear
288
- PE.pop_frame_manager(@pry_instance)
289
- @pry_instance.binding_stack.first.should == b
290
- end
291
- end
292
-
293
- describe "_pry_.backtrace" do
294
- it "should restore backtrace when frame is popped" do
295
- p1 = Pry.new
296
- bindings = [binding, binding]
297
- p1.backtrace = "my backtrace1"
298
- PE.create_and_push_frame_manager(bindings, p1)
299
- p1.backtrace = "my backtrace2"
300
- PE.create_and_push_frame_manager(bindings, p1)
301
- p1.backtrace = "my backtrace3"
302
-
303
- PE.pop_frame_manager(p1)
304
- p1.backtrace.should == "my backtrace2"
305
- PE.pop_frame_manager(p1)
306
- p1.backtrace.should == "my backtrace1"
307
- end
308
- end
309
- end
310
-
311
- describe "PryStackExplorer.clear_frame_managers" do
312
- it "should clear all FrameManagers for a Pry instance" do
313
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
314
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
315
- PE.clear_frame_managers(@pry_instance)
316
- PE.frame_hash.has_key?(@pry_instance).should == false
317
- end
318
-
319
- it "should clear all FrameManagers for a Pry instance but leave others untouched" do
320
- p2 = Pry.new
321
- bindings = [binding, binding]
322
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
323
- PE.create_and_push_frame_manager(bindings, p2)
324
- PE.clear_frame_managers(@pry_instance)
325
- PE.frame_managers(p2).count.should == 1
326
- PE.frame_hash.has_key?(@pry_instance).should == false
327
- end
328
-
329
- it "should remove key" do
330
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
331
- PE.create_and_push_frame_manager(@bindings, @pry_instance)
332
- PE.clear_frame_managers(@pry_instance)
333
- PE.frame_hash.has_key?(@pry_instance).should == false
334
- end
335
-
336
- describe "_pry_.backtrace" do
337
- it "should restore backtrace to initial one when frame managers are cleared" do
338
- p1 = Pry.new
339
- bindings = [binding, binding]
340
- p1.backtrace = "my backtrace1"
341
- PE.create_and_push_frame_manager(bindings, p1)
342
- p1.backtrace = "my backtrace2"
343
- PE.create_and_push_frame_manager(bindings, p1)
344
- p1.backtrace = "my backtrace3"
345
-
346
- PE.clear_frame_managers(p1)
347
- p1.backtrace.should == "my backtrace1"
348
- end
349
- end
350
-
351
- end
352
- end
353
- end
1
+ require 'helper'
2
+
3
+ describe PryStackExplorer do
4
+
5
+ describe "Pry.start" do
6
+ before do
7
+ Pry.config.hooks.add_hook(:when_started, :save_caller_bindings, WhenStartedHook)
8
+ Pry.config.hooks.add_hook(:after_session, :delete_frame_manager, AfterSessionHook)
9
+
10
+ @o = Object.new
11
+ class << @o; attr_reader :frame; end
12
+ def @o.bing() bong end
13
+ def @o.bong() bang end
14
+ def @o.bang() Pry.start(binding) end
15
+ end
16
+
17
+ after do
18
+ Pry.config.hooks.delete_hook(:when_started, :save_caller_bindings)
19
+ Pry.config.hooks.delete_hook(:after_session, :delete_frame_manager)
20
+ end
21
+
22
+ describe ":initial_frame option" do
23
+ it 'should default to first frame when no option provided' do
24
+ redirect_pry_io(StringIO.new("@frame = __method__\nexit\n"), out=StringIO.new) do
25
+ @o.bing
26
+ end
27
+
28
+ @o.frame.should == :bang
29
+ end
30
+
31
+ it 'should begin at correct frame even if Pry.start is monkey-patched (only works with one monkey-patch currently)' do
32
+ class << Pry
33
+ alias_method :old_start, :start
34
+
35
+ def start(*args, &block)
36
+ old_start(*args, &block)
37
+ end
38
+ end
39
+
40
+ o = Object.new
41
+ class << o; attr_reader :frames; end
42
+ def o.bing() bong end
43
+ def o.bong() bang end
44
+ def o.bang() Pry.start(binding) end
45
+
46
+ redirect_pry_io(InputTester.new(
47
+ "@frames = SE.frame_manager(_pry_).bindings.take(3)",
48
+ "exit-all")) do
49
+ o.bing
50
+ end
51
+
52
+ o.frames.map { |f| f.eval("__method__") }.should == [:bang, :bong, :bing]
53
+
54
+ class << Pry
55
+ alias_method :start, :old_start
56
+ end
57
+ end
58
+
59
+ it 'should begin session at specified frame' do
60
+ o = Object.new
61
+ class << o; attr_reader :frame; end
62
+ def o.bing() bong end
63
+ def o.bong() bang end
64
+ def o.bang() Pry.start(binding, :initial_frame => 1) end #*
65
+
66
+ redirect_pry_io(StringIO.new("@frame = __method__\nexit-all\n"), out=StringIO.new) do
67
+ o.bing
68
+ end
69
+
70
+ o.frame.should == :bong
71
+ end
72
+
73
+ it 'should begin session at specified frame when using :call_stack' do
74
+ o = Object.new
75
+ class << o; attr_accessor :frame; end
76
+ def o.alpha() binding end
77
+ def o.beta() binding end
78
+ def o.gamma() binding end
79
+
80
+ redirect_pry_io(StringIO.new("@frame = __method__\nexit\n"), out=StringIO.new) do
81
+ Pry.start(binding, :call_stack => [o.gamma, o.beta, o.alpha], :initial_frame => 1)
82
+ end
83
+
84
+ o.frame.should == :beta
85
+ end
86
+
87
+ end
88
+
89
+ describe ":call_stack option" do
90
+ it 'should invoke a session with the call stack set' do
91
+ redirect_pry_io(StringIO.new("show-stack\nexit\n"), out=StringIO.new) do
92
+ @o.bing
93
+ end
94
+
95
+ out.string.should =~ /bang.*?bong.*?bing/m
96
+ end
97
+
98
+ it 'should set no call stack when :call_stack => false' do
99
+ o = Object.new
100
+ def o.bing() bong end
101
+ def o.bong() bang end
102
+ def o.bang() Pry.start(binding, :call_stack => false) end
103
+
104
+ redirect_pry_io(StringIO.new("show-stack\nexit\n"), out=StringIO.new) do
105
+ o.bing
106
+ end
107
+
108
+ out.string.should =~ /No caller stack/
109
+ end
110
+
111
+ it 'should set custom call stack when :call_stack => [b1, b2]' do
112
+ o = Object.new
113
+ def o.alpha() binding end
114
+ def o.beta() binding end
115
+ def o.gamma() binding end
116
+
117
+ redirect_pry_io(StringIO.new("show-stack\nexit\n"), out=StringIO.new) do
118
+ Pry.start(binding, :call_stack => [o.beta, o.gamma, o.alpha])
119
+ end
120
+
121
+ out.string.should =~ /beta.*?gamma.*?alpha/m
122
+ end
123
+
124
+ it 'should raise if custom call stack does not contain bindings' do
125
+ o = OpenStruct.new
126
+ redirect_pry_io(StringIO.new("self.errors = _pry_.hooks.errors\nexit\n")) do
127
+ Pry.start(o, :call_stack => [1, 2, 3])
128
+ end
129
+ o.errors.first.is_a?(ArgumentError).should == true
130
+ end
131
+
132
+ it 'should raise if custom call stack is empty' do
133
+ o = OpenStruct.new
134
+ redirect_pry_io(StringIO.new("self.errors = _pry_.hooks.errors\nexit\n")) do
135
+ Pry.start o, :call_stack => []
136
+ end
137
+ o.errors.first.is_a?(ArgumentError).should == true
138
+ end
139
+ end
140
+ end
141
+
142
+ describe "unit tests for PryStackExplorer class methods" do
143
+ before do
144
+ @pry_instance = Pry.new
145
+ @bindings = [binding, binding]
146
+ end
147
+
148
+ after do
149
+ PE.clear_frame_managers(@pry_instance)
150
+ end
151
+
152
+ describe "PryStackExplorer.create_and_push_frame_manager" do
153
+
154
+ it "should create and push one new FrameManager" do
155
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
156
+ PE.frame_manager(@pry_instance).is_a?(PE::FrameManager).should == true
157
+ PE.frame_managers(@pry_instance).count.should == 1
158
+ end
159
+
160
+ it "should refresh Pry instance to use FrameManager's active binding" do
161
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
162
+ @pry_instance.binding_stack.size.should == 1
163
+ @pry_instance.binding_stack.first.should == @bindings.first
164
+ end
165
+
166
+ it 'should save prior binding in FrameManager instance' do
167
+ _pry_ = Pry.new
168
+ _pry_.binding_stack.push(b=binding)
169
+ PryStackExplorer.create_and_push_frame_manager(@bindings, _pry_)
170
+ PryStackExplorer.frame_manager(_pry_).prior_binding.should == b
171
+ end
172
+
173
+ describe ":initial_frame option" do
174
+ it 'should start on specified frame' do
175
+ PE.create_and_push_frame_manager(@bindings, @pry_instance, :initial_frame => 1)
176
+ @pry_instance.binding_stack.size.should == 1
177
+ @pry_instance.binding_stack.first.should == @bindings.last
178
+ end
179
+
180
+ describe "negative numbers" do
181
+ it 'should work with negative frame number (-1)' do
182
+ PE.create_and_push_frame_manager(@bindings, @pry_instance, :initial_frame => -1)
183
+ @pry_instance.binding_stack.size.should == 1
184
+ @pry_instance.binding_stack.first.should == @bindings.last
185
+ end
186
+
187
+ it 'should work with negative frame number (-2)' do
188
+ PE.create_and_push_frame_manager(@bindings, @pry_instance, :initial_frame => -2)
189
+ @pry_instance.binding_stack.size.should == 1
190
+ @pry_instance.binding_stack.first.should == @bindings.first
191
+ end
192
+ end
193
+ end
194
+
195
+ it 'should save prior backtrace in FrameManager instance' do
196
+ _pry_ = Pry.new
197
+ _pry_.backtrace = ["my backtrace"]
198
+ PryStackExplorer.create_and_push_frame_manager(@bindings, _pry_)
199
+ PryStackExplorer.frame_manager(_pry_).prior_backtrace.should == _pry_.backtrace
200
+ end
201
+
202
+ it "should create and push multiple FrameManagers" do
203
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
204
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
205
+ PE.frame_managers(@pry_instance).count.should == 2
206
+ end
207
+
208
+ it 'should push FrameManagers to stacks based on Pry instance' do
209
+ p2 = Pry.new
210
+ bindings = [binding, binding]
211
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
212
+ PE.create_and_push_frame_manager(bindings, p2)
213
+ PE.frame_managers(@pry_instance).count.should == 1
214
+ PE.frame_managers(p2).count.should == 1
215
+ end
216
+ end
217
+
218
+ describe "PryStackExplorer.frame_manager" do
219
+ it "should have the correct bindings" do
220
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
221
+ PE.frame_manager(@pry_instance).bindings.should == @bindings
222
+ end
223
+
224
+ it "should return the last pushed FrameManager" do
225
+ bindings = [binding, binding]
226
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
227
+ PE.create_and_push_frame_manager(bindings, @pry_instance)
228
+ PE.frame_manager(@pry_instance).bindings.should == bindings
229
+ end
230
+
231
+ it "should return the correct FrameManager for the given Pry instance" do
232
+ bindings = [binding, binding]
233
+ p2 = Pry.new
234
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
235
+ PE.create_and_push_frame_manager(bindings, p2)
236
+ PE.frame_manager(@pry_instance).bindings.should == @bindings
237
+ PE.frame_manager(p2).bindings.should == bindings
238
+ end
239
+ end
240
+
241
+ describe "PryStackExplorer.pop_frame_manager" do
242
+ it "should remove FrameManager from stack" do
243
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
244
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
245
+ PE.pop_frame_manager(@pry_instance)
246
+ PE.frame_managers(@pry_instance).count.should == 1
247
+ end
248
+
249
+ it "should return the most recently added FrameManager" do
250
+ bindings = [binding, binding]
251
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
252
+ PE.create_and_push_frame_manager(bindings, @pry_instance)
253
+ PE.pop_frame_manager(@pry_instance).bindings.should == bindings
254
+ end
255
+
256
+ it "should remove FrameManager from the appropriate stack based on Pry instance" do
257
+ p2 = Pry.new
258
+ bindings = [binding, binding]
259
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
260
+ PE.create_and_push_frame_manager(bindings, p2)
261
+ PE.pop_frame_manager(@pry_instance)
262
+ PE.frame_managers(@pry_instance).count.should == 0
263
+ PE.frame_managers(p2).count.should == 1
264
+ end
265
+
266
+ it "should remove key when no frames remaining for Pry instance" do
267
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
268
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
269
+ PE.pop_frame_manager(@pry_instance)
270
+ PE.pop_frame_manager(@pry_instance)
271
+ PE.frame_hash.has_key?(@pry_instance).should == false
272
+ end
273
+
274
+ it 'should not change size of binding_stack when popping' do
275
+ bindings = [bindings, bindings]
276
+ PE.create_and_push_frame_manager(bindings, @pry_instance)
277
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
278
+ PE.pop_frame_manager(@pry_instance)
279
+ @pry_instance.binding_stack.size.should == 1
280
+ end
281
+
282
+ it 'should return nil when popping non-existent frame manager' do
283
+ PE.pop_frame_manager(@pry_instance).should == nil
284
+ end
285
+
286
+ describe "restoring previous binding" do
287
+ it 'should restore previous binding for Pry instance on pop, where previous binding is not first frame' do
288
+ bindings = [binding, binding]
289
+ PE.create_and_push_frame_manager(bindings, @pry_instance).binding_index = 1
290
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
291
+ PE.pop_frame_manager(@pry_instance)
292
+ @pry_instance.binding_stack.first.should == bindings[1]
293
+ end
294
+
295
+ it 'should restore previous binding for Pry instance on pop (previous frame frame manager)' do
296
+ bindings = [binding, binding]
297
+ PE.create_and_push_frame_manager(bindings, @pry_instance)
298
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
299
+ PE.pop_frame_manager(@pry_instance)
300
+ @pry_instance.binding_stack.first.should == bindings.first
301
+ end
302
+
303
+ it 'should restore previous binding for Pry instance on pop (no previous frame manager)' do
304
+ b = binding
305
+ @pry_instance.binding_stack = [b]
306
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
307
+ PE.pop_frame_manager(@pry_instance)
308
+ @pry_instance.binding_stack.first.should == b
309
+ end
310
+
311
+ it 'should restore previous binding for Pry instance on pop (no previous frame manager AND no empty binding_stack)' do
312
+ b = binding
313
+ @pry_instance.binding_stack = [b]
314
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
315
+ @pry_instance.binding_stack.clear
316
+ PE.pop_frame_manager(@pry_instance)
317
+ @pry_instance.binding_stack.first.should == b
318
+ end
319
+ end
320
+
321
+ describe "_pry_.backtrace" do
322
+ it "should restore backtrace when frame is popped" do
323
+ p1 = Pry.new
324
+ bindings = [binding, binding]
325
+ p1.backtrace = "my backtrace1"
326
+ PE.create_and_push_frame_manager(bindings, p1)
327
+ p1.backtrace = "my backtrace2"
328
+ PE.create_and_push_frame_manager(bindings, p1)
329
+ p1.backtrace = "my backtrace3"
330
+
331
+ PE.pop_frame_manager(p1)
332
+ p1.backtrace.should == "my backtrace2"
333
+ PE.pop_frame_manager(p1)
334
+ p1.backtrace.should == "my backtrace1"
335
+ end
336
+ end
337
+ end
338
+
339
+ describe "PryStackExplorer.clear_frame_managers" do
340
+ it "should clear all FrameManagers for a Pry instance" do
341
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
342
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
343
+ PE.clear_frame_managers(@pry_instance)
344
+ PE.frame_hash.has_key?(@pry_instance).should == false
345
+ end
346
+
347
+ it "should clear all FrameManagers for a Pry instance but leave others untouched" do
348
+ p2 = Pry.new
349
+ bindings = [binding, binding]
350
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
351
+ PE.create_and_push_frame_manager(bindings, p2)
352
+ PE.clear_frame_managers(@pry_instance)
353
+ PE.frame_managers(p2).count.should == 1
354
+ PE.frame_hash.has_key?(@pry_instance).should == false
355
+ end
356
+
357
+ it "should remove key" do
358
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
359
+ PE.create_and_push_frame_manager(@bindings, @pry_instance)
360
+ PE.clear_frame_managers(@pry_instance)
361
+ PE.frame_hash.has_key?(@pry_instance).should == false
362
+ end
363
+
364
+ describe "_pry_.backtrace" do
365
+ it "should restore backtrace to initial one when frame managers are cleared" do
366
+ p1 = Pry.new
367
+ bindings = [binding, binding]
368
+ p1.backtrace = "my backtrace1"
369
+ PE.create_and_push_frame_manager(bindings, p1)
370
+ p1.backtrace = "my backtrace2"
371
+ PE.create_and_push_frame_manager(bindings, p1)
372
+ p1.backtrace = "my backtrace3"
373
+
374
+ PE.clear_frame_managers(p1)
375
+ p1.backtrace.should == "my backtrace1"
376
+ end
377
+ end
378
+
379
+ end
380
+ end
381
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pry-stack_explorer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-25 00:00:00.000000000 Z
12
+ date: 2012-02-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: binding_of_caller
16
- requirement: &70230861150480 !ruby/object:Gem::Requirement
16
+ requirement: &70251308218680 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.6.1
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70230861150480
24
+ version_requirements: *70251308218680
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: pry
27
- requirement: &70230861149000 !ruby/object:Gem::Requirement
27
+ requirement: &70251308217200 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.9.8
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70230861149000
35
+ version_requirements: *70251308217200
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: bacon
38
- requirement: &70230861147420 !ruby/object:Gem::Requirement
38
+ requirement: &70251308212380 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.1.0
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70230861147420
46
+ version_requirements: *70251308212380
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rake
49
- requirement: &70230861146780 !ruby/object:Gem::Requirement
49
+ requirement: &70251308190000 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: '0.9'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70230861146780
57
+ version_requirements: *70251308190000
58
58
  description: Walk the stack in a Pry session
59
59
  email: jrmair@gmail.com
60
60
  executables: []
@@ -103,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
103
  version: '0'
104
104
  requirements: []
105
105
  rubyforge_project:
106
- rubygems_version: 1.8.10
106
+ rubygems_version: 1.8.15
107
107
  signing_key:
108
108
  specification_version: 3
109
109
  summary: Walk the stack in a Pry session