我是ruby和rails的新手。我看到我包含的任何宝石,我都可以直接在我的代码中使用它的功能。我没有看到代码的任何导入,也没有看到函数的任何名称空间。如果宝石包含具有相同名称的函数,那么这个冲突的配方是不是?
所以 -
ruby / rails如何导入函数,如何将函数映射到gem? 当2颗宝石包含相同的功能时,它会导致冲突吗? 如果我想显式使用ruby库,我将如何导入其代码? 红宝石中有命名空间吗?
答案 0 :(得分:8)
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
说你已经安装了progressbar
gem用于在终端中显示简单的进度条(gem install progressbar
)
<强> progressbar_test.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
时,它会将进度条宝石添加到ruby查找所需文件的路径中。
Rails只是一组宝石,其中一些提供了可执行的脚本。在以前的版本中,您必须指定要加载的gem,这与我们上面的方式非常相似。但现在,使用bundler
,我们可以在一个Gemfile
中指定所有宝石,以及版本控制和源信息。 Bundler然后将计算出宝石之间的依赖关系,并为Gemfile.lock
中的项目保留我们的特定版本。由于bundler
本身就是一个宝石,你经常会看到这样的代码:
<强>配置/ application.rb中强>
require 'bundler'
Bundler.require(:default, Rails.env)
此代码告诉Bundler加载我们在gemfile中平面列出的所有依赖项,以及我们在当前rails env对应的组中列出的依赖项(例如:development)。
是的,您可以通过几种方式遇到问题。两个宝石可以具有相同的名称,虽然在这种情况下它们不能被推送到rubygems,你会很快发现它。一个更微妙的命名空间问题是两个文件是这样的:
<强> hello1.rb 强>
def hello
puts "Hi"
end
<强> hello2.rb 强>
def hello
puts "Hello, there!"
end
<强> hello3.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
答案 1 :(得分:0)
Gems是名称间隔的,因此您可以通过
显式调用方法ModuleName::Class
如果你没有显式调用一个包含的类,ruby将遍历它的所有类,直到它找到你调用的那个类,如果没有,那么它将抛出NoMethod错误。
要让Ruby看到该库,您需要它:
require 'some_library'
要在类中包含库,您:
class SomeClass
include SomeLibrary
...
答案 2 :(得分:0)
如果您查看config/application.rb
,将会看到它的工作方式:
Bundler.require(*Rails.groups)
就是这样! Bundler会自动处理所有宝石,因此您不必在使用的每个文件中都放置文件。有关更多详细信息,请参见the docs。