详解Gemfile

定义

Gemfile - 一个为了Ruby程序描述gem依赖的文件格式

概要

Gemfile里面描述了需要运行相关Ruby代码的gem依赖,一般是将此文件放到根目录。 例如Rails程序,是放在Rakefile的同一个目录下面。

语法

Gemfile相当于Ruby代码,并且有一些用于gem依赖的方法。

全局的Sources

一般写在Gemfile的头部,指定Gem的源地址,例如:

1
2
3
4
source "https://rubygems.org"

### 中国的用户可以使用这个地址
source('http://ruby.taobao.org')

一般情况下,不太建议指定多个source。如果一个gem在多个source里存在,bundler会打印一些警告出来。 如果单个gem使用不一样的source,建议使用:source选项或者source block(后面会详细介绍)。

认证

有些gem的source需要用户密码才能使用,可以通过使用bundle config命令或者直接写在source的地址里面 2种方式。

1
bundle config https://gems.example.com/ user:password

直接写在source的地址里面

1
source "https://user:password@gems.example.com"

如果2种方式都设定了的话,下面一种方式的优先级高于bundle config。

Ruby

如果你的应用需要指定一个特定的Ruby版本或者engine。

VERSION(必须指定)

你的应用需要的Ruby版本。如果你的应用使用了另外一个engine如JRuby或者Rubinius,得需要和这个版本保持兼容。

1
ruby "1.9.3"
ENGINE (:engine)

应用可以指定的Ruby Engine(如JRuby或者Rubinius)。如果engine指定了的话,对应的enine版本同样也必须指定。

ENGINE VERSION (:engine_version)

Ruby Engine的版本。这个必须与engine成对出现。

1
ruby "1.8.7", :engine => "jruby", :engine_version => "1.6.7"
PATCHLEVEL (:patchlevel)

指定Ruby对应版本的patchlevel。

1
ruby "2.0.0", :patchlevel => "247"

GEMS (#gem)

指定gem的方法,有下面的参数。

NAME (必须指定)

gem的名字

1
gem "nokogiri"
VERSION

gem的版本

1
2
gem "nokogiri", ">= 1.4.2"
gem "RedCloth", ">= 4.1.0", "< 4.2.0"

指定版本有好几种方式:

  • 固定版本
1
gem "nokogiri", "1.4.2"
  • 大于等于某个版本
1
gem "nokogiri", ">= 1.4.2"
  • 在指定版本范围内
1
gem "RedCloth", ">= 4.1.0", "< 4.2.0"
  • 约等于某个版本
1
gem "nokogiri", "~>1.4.2"

~>这个的版本有特别的意思:~> 2.0.3表示版本在>= 2.0.3< 2.1之间。 ~> 2.1表示版本在>= 2.1< 3.0之间。 ~> 2.2.beta会匹配这个版本2.2.beta.12

REQUIRE AS (:require)

用来指定require指定文件或者指定为false使应用不会自动require。

1
2
3
gem "redis", :require => ["redis/connection/hiredis", "redis"]
gem "webmock", :require => false
gem "debugger", :require => true
  • true 指应用自动require该gem。在使用该gem的地方无需自己手动require了。
  • false 应用不会自动require该gem。在使用该gem的地方需自己手动require。
  • 单个文件名或文件数组。一般gem的主文件名和gem名不一致的时候,需要在这里指定成文件名。

所以下面3个的requires其实是一样的。

1
2
3
gem "nokogiri"
gem "nokogiri", :require => "nokogiri"
gem "nokogiri", :require => true
GROUPS (:group or :groups)

每个gem可以指定在任何的一个或者多个group里面。如果gem没有指定group的话,默认是在default group里。

1
2
gem "rspec", :group => :test
gem "wirble", :groups => [:development, :test]

bundler有2个主要的方法Bundler.setup和Bundler.require可以访问group。

1
2
3
4
5
6
7
8
9
10
11
12
# setup adds gems to Ruby's load path
Bundler.setup                    # defaults to all groups
require "bundler/setup"          # same as Bundler.setup
Bundler.setup(:default)          # only set up the _default_ group
Bundler.setup(:test)             # only set up the _test_ group (but `not` _default_)
Bundler.setup(:default, :test)   # set up the _default_ and _test_ groups, but no others

# require requires all of the gems in the specified groups
Bundler.require                  # defaults to just the _default_ group
Bundler.require(:default)        # identical
Bundler.require(:default, :test) # requires the _default_ and _test_ groups
Bundler.require(:test)           # requires just the _test_ group

bundle install可以指定--without的参数来忽略某些group的gem的安装。

1
2
bundle install --without test
bundle install --without development test

如果你运行完bundle install --without test以后,bundle会记住你最后一次忽略test group的配置。 下次你如果直接运行bundle install,默认就会带--without test配置来安装gem。

并且如果调用bundler.setup没有传入参数,将会加载所有除了设定的--withoutgroup的gem。

另外运行bundle install将会下载所有的gem及其依赖的gem并且建立一个gem列表,这就意味着你不能在不同的group 加载不同版本的相同gem。

PLATFORMS (:platforms)

指定某个gem只能运行的平台。

有很多的Gemfile平台如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ruby        C Ruby (MRI) or Rubinius, but NOT Windows
ruby_18     ruby AND version 1.8
ruby_19     ruby AND version 1.9
ruby_20     ruby AND version 2.0
ruby_21     ruby AND version 2.1
ruby_22     ruby AND version 2.2
mri         Same as ruby, but not Rubinius
mri_18      mri AND version 1.8
mri_19      mri AND version 1.9
mri_20      mri AND version 2.0
mri_21      mri AND version 2.1
mri_22      mri AND version 2.2
rbx         Same as ruby, but only Rubinius (not MRI)
jruby       JRuby
mswin       Windows
mingw       Windows 32 bit 'mingw32' platform (aka RubyInstaller)
mingw_18    mingw AND version 1.8
mingw_19    mingw AND version 1.9
mingw_20    mingw AND version 2.0
mingw_21    mingw AND version 2.1
mingw_22    mingw AND version 2.2
x64_mingw   Windows 64 bit 'mingw32' platform (aka RubyInstaller x64)
x64_mingw_20  x64_mingw AND version 2.0
x64_mingw_21  x64_mingw AND version 2.1
x64_mingw_22  x64_mingw AND version 2.2

和group差不多,你可以指定一个或多个。

1
2
3
gem "weakling",   :platforms => :jruby
gem "ruby-debug", :platforms => :mri_18
gem "nokogiri",   :platforms => [:mri_18, :jruby]
SOURCE (:source)

如果某个gem需要单独从另外的source去下载,可以通过指定这个参数实现。

1
gem "some_internal_gem", :source => "https://gems.example.com"

如果找不到,将会去global source那里去找。

GIT (:git)

你可以指定一个gem是从指定的git repo那里下载。这个repo可以是公开的 (http://github.com/rails/rails.git)也可以是私有(git@github.com:rails/rails.git) 的,如果是私有必须保证你的ssh配置有权限clone该repo。

1
gem "rails", :git => "git://github.com/rails/rails.git"

这个repo必须至少有一个文件在项目的根目录下,后缀名是.gemspec,这个文件里面包含的是 各个gem指定的信息。

如果这个repo没有.gemspec文件,bundler将会试着新建一个空的文件。

如果repo里面有.gemspec文件,那必须保证该文件里面的版本和gem指定的版本要一致。 不一致的话,bundle会有警告。

1
2
3
gem "rails", "2.3.8", :git => "git://github.com/rails/rails.git"
# bundle install will fail, because the .gemspec in the rails
# repository's master branch specifies version 3.0.0

如果.gemspec文件没有的话,gem的版本必须指定,bundle将会根据这个版本新建.gemspec文件。

git这个参数还有额外的参数:

  • branch, tag, 和 ref。 你只能指定其中一个参数。默认使用的是:branch => "master"
  • submodules。 如果指定:submodules => true的话,bundle会默认扩展这个repo里面的submodule。
GITHUB (:github)

如果git repo是github的公开项目的话你只需指定用户名项目名即可。如果项目名和用户名一样,那只需指定其中一个即可。

1
2
gem "rails", :github => "rails/rails"
gem "rails", :github => "rails"

和下面这个是一样的。

1
gem "rails", :git => "git://github.com/rails/rails.git"

也是可以指定分支的:

1
gem "rails", :github => "rails/rails", :branch => "branch_name"
PATH (:path)

你可以指定某个目录下的gem,基本是和git参数一样,也是需要项目里有.gemspec文件。 但需要注意的是与git不一样的是:bundle不会编译path方式指定的gem里面的c扩展。

1
gem "rails", :path => "vendor/rails"
SOURCE, GIT, PATH, GROUP 和 PLATFORMS 的block

就是把source,git,path,group和platform可以通过block分组设置了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
source "https://gems.example.com" do
  gem "some_internal_gem"
  gem "another_internal_gem"
end

git "git://github.com/rails/rails.git" do
  gem "activesupport"
  gem "actionpack"
end

platforms :ruby do
  gem "ruby-debug"
  gem "sqlite3"
end

group :development do
  gem "wirble"
  gem "faker"
end

需要的注意的是git,设置了branch等参数的话,里面所有的gem都是会继承的。

GEMSPEC (#gemspec)

用来指定查找gem里面的gemspec文件。 gemspec有:path, :name和:development_group参数,这些参数用来查找gemspec文件的。

SOURCE 优先级

bundle使用如下的source优先级:

  1. gem本身自己定义的:source, :path, 或者 :git参数
  2. 对于依赖的一些gem, :source, :path, 或者 :git里面对应的版本优先级高于rubygems.org
  3. 对于多个全局SOURCE的情况,将会是从最后加入的一个source开始搜索优先级最高。

评论