是否有可能“卸载”('不要求')Ruby库? [英] Is it possible to 'unload' ('un-require') a Ruby library?
问题描述
我正在加载一些库,让他们做一些工作,然后做相反的 require
以避免以后出现兼容性错误。我不想转储到一个文件并重新启动一个shell,因为创建的对象(例如 data
)可以被其他库处理得很好,只是不会在那些我正在寻求卸载的早期产品中。
任何人有任何建议或知道这是否可能? 2006年的一次谈话并没有得出太多的结论,除了它看起来像Webrick设法做到这一点'。
有问题的库是 Google_drive和Nokogiri (电子表格处理库Roo依靠Google_drive进行在线电子表格读取/写入,如链接所述)。
像@Alex说的,你可以使用
内核#fork
创建一个新的ruby进程,您将在需要
你的库。新分叉的进程将有权访问父进程中加载的数据: def talk(msg)
#this将允许我们看到哪个进程是
#讲话
puts#{Process.pid}:#{msg}
end
#此数据已加载在父进程中
#将在子进程中使用(在父进程中)
this_is_data = [a,b,c]
讲话我是父进程,我看到#{this_is_data}
#这将创建一个新的ruby进程
fork {
talk我是另一个进程,我也看到#{this_is_data}
talk但是当我改变`this_is_data`时,它的一个新副本被创建
this_is_data<< d
talkMy own#{this_is_data}
}
#让我们等待并给出一个机会给子进程
#在父进程之前完成
sleep 3
talk现在,再次在父亲身边,数据是:#{this_is_data}
这个执行的结果在您的机器中会有所不同, Process.id
将返回不同的值,但它将如下所示:
23520:我是父亲程序,我看到[a,b,c]
23551:我是另一个进程,我也看到[a,b,c]
23551:但是当我更改`this_is_data`时,它的新副本被创建
23551:我自己的[a,b,c,d]
23520:现在,再次在父亲身上,数据是:[a,b,c ]
这很好!由 fork
创建的每个进程都是一个O.S.并且运行在它自己的内存空间中。
另一件你可以通过加载文件来管理全局变量的方法是替换使用通过
。这种方法不能解决已经指出的所有问题,但真的可以提供帮助。请参阅以下规范: load
来请求
requireminitest / autorun
describe在范围内加载文件do
def create_lib_file(版本)
libfile =<< CODE $ b $ class MyLibrary#{版本}
VERSION =0.0。#{version}
end
class String
def omg_danger!
end
end
putsloaded \#{MyLibrary#{version} :: VERSION}
CODE
文件。 write(my_library.rb,libfile)
结束
做完
之后File.delete(my_library.rb)if File.exists?(my_library.rb )
end
描述使用require进行加载do
it看到MyLibrary定义do
create_lib_file(1)
require_relativemy_library .rb
MyLibrary1 :: VERSION.must_be:==,0.0.1
.respond_to?(:omg_danger!)。must_be:==,true
end
结束
描述使用#load装入do
描述不包装do
它看到MyLibrary定义do
create_lib_file(2 )
加载my_library.rb
MyLibrary2 :: VERSION.must_be:==,0.0.2
.respond_to?(:omg_danger!)。must_be:==, true
end
end
描述使用匿名模块包装do
它看不到MyLibrary定义do
create_lib_file(3)
loadmy_library.rb,true
- > {MyLibrary3} .must_raise NameError
.respond_to?(:omg_danger!)。must_be:==,false
end
end
end
end
执行结果:
运行选项: - 种子16453
#运行测试:
加载0.0.3
。加载0.0.2
。加载0.0.1
。
0.004707s的完成测试,637.3486个测试/ s,1274.6973个断言/ s。
3个测试,6个断言,0个失败,0个错误,0个跳过
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.
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'.
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).
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}"
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"]
And this is good! Each process created by fork
is an O.S. level process and run in it's own memory space.
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 don't solves 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
And the result of execution:
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
这篇关于是否有可能“卸载”('不要求')Ruby库?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!