是否可以“卸载"(“un-require")一个 Ruby 库? [英] Is it possible to 'unload' ('un-require') a Ruby library?
问题描述
我正在寻找加载一些库,让它们做一些工作,然后执行与 require
相反的操作,以避免以后出现兼容性错误.我不想转储到文件并重新启动 shell,因为创建的对象(例如 data
)可以由我的其他库很好地处理,只是没有早期的我正在寻求卸载的那些.
I'm looking to load a few libraries, have them do some work, and then do the opposite of require
to avoid compatibility errors later. I don't want to have to dump to a file and restart a shell, as the objects created (such as data
) could be processed well by my other libraries, just not in the presence of the early ones I'm seeking to unload.
有人有任何建议或知道这是否可能吗?2006 年的对话 除了看起来就像 Webrick 设法以某种方式做到这一点'.
Anyone got any suggestions or know if this is possible? A conversation from 2006 didn't come to much conclusion-wise other than that 'it looks like Webrick manages to do this somehow'.
有问题的库是 Google_drive 和 Nokogiri (电子表格处理库 Roo 依赖 Google_drive 进行在线电子表格读取/写入,如该链接所述).
The libraries in question are Google_drive and Nokogiri (the spreadsheet processing library Roo depends on Google_drive for online spreadsheet reading/writing, as described at that link).
推荐答案
就像@Alex 说的,你可以使用 Kernel#fork
创建一个新的 ruby 进程,您将在其中 require
库.新的分叉进程将有权访问父进程中加载的数据:
Like @Alex said, you could use the Kernel#fork
to create a new ruby process where you will require
your libraries. The new forked process will have access to data loaded in the parent process:
def talk(msg)
# this will allow us to see which process is
# talking
puts "#{Process.pid}: #{msg}"
end
# this data was loaded on the parent process
# and will be use in the child (and in the parent)
this_is_data = ["a", "b", "c"]
talk "I'm the father process, and I see #{this_is_data}"
# this will create a new ruby process
fork{
talk "I'm another process, and I also see #{this_is_data}"
talk "But when I change `this_is_data`, a new copy of it is created"
this_is_data << "d"
talk "My own #{this_is_data}"
}
# let's wait and give a chance to the child process
# finishes before the parent
sleep 3
talk "Now, in the father again, data is: #{this_is_data}"
这个执行的结果在你的机器上会有所不同,Process.id
会返回不同的值,但是会是这样的:
The result of this execution will vary in your machine, the Process.id
will return different values, but it will be like these:
23520: I'm the father process, and I see ["a", "b", "c"]
23551: I'm another process, and I also see ["a", "b", "c"]
23551: But when I change `this_is_data`, a new copy of it is created
23551: My own ["a", "b", "c", "d"]
23520: Now, in the father again, data is: ["a", "b", "c"]
这很好!fork
创建的每个进程都是一个操作系统.级别进程并在它自己的内存空间中运行.
And this is good! Each process created by fork
is an O.S. level process and run in it's own memory space.
你可以做的另一件事是管理加载文件创建的全局变量,用 load
替换 require
的使用.这种方法并不能解决已经指出的所有问题,但确实可以提供帮助.请参阅以下规格:
Another thing you can do to somehow manage the globals created by loading a file, is replace the use of require
by load
. This approach doesn't solve all the problems already pointed, but really can help. See the following specs:
require "minitest/autorun"
describe "Loading files inside a scope" do
def create_lib_file(version)
libfile = <<CODE
class MyLibrary#{version}
VERSION = "0.0.#{version}"
end
class String
def omg_danger!
end
end
puts "loaded #{MyLibrary#{version}::VERSION}"
CODE
File.write("my_library.rb", libfile)
end
after do
File.delete("my_library.rb") if File.exists?("my_library.rb")
end
describe "loading with require" do
it "sees the MyLibrary definition" do
create_lib_file("1")
require_relative "my_library.rb"
MyLibrary1::VERSION.must_be :==, "0.0.1"
"".respond_to?(:omg_danger!).must_be :==, true
end
end
describe "loading with #load " do
describe "without wrapping" do
it "sees the MyLibrary definition" do
create_lib_file("2")
load "my_library.rb"
MyLibrary2::VERSION.must_be :==, "0.0.2"
"".respond_to?(:omg_danger!).must_be :==, true
end
end
describe "using anonymous module wraping" do
it "doesn't sees MyLibrary definition" do
create_lib_file("3")
load "my_library.rb", true
->{ MyLibrary3 }.must_raise NameError
"".respond_to?(:omg_danger!).must_be :==, false
end
end
end
end
以及执行结果:
Run options: --seed 16453
# Running tests:
loaded 0.0.3
.loaded 0.0.2
.loaded 0.0.1
.
Finished tests in 0.004707s, 637.3486 tests/s, 1274.6973 assertions/s.
3 tests, 6 assertions, 0 failures, 0 errors, 0 skips
这篇关于是否可以“卸载"(“un-require")一个 Ruby 库?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!