Gem如何工作

一般我们在使用Gem的过程中不会遇到什么问题,但如果一旦遇到问题解决问题起来可能会比较麻烦。 如果我们知道Gem怎么工作的话,将会帮助我们解决使用Gem中遇到的问题。

gem install 做了什么

gem就是压缩的代码包。你可以通过gem unpack命令看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ gem unpack resque_unit
Fetching: resque_unit-0.4.8.gem (100%)
Unpacked gem: '/Users/grant/projects/grant/resque_unit-0.4.8'
$ cd resque_unit-0.4.8
$ find .
.
./lib
./lib/resque_unit
./lib/resque_unit/assertions.rb
./lib/resque_unit/errors.rb
./lib/resque_unit/helpers.rb
./lib/resque_unit/plugin.rb
./lib/resque_unit/resque.rb
./lib/resque_unit/scheduler.rb
./lib/resque_unit/scheduler_assertions.rb
./lib/resque_unit.rb
./lib/resque_unit_scheduler.rb
./README.md
./test
./test/resque_test.rb
./test/resque_unit_scheduler_test.rb
./test/resque_unit_test.rb
./test/sample_jobs.rb
./test/test_helper.rb

gem install其实就是做类似这样的事情,取下gem压缩包文件,解压到某个特定目录。 这个特定目录位置可以通过gem environment命令查看INSTALLATION DIRECTORY

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
RubyGems Environment:
- RUBYGEMS VERSION: 2.0.14
- RUBY VERSION: 2.0.0 (2014-11-13 patchlevel 598) [x86_64-darwin14.0.0]
- INSTALLATION DIRECTORY: /Users/grant/.rbenv/versions/2.0.0-p598/lib/ruby/gems/2.0.0
- RUBY EXECUTABLE: /Users/grant/.rbenv/versions/2.0.0-p598/bin/ruby
- EXECUTABLE DIRECTORY: /Users/grant/.rbenv/versions/2.0.0-p598/bin
- RUBYGEMS PLATFORMS:
- ruby
- x86_64-darwin-14
- GEM PATHS:
- /Users/grant/.rbenv/versions/2.0.0-p598/lib/ruby/gems/2.0.0
- /Users/grant/.gem/ruby/2.0.0
- GEM CONFIGURATION:
- :update_sources => true
- :verbose => true
- :backtrace => false
- :bulk_threshold => 1000
- "gem" => "--no-ri --no-rdoc"
- REMOTE SOURCES:
- https://rubygems.org/

gem就在INSTALLATION DIRECTORY的gems目录下面:

1
2
3
$ cd /Users/grant/.rbenv/versions/2.0.0-p598/lib/ruby/gems/2.0.0
$ ls
bin       build_info  bundler     cache       doc     gems        specifications

这个path在不同环境下面的路径是不一样的。所以gem environment将会非常方便让你 知道gem的代码在哪里。

gem 代码怎么require的呢?

rubygems覆盖了ruby的require方法来实现加载gem的功能。看下面的注释就知道他怎么工作了。

1
2
3
4
5
6
7
8
9
10
11
12
core_ext/kernel_require.rb
##
# When RubyGems is required, Kernel#require is replaced with our own which
# is capable of loading gems on demand.
#
# When you call <tt>require 'x'</tt>, this is what happens:
# * If the file can be loaded from the existing Ruby loadpath, it
#   is.
# * Otherwise, installed gems are searched for a file that matches.
#   If it's found in gem 'y', that gem is activated (added to the
#   loadpath).
#

如果你想加载active_support,RubyGems首先使用Ruby的require方法从loadpath里去找, 这个将会出现一个错误。

1
2
3
4
LoadError: cannot load such file -- active_support
from (irb):17:in `require'
from (irb):17
from /usr/local/bin/irb:11:in `<main>'

通过require找不到的话,rubygems会从Gems文件里面找active_support.rb

1
2
irb(main):001:0> spec = Gem::Specification.find_by_path('active_support')
=> #<Gem::Specification:0x3fe52159e714 activesupport-4.1.8>

如果找到的话,将会激活这个gem,然后把这个gem加到load path里面去。

1
2
3
4
5
6
irb(main):004:0*  $LOAD_PATH
=> ["/Users/grant/.rbenv/plugins/rbenv-gem-rehash", "/Users/grant/.rbenv/rbenv.d/exec/gem-rehash", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/site_ruby/2.0.0", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/site_ruby/2.0.0/x86_64-darwin14.0.0", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/site_ruby", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/vendor_ruby/2.0.0", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/vendor_ruby/2.0.0/x86_64-darwin14.0.0", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/vendor_ruby", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/2.0.0", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/2.0.0/x86_64-darwin14.0.0"]
irb(main):005:0> spec.activate
=> true
irb(main):006:0>  $LOAD_PATH
=> ["/Users/grant/.rbenv/plugins/rbenv-gem-rehash", "/Users/grant/.rbenv/rbenv.d/exec/gem-rehash", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/gems/2.0.0/gems/i18n-0.6.11/lib", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/gems/2.0.0/gems/thread_safe-0.3.4/lib", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/gems/2.0.0/gems/activesupport-4.1.8/lib", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/site_ruby/2.0.0", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/site_ruby/2.0.0/x86_64-darwin14.0.0", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/site_ruby", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/vendor_ruby/2.0.0", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/vendor_ruby/2.0.0/x86_64-darwin14.0.0", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/vendor_ruby", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/2.0.0", "/Users/grant/.rbenv/versions/2.0.0-p481/lib/ruby/2.0.0/x86_64-darwin14.0.0"]

这时候active_support就在加载路径里面,你可以在任何地方使用它了。

总结

通过上面基本知道rubygems是怎么工作的,这样遇到相关的问题的时候,你可以根据上面的一些信息挖掘出更深层次的原因。

评论