pry-moves 0.1.1 → 0.1.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.
@@ -0,0 +1,88 @@
1
+ module PryStackExplorer
2
+
3
+ # This class represents a call-stack. It stores the
4
+ # frames that make up the stack and is responsible for updating the
5
+ # associated Pry instance to reflect the active frame. It is fully Enumerable.
6
+ class FrameManager
7
+ include Enumerable
8
+
9
+ # @return [Array<Binding>] The array of bindings that constitute
10
+ # the call-stack.
11
+ attr_accessor :bindings
12
+
13
+ # @return [Fixnum] The index of the active frame (binding) in the call-stack.
14
+ attr_accessor :binding_index
15
+
16
+ # @return [Hash] A hash for user defined data
17
+ attr_reader :user
18
+
19
+ # @return [Binding] The binding of the Pry instance before the
20
+ # FrameManager took over.
21
+ attr_reader :prior_binding
22
+
23
+ # @return [Array] The backtrace of the Pry instance before the
24
+ # FrameManager took over.
25
+ attr_reader :prior_backtrace
26
+
27
+ def initialize(bindings, _pry_)
28
+ self.bindings = bindings
29
+ self.binding_index = 0
30
+ @pry = _pry_
31
+ @user = {}
32
+ @prior_binding = _pry_.binding_stack.last
33
+ @prior_backtrace = _pry_.backtrace
34
+ end
35
+
36
+ def filter_bindings(vapid_frames: false)
37
+ bindings.reject do |binding|
38
+ !vapid_frames and
39
+ binding.local_variable_defined?(:vapid_frame)
40
+ end
41
+ end
42
+
43
+ # Iterate over all frames
44
+ def each(&block)
45
+ bindings.each(&block)
46
+ end
47
+
48
+ # Ensure the Pry instance's active binding is the frame manager's
49
+ # active binding.
50
+ def refresh_frame(run_whereami=true)
51
+ change_frame_to binding_index, run_whereami
52
+ end
53
+
54
+ # @return [Binding] The currently active frame
55
+ def current_frame
56
+ bindings[binding_index]
57
+ end
58
+
59
+ # Set the binding index (aka frame index), but raising an Exception when invalid
60
+ # index received. Also converts negative indices to their positive counterparts.
61
+ # @param [Fixnum] index The index.
62
+ def set_binding_index_safely(index)
63
+ if index > bindings.size - 1
64
+ raise Pry::CommandError, "At top of stack, cannot go further"
65
+ elsif index < 0
66
+ raise Pry::CommandError, "At bottom of stack, cannot go further"
67
+ else
68
+ self.binding_index = index
69
+ end
70
+ end
71
+
72
+ # Change active frame to the one indexed by `index`.
73
+ # Note that indexing base is `0`
74
+ # @param [Fixnum] index The index of the frame.
75
+ def change_frame_to(index, run_whereami=true)
76
+ set_binding_index_safely(index)
77
+
78
+ if @pry.binding_stack.empty?
79
+ @pry.binding_stack.replace [bindings[binding_index]]
80
+ else
81
+ @pry.binding_stack[-1] = bindings[binding_index]
82
+ end
83
+
84
+ @pry.run_command "whereami" if run_whereami
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,139 @@
1
+ # pry-stack_explorer.rb
2
+ # (C) John Mair (banisterfiend); MIT license
3
+
4
+ require "pry-stack_explorer/commands"
5
+ require "pry-stack_explorer/frame_manager"
6
+ require "pry-stack_explorer/when_started_hook"
7
+ require "binding_of_caller"
8
+
9
+ module PryStackExplorer
10
+
11
+ # short-hand for `PryStackExplorer`
12
+ ::SE = self
13
+
14
+ class << self
15
+ # @return [Hash] The hash storing all frames for all Pry instances for
16
+ # the current thread.
17
+ def frame_hash
18
+ Thread.current[:__pry_frame_managers__] ||= Hash.new { |h, k| h[k] = [] }
19
+ end
20
+
21
+ # Return the complete frame manager stack for the Pry instance
22
+ # @param [Pry] _pry_ The Pry instance associated with the frame
23
+ # managers
24
+ # @return [Array] The stack of Pry::FrameManager objections
25
+ def frame_managers(_pry_)
26
+ frame_hash[_pry_]
27
+ end
28
+
29
+ # Create a `Pry::FrameManager` object and push it onto the frame
30
+ # manager stack for the relevant `_pry_` instance.
31
+ # @param [Array] bindings The array of bindings (frames)
32
+ # @param [Pry] _pry_ The Pry instance associated with the frame manager
33
+ def create_and_push_frame_manager(bindings, _pry_, options={})
34
+ fm = FrameManager.new(bindings, _pry_)
35
+ frame_hash[_pry_].push fm
36
+ push_helper(fm, options)
37
+ fm
38
+ end
39
+
40
+ # Update the Pry instance to operate on the specified frame for the
41
+ # current frame manager.
42
+ # @param [PryStackExplorer::FrameManager] fm The active frame manager.
43
+ # @param [Hash] options The options hash.
44
+ def push_helper(fm, options={})
45
+ options = {
46
+ :initial_frame => 0
47
+ }.merge!(options)
48
+
49
+ fm.change_frame_to(options[:initial_frame], false)
50
+ end
51
+
52
+ private :push_helper
53
+
54
+ # Delete the currently active frame manager
55
+ # @param [Pry] _pry_ The Pry instance associated with the frame
56
+ # managers.
57
+ # @return [Pry::FrameManager] The popped frame manager.
58
+ def pop_frame_manager(_pry_)
59
+ return if frame_managers(_pry_).empty?
60
+
61
+ popped_fm = frame_managers(_pry_).pop
62
+ pop_helper(popped_fm, _pry_)
63
+ popped_fm
64
+ end
65
+
66
+ # Restore the Pry instance to operate on the previous
67
+ # binding. Also responsible for restoring Pry instance's backtrace.
68
+ # @param [Pry::FrameManager] popped_fm The recently popped frame manager.
69
+ # @param [Pry] _pry_ The Pry instance associated with the frame managers.
70
+ def pop_helper(popped_fm, _pry_)
71
+ if frame_managers(_pry_).empty?
72
+ if _pry_.binding_stack.empty?
73
+ _pry_.binding_stack.push popped_fm.prior_binding
74
+ else
75
+ _pry_.binding_stack[-1] = popped_fm.prior_binding
76
+ end
77
+
78
+ frame_hash.delete(_pry_)
79
+ else
80
+ frame_manager(_pry_).refresh_frame(false)
81
+ end
82
+
83
+ # restore backtrace
84
+ _pry_.backtrace = popped_fm.prior_backtrace
85
+ end
86
+
87
+ private :pop_helper
88
+
89
+ # Clear the stack of frame managers for the Pry instance
90
+ # @param [Pry] _pry_ The Pry instance associated with the frame managers
91
+ def clear_frame_managers(_pry_)
92
+ pop_frame_manager(_pry_) until frame_managers(_pry_).empty?
93
+ frame_hash.delete(_pry_) # this line should be unnecessary!
94
+ end
95
+
96
+ alias_method :delete_frame_managers, :clear_frame_managers
97
+
98
+ # @return [PryStackExplorer::FrameManager] The currently active frame manager
99
+ def frame_manager(_pry_)
100
+ frame_hash[_pry_].last
101
+ end
102
+
103
+ # Simple test to check whether two `Binding` objects are equal.
104
+ # @param [Binding] b1 First binding.
105
+ # @param [Binding] b2 Second binding.
106
+ # @return [Boolean] Whether the `Binding`s are equal.
107
+ def bindings_equal?(b1, b2)
108
+ (b1.eval('self').equal?(b2.eval('self'))) &&
109
+ (b1.eval('__method__') == b2.eval('__method__')) &&
110
+ (b1.eval('local_variables').map { |v| b1.eval("#{v}") }.equal?(
111
+ b2.eval('local_variables').map { |v| b2.eval("#{v}") }))
112
+ end
113
+ end
114
+ end
115
+
116
+ Pry.config.hooks.add_hook(:after_session, :delete_frame_manager) do |_, _, _pry_|
117
+ PryStackExplorer.clear_frame_managers(_pry_)
118
+ end
119
+
120
+ Pry.config.hooks.add_hook(:when_started, :save_caller_bindings, PryStackExplorer::WhenStartedHook.new)
121
+
122
+ # Import the StackExplorer commands
123
+ Pry.config.commands.import PryStackExplorer::Commands
124
+
125
+ # monkey-patch the whereami command to show some frame information,
126
+ # useful for navigating stack.
127
+ Pry.config.commands.before_command("whereami") do |num|
128
+ if PryStackExplorer.frame_manager(_pry_) && !internal_binding?(target)
129
+ bindings = PryStackExplorer.frame_manager(_pry_).bindings
130
+ binding_index = PryStackExplorer.frame_manager(_pry_).binding_index
131
+
132
+ info = "#{Pry::Helpers::Text.bold('Frame:')} "+
133
+ "#{binding_index}/#{bindings.size - 1} "+
134
+ "#{bindings[binding_index].frame_type}"
135
+
136
+ output.puts "\n"
137
+ output.puts info
138
+ end
139
+ end
@@ -0,0 +1,111 @@
1
+ module PryStackExplorer
2
+ class WhenStartedHook
3
+ include Pry::Helpers::BaseHelpers
4
+
5
+ def caller_bindings(target)
6
+ bindings = binding.callers
7
+
8
+ bindings = remove_internal_frames(bindings)
9
+ bindings = remove_debugger_frames(bindings)
10
+ bindings = bindings.drop(1) if pry_method_frame?(bindings.first)
11
+
12
+ mark_vapid_frames(bindings)
13
+
14
+ bindings
15
+ end
16
+
17
+ def call(target, options, _pry_)
18
+ target ||= _pry_.binding_stack.first if _pry_
19
+ options = {
20
+ :call_stack => true,
21
+ :initial_frame => 0
22
+ }.merge!(options)
23
+
24
+ return if !options[:call_stack]
25
+
26
+ if options[:call_stack].is_a?(Array)
27
+ bindings = options[:call_stack]
28
+
29
+ if !valid_call_stack?(bindings)
30
+ raise ArgumentError, ":call_stack must be an array of bindings"
31
+ end
32
+ else
33
+ bindings = caller_bindings(target)
34
+ end
35
+
36
+ PryStackExplorer.create_and_push_frame_manager bindings, _pry_, :initial_frame => options[:initial_frame]
37
+ end
38
+
39
+ private
40
+
41
+ def mark_vapid_frames(bindings)
42
+ stepped_out = false
43
+ actual_file, actual_method = nil, nil
44
+
45
+ bindings.each do |binding|
46
+ if stepped_out
47
+ if actual_file == binding.eval("__FILE__") and actual_method == binding.eval("__method__")
48
+ stepped_out = false
49
+ else
50
+ binding.local_variable_set :vapid_frame, true
51
+ end
52
+ elsif binding.frame_type == :block
53
+ stepped_out = true
54
+ actual_file = binding.eval("__FILE__")
55
+ actual_method = binding.eval("__method__")
56
+ end
57
+
58
+ if binding.local_variable_defined? :hide_from_stack
59
+ binding.local_variable_set :vapid_frame, true
60
+ end
61
+ end
62
+ end
63
+
64
+ # remove internal frames related to setting up the session
65
+ def remove_internal_frames(bindings)
66
+ start_frames = internal_frames_with_indices(bindings)
67
+ start_frame_index = start_frames.first.last
68
+
69
+ if start_frames.size >= 2
70
+ # god knows what's going on in here
71
+ idx1, idx2 = start_frames.take(2).map(&:last)
72
+ start_frame_index = idx2 if !nested_session?(bindings[idx1..idx2])
73
+ end
74
+
75
+ bindings.drop(start_frame_index + 1)
76
+ end
77
+
78
+ # remove pry-nav / pry-debugger / pry-byebug frames
79
+ def remove_debugger_frames(bindings)
80
+ bindings.drop_while { |b| b.eval("__FILE__") =~ /\/pry-/ }
81
+ end
82
+
83
+ # binding.pry frame
84
+ # @return [Boolean]
85
+ def pry_method_frame?(binding)
86
+ safe_send(binding.eval("__method__"), :==, :pry)
87
+ end
88
+
89
+ # When a pry session is started within a pry session
90
+ # @return [Boolean]
91
+ def nested_session?(bindings)
92
+ bindings.detect do |b|
93
+ safe_send(b.eval("__method__"), :==, :re) &&
94
+ safe_send(b.eval("self.class"), :equal?, Pry)
95
+ end
96
+ end
97
+
98
+ # @return [Array<Array<Binding, Fixnum>>]
99
+ def internal_frames_with_indices(bindings)
100
+ bindings.each_with_index.select do |b, i|
101
+ b.frame_type == :method &&
102
+ safe_send(b.eval("self"), :equal?, Pry) &&
103
+ safe_send(b.eval("__method__"), :==, :start)
104
+ end
105
+ end
106
+
107
+ def valid_call_stack?(bindings)
108
+ bindings.any? && bindings.all? { |v| v.is_a?(Binding) }
109
+ end
110
+ end
111
+ end
data/playground/demo.rb CHANGED
@@ -10,23 +10,54 @@ class A
10
10
  self
11
11
  end
12
12
 
13
+ def pre_bb
14
+ [1,2,3].each do
15
+ bb
16
+ end
17
+ puts :prebb
18
+ end
19
+
13
20
  def bb
14
- block do
15
- c = :some_code
21
+ binding.pry
22
+ block_func do
23
+ #cc
24
+ ff
25
+ a = :some_code
16
26
  end
17
27
  d = :some_code
18
28
  e = :some_code
19
29
  self
20
30
  end
21
31
 
22
- def block
32
+ def cc
33
+ dd_vapid
34
+ end
35
+
36
+ def dd_vapid
37
+ hide_from_stack = true
38
+ ee
39
+ end
40
+
41
+ def ee
42
+ binding.pry
43
+ end
44
+
45
+ def ff
46
+ e = :ff
47
+ end
48
+
49
+ def block_func
23
50
  e = :some_code
24
- yield
51
+ [1,1].each do
52
+ yield
53
+ end
25
54
  f = :other_code
26
55
  end
27
56
 
28
57
  end
29
58
 
30
- binding.pry
31
- A.new.aa.bb
59
+ #binding.pry
60
+ puts :aaa
61
+ A.new.aa.pre_bb
32
62
  c = :some_code
63
+ puts :zzz
data/playground/sand.rb CHANGED
@@ -1,9 +1,8 @@
1
- require 'pry'
2
1
  require 'pry-moves'
3
2
  #require 'pry-nav'
4
3
  require './tracer.rb'
5
4
 
6
- def debug?
5
+ def debucher?
7
6
  binding.pry
8
7
  true
9
8
  end
@@ -34,19 +33,20 @@ end
34
33
  #trace_events
35
34
 
36
35
  a = 1123
36
+ b = binding
37
37
 
38
38
  puts :prepare
39
39
 
40
40
  binding.pry
41
41
 
42
- A.new.aa.bb.cc
42
+ a = A.new.aa.bb.cc
43
43
 
44
44
  bb = 1
45
45
 
46
46
  exit
47
47
 
48
- pp = 123 if debug?
49
- binding.pry if debug?
48
+ pp = 123 if debucher?
49
+ binding.pry if debucher?
50
50
 
51
51
  binding.pry
52
52
 
@@ -0,0 +1,26 @@
1
+ require 'pry-moves'
2
+
3
+ Thread.current[:name] = 'main'
4
+
5
+ a = Thread.new do
6
+ Thread.current[:name] = 'a'
7
+ sleep 0.2
8
+ puts 'a'
9
+ binding.pry
10
+ puts 'aaaa'
11
+ sleep 1
12
+ puts 'aaa'
13
+ end
14
+
15
+ b = Thread.new do
16
+ Thread.current[:name] = 'b'
17
+ 20223000.times do
18
+ 432 * 3232
19
+ end
20
+ puts '2'
21
+ binding.pry
22
+ puts '22'
23
+ end
24
+
25
+ a.join
26
+ b.join
data/pry-moves.gemspec CHANGED
@@ -20,6 +20,6 @@ Gem::Specification.new do |gem|
20
20
  # Dependencies
21
21
  gem.required_ruby_version = '>= 1.8.7'
22
22
  gem.add_runtime_dependency 'pry', '>= 0.9.10', '< 0.11.0'
23
- gem.add_runtime_dependency 'pry-stack_explorer', '~> 0.4.9'
23
+ gem.add_runtime_dependency 'binding_of_caller', '>= 0.7'
24
24
  gem.add_development_dependency 'pry-remote', '~> 0.1.6'
25
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pry-moves
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garmoshka Mo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-20 00:00:00.000000000 Z
11
+ date: 2017-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -31,19 +31,19 @@ dependencies:
31
31
  - !ruby/object:Gem::Version
32
32
  version: 0.11.0
33
33
  - !ruby/object:Gem::Dependency
34
- name: pry-stack_explorer
34
+ name: binding_of_caller
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - "~>"
37
+ - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: 0.4.9
39
+ version: '0.7'
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
- - - "~>"
44
+ - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: 0.4.9
46
+ version: '0.7'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: pry-remote
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -70,18 +70,28 @@ files:
70
70
  - LICENSE
71
71
  - README.md
72
72
  - Rakefile
73
+ - dynamic_debug_experiments.rb
73
74
  - lib/pry-moves.rb
75
+ - lib/pry-moves/backtrace.rb
74
76
  - lib/pry-moves/cli.rb
75
77
  - lib/pry-moves/commands.rb
78
+ - lib/pry-moves/helpers.rb
76
79
  - lib/pry-moves/pry_ext.rb
77
80
  - lib/pry-moves/pry_remote_ext.rb
81
+ - lib/pry-moves/pry_wrapper.rb
78
82
  - lib/pry-moves/tracer.rb
79
83
  - lib/pry-moves/version.rb
84
+ - lib/pry-moves/watch.rb
85
+ - lib/pry-stack_explorer/commands.rb
86
+ - lib/pry-stack_explorer/frame_manager.rb
87
+ - lib/pry-stack_explorer/pry-stack_explorer.rb
88
+ - lib/pry-stack_explorer/when_started_hook.rb
80
89
  - playground/Gemfile
81
90
  - playground/README.md
82
91
  - playground/demo.rb
83
92
  - playground/recursions.rb
84
93
  - playground/sand.rb
94
+ - playground/threads.rb
85
95
  - playground/tracer.rb
86
96
  - pry-moves.gemspec
87
97
  homepage: https://github.com/garmoshka-mo/pry-moves
@@ -104,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
114
  version: '0'
105
115
  requirements: []
106
116
  rubyforge_project:
107
- rubygems_version: 2.5.1
117
+ rubygems_version: 2.6.8
108
118
  signing_key:
109
119
  specification_version: 4
110
120
  summary: Simple execution navigation for Pry.