9

我是 ruby​​ 和 rails 的新手。我看到我包含的任何 gem,我可以直接在我的代码中使用它的功能。我没有看到代码的任何导入,也没有看到函数的任何名称空间。如果宝石包含具有相同名称的函数,这不是冲突的秘诀吗?

所以 -

ruby/rails 如何导入函数,如何将函数映射到 gem ?当 2 个 gem 包含相同的功能时会导致冲突吗?如果我想显式使用 ruby​​ 库,我将如何导入它的代码?红宝石中有命名空间吗?

4

3 回答 3

11

红宝石

ruby 将一个文件中声明的函数导入另一个文件的方式是通过require函数。load完成类似的事情,但出于一般目的,require通常是您想要的(有关更多详细信息,请参阅http://ionrails.com/2009/09/19/ruby_require-vs-load-vs-include-vs-extend/

hello_lib.rb

def say_hello
  puts "hello"
end

# that's right, you can execute code when a library is required,
# so the sky's the limit of what you can do
puts "Hey, I've been required!"

hello_caller.rb

# load the code from `hello_lib.rb` in the same directory
require './hello_lib.rb'

子目录/hello_other_caller.rb

# for illustrative purposes, adding the parent directory to the load path
# so that ruby will look there for files I want to require
$: << '..'
require 'hello_lib.rb'
say_hello    

宝石

Gems 可以被认为是一个 ruby​​ 代码包或一个库。有几种加载 gem 的方法,但最常见的是通过require假设您已安装progressbargem 以在终端中显示简单的进度条 ( gem install progressbar)

进度条测试.rb

require 'rubygems'
require 'progressbar'

# this also works
# gem 'progressbar', '~> 0.9.2'

pbar = ProgressBar.new("test", 100)
100.times do
  sleep 0.1
  pbar.inc
end
pbar.finish

这样做的原因是,当我们需要时rubygems,它会将进度条 gem 添加到 ruby​​ 查找所需文件的路径中。

导轨

Rails 只是一组 gem,其中一些提供可执行脚本。在以前的版本中,您必须指定要加载的 gem,就像我们上面所做的那样。但是现在,有了bundler,我们可以在一个中指定所有的 gem Gemfile,以及版本控制和源信息。然后,Bundler 将计算出 gem 之间的依赖关系,并将项目的特定版本控制在Gemfile.lock. 由于bundler它本身就是一个 gem,你会经常看到这样的代码:

配置/应用程序.rb

require 'bundler'
Bundler.require(:default, Rails.env)

这段代码告诉 Bundler 加载我们在 gemfile 中简单列出的所有依赖项,以及我们在与当前 rails env 对应的组中列出的那些依赖项(例如:development)。

命名空间

是的,您可以通过几种方式遇到问题。两个宝石可以具有相同的名称,尽管在这种情况下它们不能被推送到 ruby​​gems,你会很快发现。一个更微妙的命名空间问题是,如果两个文件执行以下操作:

你好1.rb

def hello
  puts "Hi"
end

你好2.rb

def hello
  puts "Hello, there!"
end

你好3.rb

require './hello1'
require './hello2'
hello

在这里,我们看到当我们在全局命名空间中发生命名空间冲突时会发生什么。如果两个库在同一个类名中定义了同一个方法,就会发生类似的事情(这种猴子补丁虽然不鼓励,但仍然会发生!)。在实践中,您不会遇到太多这种情况,尤其是在使用模块命名空间代码方面使用良好的纪律时,例如我正在编写 gem hello

module Hello
  # not such a good name, but won't conflict with ::Object
  class Object
    def to_s
      puts 'this is a bad idea'
    end
  end
end
于 2012-08-01T16:25:45.350 回答
0

Gems 是名称空间的,因此您可以通过以下方式显式调用方法

ModuleName::Class

如果你没有显式调用一个包含的类,ruby 将遍历它的所有类,直到找到你调用的类,如果没有,那么它会抛出一个 NoMethod 错误。

要让 Ruby 看到该库,您需要它:

require 'some_library'

要将库包含在类中,您:

class SomeClass
 include SomeLibrary
 ...
于 2012-08-01T16:04:27.947 回答
0

如果您查看config/application.rb,您会看到它是如何做到的:

Bundler.require(*Rails.groups)

而已!Bundler 会自动处理所有需要的 gem,因此您不必在使用的每个文件中都处理。有关更多详细信息,请参阅文档

于 2019-10-17T01:25:11.833 回答