是否有可能中断正在运行的Ruby脚本,更新它,然后继续运行它?Ruby - 更新运行脚本
E.g.说你有这个脚本:
(0..10).each do |x|
puts x
end
你可以中断它,修改它,二号线阅读:
puts x * 2
然后继续执行?
(假设我们忽略琐碎的争论就像中断时间过短)
是否有可能中断正在运行的Ruby脚本,更新它,然后继续运行它?Ruby - 更新运行脚本
E.g.说你有这个脚本:
(0..10).each do |x|
puts x
end
你可以中断它,修改它,二号线阅读:
puts x * 2
然后继续执行?
(假设我们忽略琐碎的争论就像中断时间过短)
pry做一些事情有点像这样。
如果我有像这样的脚本test.rb
:
require 'pry'
result = []
5.times do |i|
result << "#{i}"
binding.pry if i == 2
end
puts "result is ", result.join(",")
然后在这是第3次迭代将暂停在断点处,我可以输入命令。如果我进入
edit test.rb
然后$EDITOR
(或纳米)将打开,我可以改变的源代码。当我退出文本编辑器时,pry将处于相同的断点处,但会重新运行现有代码,然后使用修改后的代码。这是一种子外壳,退出它将使原始代码恢复原始断点。退出此第二个断点后,我返回到bash,并且对该文件的编辑已保留。
您也可以传递一个方法名称,但它具有相同的效果(一个子shell),而不是将路径传递给edit
。因此,在这两种情况下,与上面的代码,如果我改变
result << "#{i}"
到
result << "#{i}*"
,我会看到无论是result is 0,1,2,3,4
或result is 0*,1*,2*,3*,4*
,但不result is 0,1,2,3*,4*
。
另外,在pry中,可以在断点处轻松编辑局部变量。例如:
require 'pry'
a = 1
binding.pry
puts a
如果键入a = 2
然后control+d
退出断点时,程序将打印2
像预期。您还可以使用运行时元编程来覆盖方法,实例变量等。
如果你想真正停止的过程中,你可以trap
中断信号,写目前的进展到一个文件,然后查找文件开始备份时:
progress_file = './script_progress.txt'
x = if File.exists?(progress_file)
File.read(progress_file).to_i
else
0
end
Signal.trap("INT") {
File.open(progress_file, 'w') { |f| f.write(x.to_s) }
exit
}
while x <= 10 do
puts x
x += 1
sleep(1)
end
结果:
$ rm script_progress.txt
$ ruby example.rb
0
1
2
3
^C$ cat script_progress.txt
4
# modify example.rb here, changing `puts x` to `puts x * 2`
$ ruby example.rb
8
10
12
14
16
18
20
你也可以使用at_exit
写入文件脚本退出任何时间(即使它只是正常完成):
progress_file = './script_progress.txt'
x = if File.exists?(progress_file)
File.read(progress_file).to_i
else
0
end
at_exit do
File.open(progress_file, 'w') { |f| f.write(x.to_s) }
end
while x <= 10 do
puts x
x += 1
sleep(1)
end
结果:
$ ruby example.rb
0
1
2
3
4
^Cexample.rb:16:in `sleep': Interrupt
from example.rb:16:in `<main>'
# modify example.rb to double the output again
$ ruby example.rb
10
12
14
16
18
20
如果你想的过程中继续运行,但为了能够在功能上切换不同的,你可以使用Process.kill
发送自定义信号:
pid = fork do
Signal.trap("USR1") {
$double = !$double
}
(0..10).each do |x|
puts $double ? x * 2 : x
sleep(1)
end
end
Process.detach(pid)
sleep(5)
Process.kill("USR1", pid)
sleep(6)
结果:
$ ruby example.rb
0
1
2
3
4
10
12
14
16
18
20
你可以用它来告诉ruby到load
一个文件再次:
File.open('print_number.rb', 'w') do |file|
file.write <<-contents
def print_number(x)
puts x
end
contents
end
pid = fork do
load './print_number.rb'
Signal.trap("USR1") {
load './print_number.rb'
}
(0..10).each do |x|
print_number(x)
sleep(1)
end
end
Process.detach(pid)
sleep(5)
File.open('print_number.rb', 'w') do |file|
file.write <<-contents
def print_number(x)
puts x * 2
end
contents
end
Process.kill("USR1", pid)
sleep(6)
结果:
$ ruby example.rb
0
1
2
3
4
10
12
14
16
18
20
有一些疯狂的黑客!红宝石真棒:) –
我也偶然发现了[本演示文稿](http://avdi.org/talks/rockymtnruby-2011/things-you-didnt-know-about-exceptions.html),它展示了一些同样疯狂的想法围绕流量控制 - 例如覆盖'raise'方法,继续执行。 –
你看着'load'重装'.rbs'? –