Gemfile的作用无非就是告诉bundler你的项目具体都需要哪些gem,这些gem都需要哪些版本,以及从哪获取这些gem。其实你的问题应该就是跟第三点有关,总的来说,gem的来源可以有四种:
这个是最直接的,通过这种方式指定的gem,bundler会从文件开头的 source
中去查找这个gem:
source 'https://rubygems.org'
gem 'rails' # this gem will be installed from https://rubygems.org
通过在 gem
方法(Gemfile实际上就是一个ruby的代码文件)中指定 git
参数,可以使bundler从指定的远程代码库上拉取代码,比如:
# nokogiri will be installed from git://github.com/tenderlove/nokogiri.git
gem 'nokogiri', :git => 'git://github.com/tenderlove/nokogiri.git'
上面第2种方法只是针对所有合法的git代码库(不仅仅是github,也可以是你自己的一个git服务器上一个代码库)而言,而如果你所需要的库来自于github,则可以通过更方便的 github
参数实现目标:
gem 'nokogiri', :github => 'tenderlove/nokogiri'
可以看到,只要指定了 author/repo_name
的形式,bundler就能自动从github上获取你所需要的gem了。
注意: 第2跟第3种方式还都可以通过 branch
参数指定你所需要的代码分支,比如:
gem 'refinerycms', github: 'refinery/refinerycms', branch: 'master'
假如你有一个已经放在项目目录中(其实可以是任何地方)的gem,则可以通过 path
参数指定所需的gem在文件系统中的位置,比如:
gem "rails", :path => "vendor/rails"
bundler将会根据path指定的路径去查找并且安装gem。
最后顺便说下我的一点体会,一般像这种gem来自于项目目录下的情况,大多是因为项目中用到了一些提供扩展机制的框架,比如 Spree以及 Refinery,这两者生成的扩展或者子Engine都是以gem的形式放在vendor或者lib目录下,然后从Gemfile里边进行指定,比如我的一个项目中的一个实例:
gem 'refinerycms-factories', :path => 'vendor/extensions'
refinerycms-factories是我用Refinery的generator生成的一个子engine,默认放在 verdor/extensions
目录下。
另一种可能比较常见的情况就是你用到了某个可能不再维护的gem,由于对源代码的改动较大,所以你干脆把这个gem的源代码下载到本地项目目录下,然后直接进行修改,最后通过 path
去安装。
关于Gemfiile的更多资料,请自行猛戳:
Bundler homepage
Gemfile manual page