pry-stack_explorer 0.3.1 → 0.3.2

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