是否可以“卸载"(“un-require")一个 Ruby 库? [英] Is it possible to 'unload' ('un-require') a Ruby library?

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

问题描述

我正在寻找加载一些库,让它们做一些工作,然后执行与 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屋!

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