Hầu hết thời gian, đá quý trong Ruby Just Work. Nhưng có một vấn đề lớn với phép thuật của Ruby:khi mọi thứ diễn ra không như ý muốn, thật khó để tìm ra lý do.
Bạn sẽ không thường xuyên gặp vấn đề với đá quý của mình. Nhưng khi bạn làm vậy, Google lại vô ích một cách đáng ngạc nhiên. Các thông báo lỗi là chung chung, vì vậy chúng có thể có một trong nhiều nguyên nhân khác nhau. Và nếu bạn không hiểu cách đá quý thực sự hoạt động với Ruby, bạn sẽ gặp khó khăn khi tự mình gỡ lỗi những vấn đề này.
Đá quý có thể dường như huyền diệu. Nhưng với một cuộc điều tra nhỏ, chúng khá dễ hiểu.
gem install
có chức năng gì làm gì?
Đá quý Ruby chỉ là một số mã được nén với một ít dữ liệu bổ sung. Bạn có thể thấy mã bên trong một viên ngọc bằng 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 nhất, thực hiện một cái gì đó giống như thế này. Nó lấy viên đá quý và đưa các tệp của nó vào một thư mục đặc biệt trên hệ thống của bạn. Bạn có thể thấy nơi gem install
sẽ cài đặt đá quý của bạn nếu bạn chạy gem environment
(tìm INSTALLATION DIRECTORY:
dòng):
~ 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
Tất cả mã gem đã cài đặt của bạn sẽ ở đó, dưới gems
thư mục.
Các đường dẫn này khác nhau giữa các hệ thống và chúng cũng phụ thuộc vào cách bạn cài đặt Ruby (rvm khác với Homebrew, khác với rbenv, v.v.). Vì vậy, gem environment
sẽ hữu ích khi bạn muốn biết mã của những viên ngọc quý của mình ở đâu.
Yêu cầu mã đá quý như thế nào?
Để giúp bạn sử dụng mã bên trong các viên ngọc của mình, RubyGems sẽ ghi đè require
của Ruby phương pháp. (Nó thực hiện điều này trong core_ext / kernel_require.rb). Nhận xét khá rõ ràng:
##
# 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).
#
Ví dụ:giả sử bạn muốn tải active_support
. RubyGems sẽ cố gắng yêu cầu nó bằng cách sử dụng require
của Ruby phương pháp. Điều đó gây ra cho bạn lỗi này:
LoadError: cannot load such file -- active_support
from (irb):17:in `require'
from (irb):17
from /usr/local/bin/irb:11:in `<main>'
RubyGems xem xét thông báo lỗi đó và thấy rằng nó cần tìm active_support.rb
bên trong của một viên đá quý, thay vào đó. Để làm điều đó, nó sẽ quét qua siêu dữ liệu của các viên đá quý, tìm kiếm viên đá quý có chứa active_support.rb
:
irb(main):001:0> spec = Gem::Specification.find_by_path('active_support')
=> #<Gem::Specification:0x3fe366874324 activesupport-4.2.0.beta1>
Sau đó, nó kích hoạt gem, thêm mã bên trong gem vào đường dẫn tải của Ruby (các thư mục bạn có thể require
tệp từ):
irb(main):002:0> $LOAD_PATH
=> ["/usr/local/Cellar/ruby/2.1.2/lib/ruby/site_ruby/2.1.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/site_ruby/2.1.0/x86_64-darwin14.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/site_ruby", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/vendor_ruby/2.1.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin14.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/vendor_ruby", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/2.1.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/2.1.0/x86_64-darwin14.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", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/site_ruby/2.1.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/site_ruby/2.1.0/x86_64-darwin14.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/site_ruby", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/vendor_ruby/2.1.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin14.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/vendor_ruby", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/2.1.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/2.1.0/x86_64-darwin14.0"]
Bây giờ active_support
đang ở trên đường dẫn tải, bạn có thể require
các tệp trong gem giống như bất kỳ đoạn mã Ruby nào khác. Bạn thậm chí có thể sử dụng phiên bản gốc của require
, cái đã bị RubyGems ghi đè:
irb(main):005:0> gem_original_require 'active_support'
=> true
Tuyệt vời!
Một chút kiến thức sẽ giúp bạn đi một chặng đường dài
RubyGems có vẻ phức tạp. Nhưng ở cấp độ cơ bản nhất, nó chỉ quản lý đường dẫn tải của Ruby cho bạn. Điều đó không có nghĩa là tất cả đều dễ dàng. Tôi không trình bày cách RubyGems quản lý xung đột phiên bản giữa các viên ngọc, mã nhị phân viên đá quý (như rails
và rake
), Phần mở rộng C và nhiều thứ khác.
Nhưng biết RubyGems ngay cả ở cấp độ bề mặt này sẽ giúp ích rất nhiều. Với một chút mã đọc và chơi trong irb
, bạn sẽ có thể đi sâu vào nguồn đá quý của mình. Bạn có thể hiểu nơi sống của đá quý, vì vậy bạn có thể đảm bảo rằng RubyGems biết về chúng. Và khi bạn biết cách nạp đá quý, bạn có thể tìm hiểu một số vấn đề tải có vẻ điên rồ.
Nếu bạn muốn tìm hiểu thêm về cách Rails và Bundler xử lý gem, hãy xem bài viết này:Rails xử lý gem như thế nào ?.