pry-timetravel 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 036cd80689a69996c2e965251b5eea0d8ad65958
4
- data.tar.gz: 4469ac880bb66bcea64873f4cc423f06c2603a76
3
+ metadata.gz: 3289f1ed4dd5e11a532a3d191c836616c520f5fa
4
+ data.tar.gz: 4cca9997562fb1a4ec503a758a869918981056df
5
5
  SHA512:
6
- metadata.gz: 948b4b85a37039e6829ff9a511ce3cf9c40f3c28d10b0f62e3d9726089c7e2280a9350553f903e15cbce77a36efc5334a1cd917a6c0cb23c0e35fd835204c727
7
- data.tar.gz: c045d71745d255a7e3c37978cc212a666cde0e40adb625deded075b8323283fc12c070b7377e7b8dcbb3267ba50c05cc97e43f24740d8e6c1c95d62b92e62a75
6
+ metadata.gz: 2cc90461d45f52950855ddd68fea6ce8182bb53a1baae82e64def62866ead46512dbab867b4b46cc5a92e11f20868e26876e97d2f2315cdb3a4754f08aea0284
7
+ data.tar.gz: 9d76b24d9980686987bf3b85a9d881652bc1eee7ab4ccc6274017bc8bc568a5ff4b2e6dfc9ff0dee54632b5fab99e2b249272a6683b103fadc7d4bb6d9f5ba18
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require spec_helper
3
+ --format d
@@ -0,0 +1,4 @@
1
+ ## 0.0.4 released 2017-01-02
2
+ * Add auto-snapshot mode via `snap -a`
3
+ * Include `snap next` and `snap step` aliases by default
4
+
data/README.md CHANGED
@@ -28,6 +28,10 @@ WARNING: Time travel may cause zombies.
28
28
 
29
29
  ## KNOWN ISSUES
30
30
 
31
+ ### General
32
+
33
+ * If you close a connection, like to a DB, it is closed for all snapshots
34
+
31
35
  ### Redis fork detection
32
36
 
33
37
  Redis checks to see if you forked and yells at you about needing to reconnect.
@@ -44,8 +48,12 @@ this to bypass safety measures:
44
48
  end
45
49
  end
46
50
 
47
- Maybe this will be a default hack that gets activated on your first snapshot at
48
- some point in the near future.
51
+ ## Similar Technology
52
+
53
+ * [Time Travel Python Debugger](https://github.com/TomOnTime/timetravelpdb)
54
+ * [Elm's Time Traveling Debugger](http://debug.elm-lang.org/)
55
+ * [OCaml Time Travel](http://caml.inria.fr/pub/docs/manual-ocaml-4.00/manual030.html#htoc195)
56
+ * [Chronon (java - proprietary)](http://chrononsystems.com/)
49
57
 
50
58
  ## Meta
51
59
 
data/Rakefile CHANGED
@@ -1,9 +1,9 @@
1
- # require 'rspec/core/rake_task'
1
+ require 'rspec/core/rake_task'
2
2
 
3
3
  task :default => :test
4
4
  task :spec => :test
5
5
 
6
- # RSpec::Core::RakeTask.new(:test)
6
+ RSpec::Core::RakeTask.new(:test)
7
7
 
8
8
  task :build do
9
9
  sh 'gem build *.gemspec'
@@ -4,6 +4,15 @@ require 'json'
4
4
 
5
5
  require_relative 'pry-timetravel/commands'
6
6
 
7
+ # = Timetravel!
8
+ #
9
+ # This is a pry plugin that keeps a pool of fork()ed process checkpoints, so
10
+ # that you can jump "back in time" to a previous place in your execution.
11
+ #
12
+ # == Forking Model
13
+ #
14
+ # When you create a snapshot, fork() is executed. The parent (original) process
15
+ # is suspended, and the new child process picks up where that left off.
7
16
  class PryTimetravel
8
17
  class << self
9
18
 
@@ -15,6 +24,7 @@ class PryTimetravel
15
24
  end
16
25
  end
17
26
 
27
+ # TODO: Should probably delay calling this until first snapshot
18
28
  at_exit do
19
29
  PryTimetravel.dlog "at_exit"
20
30
  if $root_parent && $$ != $root_parent
@@ -24,136 +34,200 @@ class PryTimetravel
24
34
  end
25
35
 
26
36
  def enter_suspended_animation
27
- dlog("Installing SIGCONT trap")
37
+ dlog("Suspend: Installing SIGCONT trap")
28
38
  old_sigcont_handler = Signal.trap('CONT') do
29
39
  dlog("Got a SIGCONT")
30
40
  end
31
41
 
32
- dlog("Installing SIGEXIT trap")
42
+ dlog("Suspend: Installing SIGEXIT trap")
33
43
  old_sigexit_handler = Signal.trap('EXIT') do
34
44
  dlog("got EXIT")
35
45
  Kernel.exit! true
36
46
  end
37
47
 
38
- dlog("Stopping myself")
48
+ dlog("Suspend: Stopping myself")
39
49
  Process.kill 'SIGSTOP', $$
40
- dlog("Back from SIGSTOP!")
41
50
 
42
- @snap_tree = JSON.parse(File.read("/tmp/timetravel_#{$root_parent}.json"))
51
+ dlog("Resume: Back from SIGSTOP! Loading snapshot tree")
52
+ load_global_timetravel_state
43
53
 
44
- dlog("Returning to old SIGCONT")
54
+ dlog("Resume: Returning to old SIGCONT")
45
55
  Signal.trap('CONT', old_sigcont_handler || "DEFAULT")
46
56
 
47
- dlog("Returning to old SIGEXIT")
57
+ dlog("Resume: Returning to old SIGEXIT")
48
58
  Signal.trap('EXIT', old_sigexit_handler || "DEFAULT")
49
59
  end
50
60
 
61
+ # The root parent is a sort of overseer of the whole tree, and something
62
+ # that is still alive and waiting for any signals from the outside world.
63
+ #
64
+ # Once any time travel starts, the parent forks and waits for its one and only direct child. All the other action happens in that child and its own children.
65
+ #
66
+ # If you USR1 this root parent, it will try to clean up the entire tree.
67
+ #
68
+ # It ignores INT, so that if you ^C the process it won't die so quickly.
51
69
  def start_root_parent
52
70
  $root_parent = $$
53
71
  child_pid = fork
54
72
  if child_pid
55
73
  Signal.trap('INT') do
56
- dlog("root-parent got INT, ignoring")
74
+ dlog("Root-parent: Got INT, ignoring")
57
75
  end
58
76
  Signal.trap('USR1') do
59
- dlog("root-parent got USR1, exiting")
60
- FileUtils.rm("/tmp/timetravel_#{$root_parent}.json")
77
+ dlog("Root-parent: Got USR1, exiting")
78
+ cleanup_global_timetravel_state
61
79
  Kernel.exit! true
62
80
  end
63
- dlog "Root parent waiting on #{child_pid}"
64
- # sleep
65
- # Process.waitall
81
+ dlog "Root parent: Waiting on child pid #{child_pid}"
66
82
  Process.waitpid child_pid
67
- # Process.waitpid 0
68
- dlog "Root parent exiting after wait"
83
+ dlog "Root parent: Exiting after wait"
84
+ cleanup_global_timetravel_state
69
85
  FileUtils.rm("/tmp/timetravel_#{$root_parent}.json")
70
86
  Kernel.exit! true
71
87
  end
72
88
  end
73
89
 
74
- def snapshot(target, parent = -> {}, child = -> {})
90
+ def auto_snapshot(target)
91
+ if !@do_trace
92
+ @trace = TracePoint.new(:line) do |tp|
93
+ # puts "trace status: #{$in_trace}"
94
+ if !$in_trace
95
+ $in_trace = true
96
+ # puts "path: #{File.expand_path(tp.path)}"
97
+ # puts "snapshotting trace"
98
+ # if ! (tp.defined_class.to_s =~ /Pry/)
99
+ # if tp.path =~ /<main>/
100
+ # if tp.path =~ /<main>/
101
+ # p [tp.path, tp.lineno, tp.event, tp.defined_class, Dir.pwd] # , tp.raised_exception]
102
+ # end
103
+ # if tp.path.include?(Dir.pwd) || tp.path =~ /<main>/
104
+ if File.expand_path(tp.path).include?(Dir.pwd)
105
+ p [tp.path, tp.lineno, tp.event, tp.defined_class, Dir.pwd] # , tp.raised_exception]
106
+ # p caller
107
+ # if tp.path =~ /<main>/
108
+ # # p tp
109
+ # p [tp.path, tp.lineno, tp.event] # , tp.raised_exception]
110
+ PryTimetravel.snapshot(
111
+ tp.binding,
112
+ # now_do: -> { run(args.join(" ")) unless args.empty? },
113
+ # on_return_do: -> { run('whereami') }
114
+ )
115
+ # end
116
+ end
117
+ $in_trace = false
118
+ end
119
+ end
120
+ @trace.enable
121
+ @do_trace = true
122
+ else
123
+ @trace.disable
124
+ @do_trace = false
125
+ end
126
+ end
127
+
128
+ def update_current_snapshot_info(target, parent_pid = nil)
129
+ my_pid = $$.to_s
130
+ @snap_tree ||= {}
131
+ @snap_tree[my_pid] ||= {}
132
+ @snap_tree[my_pid]["file"] = target.eval('__FILE__')
133
+ @snap_tree[my_pid]["line"] = target.eval('__LINE__')
134
+ @snap_tree[my_pid]["time"] = Time.now.to_f
135
+ @snap_tree[my_pid]["id"] = @id
136
+ @snap_tree[my_pid]["previous"] = parent_pid if parent_pid
137
+ end
138
+
139
+ def snapshot(target, opts = {})
140
+ opts[:now_do] ||= -> {}
141
+ opts[:on_return_do] ||= -> {}
75
142
 
76
143
  # We need a root-parent to keep the shell happy
77
144
  if ! $root_parent
78
145
  start_root_parent
79
146
  end
80
147
 
148
+ @id ||= 0
81
149
  @timetravel_root ||= $$
82
- @snap_tree ||= {
83
- $$.to_s => {
84
- "file" => target.eval('__FILE__'),
85
- "line" => target.eval('__LINE__'),
86
- }
87
- }
150
+ update_current_snapshot_info(target)
151
+ @id += 1
88
152
 
89
153
  parent_pid = $$
90
154
  child_pid = fork
91
155
 
92
156
  if child_pid
93
157
 
94
- dlog("I am parent #{parent_pid}: I have a child pid #{child_pid}")
158
+ dlog("Snapshot: I am parent #{parent_pid}. I have a child pid #{child_pid}. Now suspending.")
95
159
  enter_suspended_animation
96
160
 
97
- # Perform child operation
98
- child.()
161
+ dlog("Snapshot: Back from suspended animation. Running on_return_do.")
162
+ # Perform operation now that we've come back
163
+ opts[:on_return_do].()
99
164
 
100
165
  else
101
166
 
102
167
  child_pid = $$
103
- dlog("I am child #{child_pid}: I have a parent pid #{parent_pid}")
168
+ dlog("Snapshot: I am child #{child_pid}. I have a parent pid #{parent_pid}")
104
169
 
105
- @snap_tree[child_pid.to_s] = {
106
- "previous" => parent_pid,
107
- "file" => target.eval('__FILE__'),
108
- "line" => target.eval('__LINE__'),
109
- }
170
+ update_current_snapshot_info(target, parent_pid)
110
171
 
111
- # Perform parent operation
112
- parent.()
172
+ # Perform immediate operation
173
+ dlog("Snapshot: Running now_do.")
174
+ opts[:now_do].()
113
175
 
114
176
  end
115
177
  end
116
178
 
117
- def snapshot_list(target, indent = "", node = @timetravel_root.to_s)
118
- # @snap_tree && @snap_tree.keys.join(" ")
179
+ def snapshot_list(target, indent = "", node = @timetravel_root.to_s, my_indent = nil)
180
+ if node == ""
181
+ return "No snapshots"
182
+ end
119
183
  return unless node && node != ""
120
184
 
121
- # This shouldn't be here
122
- @snap_tree[$$.to_s]["file"] = target.eval('__FILE__')
123
- @snap_tree[$$.to_s]["line"] = target.eval('__LINE__')
185
+ # Freshen the current snapshot so it looks right
186
+ update_current_snapshot_info(target)
124
187
 
125
- out = "#{indent}#{node} #{@snap_tree[node]["file"]} #{@snap_tree[node]["line"]} #{ node == $$.to_s ? '***' : ''}\n"
126
- @snap_tree.keys.select { |n|
127
- @snap_tree[n]["previous"] == node.to_i
128
- }.each do |n|
129
- out += snapshot_list(target, indent + " ", n)
188
+ code_line = IO.readlines(@snap_tree[node]["file"])[@snap_tree[node]["line"].to_i - 1].chomp
189
+
190
+ out = "#{my_indent || indent}#{node} (#{@snap_tree[node]["id"]}) #{@snap_tree[node]["file"]} #{@snap_tree[node]["line"]} #{ node == $$.to_s ? '***' : ''} #{code_line}\n"
191
+ children = @snap_tree.keys.select { |n| @snap_tree[n]["previous"] == node.to_i }
192
+ if children.length == 1
193
+ out += snapshot_list(target, indent, children[0])
194
+ else
195
+ children.each { |n|
196
+ out += snapshot_list(target, indent + " ", n, indent + "> ")
197
+ }
130
198
  end
199
+ # @snap_tree.keys.select { |n|
200
+ # @snap_tree[n]["previous"] == node.to_i
201
+ # }.each do |n|
202
+ # out += snapshot_list(target, indent + " ", n)
203
+ # end
131
204
  out
132
205
  end
133
206
 
134
- def restore_snapshot(target, target_pid = nil, count = 1)
135
- dlog("Thinking about time travel... $$");
207
+ def restore_snapshot(target, target_pid = nil)
208
+ dlog("Restore: Trying to restore,");
136
209
 
137
210
  if target_pid.nil? && @snap_tree && ! @snap_tree[$$.to_s].nil?
138
- count = 1 if count < 1
139
211
  target_pid = @snap_tree[$$.to_s]["previous"]
140
- @snap_tree[$$.to_s]["file"] = target.eval('__FILE__')
141
- @snap_tree[$$.to_s]["line"] = target.eval('__LINE__')
142
212
  else
143
213
  target_pid = target_pid
144
214
  end
145
215
 
146
- if target_pid
147
- dlog("ME #{$$}: I found a target pid #{target_pid}! TIME TRAVEL TIME")
216
+ if target_pid && @snap_tree[target_pid.to_s]
217
+ dlog("Restore: I found a target pid #{target_pid}! TIME TRAVEL TIME")
148
218
 
149
- File.open("/tmp/timetravel_#{$root_parent}.json", 'w') do |f|
150
- f.puts @snap_tree.to_json
151
- end
219
+ # Update our current information of our current running snapshot
220
+ update_current_snapshot_info(target)
221
+
222
+ save_global_timetravel_state
152
223
 
224
+ # Bring our target back to life
153
225
  Process.kill 'SIGCONT', target_pid
226
+
227
+ # Go to sleeeeeeeppppp
154
228
  enter_suspended_animation
155
229
  else
156
- dlog("I was unable to time travel. Maybe it is a myth.");
230
+ dlog("Restore: I was unable to time travel. Maybe it is a myth.");
157
231
  puts "No previous snapshot found."
158
232
  end
159
233
  end
@@ -162,6 +236,32 @@ class PryTimetravel
162
236
  restore_snapshot(@timetravel_root) if @timetravel_root
163
237
  end
164
238
 
239
+ def global_timetravel_state_filename
240
+ "/tmp/timetravel_#{$root_parent}.json"
241
+ end
242
+
243
+ def save_global_timetravel_state
244
+ File.open(global_timetravel_state_filename, 'w') do |f|
245
+ global_state = {
246
+ snap_tree: @snap_tree,
247
+ do_trace: @do_trace
248
+ }
249
+ f.puts global_state.to_json
250
+ end
251
+ end
252
+
253
+ def load_global_timetravel_state
254
+ global_state = JSON.parse(File.read(global_timetravel_state_filename))
255
+ @snap_tree = global_state["snap_tree"]
256
+ @do_trace = global_state["do_trace"]
257
+ dlog("Loaded: " + @snap_tree.to_json)
258
+ @id = (@snap_tree.values.map{|snap| snap['id']}.max || 0) + 1
259
+ end
260
+
261
+ def cleanup_global_timetravel_state
262
+ FileUtils.rm(global_timetravel_state_filename)
263
+ end
264
+
165
265
  end
166
266
  end
167
267
 
@@ -4,10 +4,11 @@ Pry::Commands.create_command "snap", "Create a snapshot that you can later retur
4
4
  group 'Timetravel'
5
5
  banner <<-'BANNER'
6
6
  Usage: snap [cmd]
7
- snap --list
7
+ snap -l|--list List existing snapshots
8
+ snap -a|--auto Automatically take new snapshots
8
9
 
9
10
  This will add a snapshot which you can return to later.
10
-
11
+
11
12
  If you provide [cmd] then that command will also be run -- nice for "snap next" in conjunction with pry-byebug.
12
13
  BANNER
13
14
 
@@ -17,17 +18,19 @@ Pry::Commands.create_command "snap", "Create a snapshot that you can later retur
17
18
  # :optional_argument => true, :as => Integer
18
19
  opt.on :l, :list,
19
20
  "Show a list of existing snapshots"
21
+ opt.on :a, :auto, "Automatically take snapshots!"
20
22
  end
21
23
  def process
22
24
  if opts.l?
23
25
  output.puts PryTimetravel.snapshot_list(target)
26
+ elsif opts.a?
27
+ output.puts PryTimetravel.auto_snapshot(target)
24
28
  else
25
29
  PryTimetravel.snapshot(
26
30
  target,
27
- -> { run(args.join(" ")) unless args.empty? },
28
- -> { run('whereami') }
31
+ now_do: -> { run(args.join(" ")) unless args.empty? },
32
+ on_return_do: -> { run('whereami') }
29
33
  )
30
- # run('whereami')
31
34
  end
32
35
  end
33
36
  end
@@ -49,7 +52,7 @@ Pry::Commands.create_command "back", "Go back to the most recent snapshot" do
49
52
  opt.on :home, "Jump to the end of the original execution sequence"
50
53
  end
51
54
  def process
52
- if opts.h?
55
+ if opts.home?
53
56
  PryTimetravel.restore_root_snapshot(target)
54
57
  else
55
58
  target_pid = args.first ? args.first.to_i : opts[:p]
@@ -58,3 +61,6 @@ Pry::Commands.create_command "back", "Go back to the most recent snapshot" do
58
61
  end
59
62
  end
60
63
 
64
+ Pry::Commands.alias_command 'n', 'snap next'
65
+ Pry::Commands.alias_command 's', 'snap step'
66
+ Pry::Commands.alias_command 'p', 'back'
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'pry-timetravel'
3
- s.version = '0.0.3'
3
+ s.version = '0.0.4'
4
4
  s.summary = 'Timetravel'
5
5
  s.description = 'Allows you to timetravel!'
6
6
  s.homepage = 'https://github.com/awwaiid/pry-timetravel'
@@ -12,8 +12,6 @@ Gem::Specification.new do |s|
12
12
  s.add_dependency 'pry'
13
13
 
14
14
  s.add_development_dependency 'rake'
15
- # s.add_development_dependency 'rspec'
16
- # s.add_development_dependency 'yard'
17
- # s.add_development_dependency 'redcarpet'
18
- # s.add_development_dependency 'capybara'
15
+ s.add_development_dependency 'rspec'
16
+ s.add_development_dependency 'pry-byebug'
19
17
  end
@@ -1,11 +1,126 @@
1
1
  require './spec/spec_helper'
2
+ require 'pty'
3
+ require 'expect'
2
4
 
3
- describe "pry-timetravel commands" do
4
- describe "checkpoint" do
5
- it "forks a child"
5
+ pry_timetravel_cmd = "TERM=dumb pry -f --no-color --no-pager --no-history --noprompt -s timetravel"
6
+
7
+ describe "pry-timetravel" do
8
+ it "starts with no snapshots" do
9
+ PTY.spawn(pry_timetravel_cmd) do |reader, writer|
10
+ writer.puts("snap --list")
11
+ found = reader.expect(/No snapshots/,1)
12
+ expect(found).to be_truthy
13
+ end
14
+ end
15
+
16
+ it "Exits with 0 snapshots cleanly" do
17
+ saved_pid = nil
18
+ PTY.spawn(pry_timetravel_cmd) do |reader, writer, cmd_pid|
19
+ saved_pid = cmd_pid
20
+ writer.puts("snap --list")
21
+ found = reader.expect(/No snapshots/,1)
22
+ expect(found).to be_truthy
23
+ writer.puts("exit")
24
+ sleep 0.1 # Give time to exit?
25
+ end
26
+
27
+ pid_list = `ps h -o pid,ppid -s #{saved_pid}`.split(/\n/)
28
+ expect(pid_list.count).to be == 0
29
+ end
30
+
31
+ it "creates one snapshot" do
32
+ PTY.spawn(pry_timetravel_cmd) do |reader, writer, cmd_pid|
33
+ writer.puts("snap")
34
+ writer.puts("snap --list")
35
+
36
+ all1, pid1 = reader.expect(/^(\d+) \(0\) <main> 1/,1)
37
+ all2, pid2 = reader.expect(/^ (\d+) \(1\) <main> 1 \*\*\*/,1)
38
+
39
+ expect(pid1.to_i).to be > 0
40
+ expect(pid2.to_i).to be > 0
41
+
42
+ pid_list = `ps h -o pid,ppid,sess -s #{cmd_pid}`.split(/\n/)
43
+ # 0: shell
44
+ # 1: root
45
+ # 2: base snapshot
46
+ # 3: current running branch
47
+ expect(pid_list.count).to be == 4
48
+ end
49
+ end
50
+
51
+ it "creates second snapshot" do
52
+ PTY.spawn(pry_timetravel_cmd) do |reader, writer, cmd_pid|
53
+ writer.puts("snap")
54
+ writer.puts("snap")
55
+ writer.puts("snap --list")
56
+
57
+ all1, pid1 = reader.expect(/^(\d+) \(0\) <main> 1/,1)
58
+ all2, pid2 = reader.expect(/^ (\d+) \(1\) <main> 1/,1)
59
+ all3, pid3 = reader.expect(/^ (\d+) \(2\) <main> 1 \*\*\*/,1)
60
+
61
+ expect(pid1.to_i).to be > 0
62
+ expect(pid2.to_i).to be > 0
63
+ expect(pid3.to_i).to be > 0
64
+
65
+ pid_list = `ps h -o pid,ppid -s #{cmd_pid}`.split(/\n/)
66
+ # 0: shell
67
+ # 1: root
68
+ # 2: base snapshot
69
+ # 2: second snapshot
70
+ # 3: current running branch
71
+ expect(pid_list.count).to be == 5
72
+ end
73
+ end
74
+
75
+ it "Can time-travel to before a var existed" do
76
+ PTY.spawn(pry_timetravel_cmd) do |reader, writer, cmd_pid|
77
+ writer.puts("snap")
78
+ writer.puts("x = 7")
79
+ reader.expect(/^=> 7/,1)
80
+ writer.puts("x")
81
+ reader.expect(/^=> 7/,1)
82
+ writer.puts("back")
83
+ reader.expect(/^At the top level\./,1)
84
+ writer.puts("x")
85
+ result = reader.expect(/^NameError: undefined local variable or method `x' for main:Object/,1)
86
+ expect(result).to be_truthy
87
+ end
6
88
  end
7
- describe "timetravel" do
8
- it "reinvokes the saved checkpoint and kills itself"
89
+
90
+ it "Can time-travel to a previous var value" do
91
+ PTY.spawn(pry_timetravel_cmd) do |reader, writer, cmd_pid|
92
+ writer.puts("x = 7")
93
+ expect(reader.expect(/^=> 7/,1)).to be_truthy
94
+ writer.puts("snap")
95
+ writer.puts("x")
96
+ expect(reader.expect(/^=> 7/,1)).to be_truthy
97
+ writer.puts("snap")
98
+ writer.puts("x = 7")
99
+ reader.expect(/^=> 13/,1)
100
+ writer.puts("back")
101
+ reader.expect(/^At the top level\./,1)
102
+ writer.puts("x")
103
+ result = reader.expect(/^=> 7/,1)
104
+ expect(result).to be_truthy
105
+ end
9
106
  end
107
+
108
+ it "Can auto-checkpoint" do
109
+ PTY.spawn(pry_timetravel_cmd) do |reader, writer, cmd_pid|
110
+ writer.puts("snap -a")
111
+ writer.puts("x = 7")
112
+ expect(reader.expect(/^=> 7/,1)).to be_truthy
113
+ writer.puts("x")
114
+ expect(reader.expect(/^=> 7/,1)).to be_truthy
115
+ writer.puts("x = 13")
116
+ expect(reader.expect(/^=> 13/,1)).to be_truthy
117
+ writer.puts("back")
118
+ expect(reader.expect(/^At the top level\./,1)).to be_truthy
119
+ writer.puts("x")
120
+ result = reader.expect(/^=> 7/,1)
121
+ expect(result).to be_truthy
122
+ end
123
+ end
124
+
10
125
  end
11
126
 
@@ -1,6 +1,25 @@
1
1
  require 'rspec'
2
- require 'rspec/autorun'
2
+ require './lib/pry-timetravel'
3
3
 
4
- require 'pry/test/helper'
4
+ #require 'pry/test/helper'
5
5
 
6
- require './lib/pry-timetravel'
6
+ # in case the tests call reset_defaults, ensure we reset them to
7
+ # amended (test friendly) values
8
+ # class << Pry
9
+ # alias_method :orig_reset_defaults, :reset_defaults
10
+ # def reset_defaults
11
+ # orig_reset_defaults
12
+
13
+ # Pry.config.color = false
14
+ # Pry.config.pager = false
15
+ # Pry.config.should_load_rc = false
16
+ # Pry.config.should_load_local_rc= false
17
+ # Pry.config.should_load_plugins = false
18
+ # Pry.config.history.should_load = false
19
+ # Pry.config.history.should_save = false
20
+ # Pry.config.correct_indent = false
21
+ # Pry.config.hooks = Pry::Hooks.new
22
+ # Pry.config.collision_warning = false
23
+ # end
24
+ # end
25
+ # Pry.reset_defaults
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pry-timetravel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brock Wilcox
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-18 00:00:00.000000000 Z
11
+ date: 2017-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry-byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
41
69
  description: Allows you to timetravel!
42
70
  email:
43
71
  - awwaiid@thelackthereof.org
@@ -46,7 +74,9 @@ extensions: []
46
74
  extra_rdoc_files: []
47
75
  files:
48
76
  - ".gitignore"
77
+ - ".rspec"
49
78
  - ".travis.yml"
79
+ - CHANGES.md
50
80
  - Gemfile
51
81
  - LICENSE.MIT
52
82
  - README.md
@@ -76,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
106
  version: '0'
77
107
  requirements: []
78
108
  rubyforge_project:
79
- rubygems_version: 2.2.2
109
+ rubygems_version: 2.5.1
80
110
  signing_key:
81
111
  specification_version: 4
82
112
  summary: Timetravel