Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Hiểu Ruby Gems: Cách hoạt động và troubleshooting

Phần lớn thời gian, gem Ruby Just Works. Nhưng vấn đề lớn với Ruby magic: khi sai, khó tìm nguyên nhân.

Bạn không thường gặp vấn đề gem. Nhưng khi gặp, Google ít giúp. Error message generic, nhiều nguyên nhân. Và nếu không hiểu gem thực sự làm việc với Ruby như thế nào, bạn sẽ khổ debug tự lực.

Gem có vẻ ma thuật. Nhưng với chút điều tra, dễ hiểu.

gem install làm gì?

Ruby gem chỉ là code zip kèm data nhỏ. Xem code trong gem với gem unpack:

~/Source/playground jweiss$ gem unpack resque_unit
Fetching: resque_unit-0.4.8.gem (100%)
Unpacked gem: '/Users/jweiss/Source/playground/resque_unit-0.4.8'
~/Source/playground jweiss$ cd resque_unit-0.4.8
~/Source/playground/resque_unit-0.4.8 jweiss$ 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
~/Source/playground/resque_unit-0.4.8 jweiss$

gem install, dạng đơn giản, làm tương tự như này. Lấy gem, đặt file vào thư mục đặc biệt trên hệ thống. Xem gem install cài đâu bằng gem environment (tìm dòng INSTALLATION DIRECTORY:):

~ jweiss$ gem environment
RubyGems Environment:
- RUBYGEMS VERSION: 2.2.2
- RUBY VERSION: 2.1.2 (2014-05-08 patchlevel 95) [x86_64-darwin14.0]
- INSTALLATION DIRECTORY: /usr/local/Cellar/ruby/2.1.2/lib/ruby/gems/2.1.0
...
~ jweiss$ ls /usr/local/Cellar/ruby/2.1.2/lib/ruby/gems/2.1.0
bin bundler doc gems build_info cache extensions specifications

Code gem cài sẽ ở đó, dưới thư mục gems.

Path này khác nhau hệ thống, và phụ thuộc cách cài Ruby (rvm khác Homebrew, khác rbenv...). Vậy gem environment hữu ích khi muốn biết code gem ở đâu.

Code gem được require như thế nào?

Để giúp dùng code trong gem, RubyGems override method require của Ruby. (Làm ở core_ext/kernel_require.rb). Comment rõ ràng:

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 require 'x', 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).
#

Ví dụ, muốn load active_support. RubyGems thử require bằng require Ruby. Ra lỗi:

LoadError: cannot load such file -- active_support
from (irb):17:in `require'
from (irb):17
from /usr/local/bin/irb:11:in `
'

RubyGems xem error, thấy cần tìm active_support.rb trong gem. Quét metadata gem, tìm gem chứa active_support.rb:

irb(main):001:0> spec = Gem::Specification.find_by_path('active_support')
=> #

Rồi activate gem, thêm code gem vào Ruby load path (thư mục bạn có thể require file):

irb(main):002:0> $LOAD_PATH
=> ["/usr/local/Cellar/ruby/2.1.2/lib/ruby/site_ruby/2.1.0", ...]
irb(main):003:0> spec.activate
=> true
irb(main):004:0> $LOAD_PATH
=> ["/usr/local/Cellar/ruby/2.1.2/lib/ruby/gems/2.1.0/gems/i18n-0.7.0.beta1/lib",
    "/usr/local/Cellar/ruby/2.1.2/lib/ruby/gems/2.1.0/gems/thread_safe-0.3.4/lib",
    "/usr/local/Cellar/ruby/2.1.2/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0.beta1/lib", ...]

Bây giờ active_support trên load path, bạn require file gem như code Ruby thường. Thậm chí dùng require gốc, bị RubyGems override:

irb(main):005:0> gem_original_require 'active_support'
=> true

Cool!

Chút kiến thức đi xa

RubyGems có vẻ phức tạp. Nhưng cấp cơ bản, nó chỉ quản lý Ruby load path cho bạn. Không nói là tất cả dễ. Tôi không cover cách RubyGems xử lý conflict version giữa gem, gem binary (như rails, rake), C extension, và nhiều thứ khác.

Nhưng biết RubyGems cấp bề mặt cũng giúp nhiều. Với chút đọc code và chơi irb, bạn mò source gem. Hiểu gem ở đâu, đảm bảo RubyGems biết. Biết gem load như nào, debug được loading problem kỳ quặc.

Muốn học thêm Rails và Bundler xử lý gem như nào, đọc bài: How does Rails handle gems?.