是否有可能“卸载”('不要求')Ruby库? [英] Is it possible to 'unload' ('un-require') a Ruby library?

查看:119
本文介绍了是否有可能“卸载”('不要求')Ruby库?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在加载一些库,让他们做一些工作,然后做相反的 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆