rails如何从gem中隐式导入函数?

时间:2012-08-01 15:52:30

标签: ruby-on-rails ruby

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

所以 -

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

3 个答案:

答案 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