रूबी में निर्भरता प्रबंधन में आमतौर पर रूबी और मणि संस्करणों को निर्दिष्ट करना शामिल होता है जिस पर हमारी परियोजना निर्भर करती है। रूबी के साथ काम करने के मेरे अनुभव में, डिबगिंग निर्भरता मेरी सबसे बड़ी चुनौतियों में से एक रही है। असफलताएं आम नहीं हैं क्योंकि कई चीजें "बस काम करती हैं"; हालांकि, जब चीजें गलत हो जाती हैं, तो आमतौर पर उन्हें डीबग करना और ठीक करना अनावश्यक रूप से कठिन होता है। इस लेख में, मैं रूबी में निर्भरता प्रबंधन में शामिल टुकड़ों को रखूंगा। यह इन अजीब मुद्दों को होने पर डीबग करने में सहायता करेगा।
रूबी कोड लोड हो रहा है
डिफ़ॉल्ट रूप से, रूबी भाषा कहीं और परिभाषित कोड लोड करने के लिए दो प्रमुख तरीके प्रदान करती है:load
&require
।
load 'json.rb'
require 'json.rb'
require_relative 'json.rb'
दोनों लोडिंग विधियां पूर्ण और सापेक्ष पथ दोनों को तर्क के रूप में स्वीकार करती हैं। हालांकि, दो अलग-अलग कारक हैं:
- एकाधिक कॉल
load
फ़ाइल को फिर से निष्पादित करेगा, जबकिrequire
. के लिए एकाधिक कॉल फ़ाइल को फिर से निष्पादित नहीं करेगा; इसके बजाय, यहfalse
लौटाएगा । load
करने के लिए कॉल करता है केवल निरपेक्ष और सापेक्ष पथों का समाधान करता है।require
. के लिए कॉल$LOAD_PATH
. पर जांच करता है जब पथ पूर्ण पथ का समाधान नहीं करता है।
एक तीसरा प्रकार है require_relative
, जो रूबी प्रक्रिया की कार्यशील निर्देशिका के बजाय वर्तमान फ़ाइल के स्थान के सापेक्ष कोड की आवश्यकता के लिए सापेक्ष पथ का उपयोग करता है।
आरबीएनवी
एक संस्करण प्रबंधक एक उपकरण है जिसका उपयोग हमारे दुभाषिया (इस मामले में, रूबी) के संस्करणों के बीच प्रबंधन और आसानी से स्विच करने के लिए किया जाता है और हमारी परियोजना के लिए संबंधित रत्न खोजने के लिए स्थान निर्दिष्ट करता है। संस्करण प्रबंधक मोटे तौर पर भाषा अज्ञेयवादी उपकरण हैं, और विभिन्न भाषाओं में उनके संबंधित कार्यान्वयन होते हैं, जैसे कि Nvm, n Node.js के लिए, pyenv के लिए Python, और Rbenv, rvm, और रूबी के लिए chruby। अब, चलिए rbenv
लेते हैं स्पिन के लिए, क्या हम?
रूबी संस्करण स्थापित करें
हम कमांड का उपयोग करते हैं rbenv install
रूबी के किसी भी संस्करण को स्थापित करने के लिए:
# Install ruby 2.6.1
$ rbenv install 2.6.1
Downloading openssl-1.1.1i.tar.gz...
-> https://dqw8nmjcqpjn7.cloudfront.net/e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242
Installing openssl-1.1.1i...
Installed openssl-1.1.1i to /home/directory/.rbenv/versions/2.6.1
Downloading ruby-2.6.1.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.1.tar.bz2
Installing ruby-2.6.1...
ruby-build: using readline from homebrew
Installed ruby-2.6.1 to /home/directory/.rbenv/versions/2.6.1
# Check Installation
$ rbenv versions # Shows all versions installed.
system
2.6.1
# Lookup versions available for installation
$ rbenv install -L
1.8.5-p52
1.8.5-p113
1.8.5-p114
...
2.7.0-rc1
2.7.0-rc2
2.7.0
...
truffleruby+graalvm-20.1.0
truffleruby+graalvm-20.2.0
truffleruby+graalvm-20.3.0
# The full list above amounts to about 500 versions, scrolling through the entire list is a lot.
# The command below is an easy shortcut to find your specific version with fzf.
$ rbenv install `rbenv install -L | fzf`
संस्करणों के बीच स्विच करें
रूबी के संस्करणों के बीच स्विच करने के तरीके की पहचान करने के कई तरीके हैं; निरपवाद रूप से, rbenv
निम्नलिखित करता है:
RBENV_VERSION
की जांच करता है ।- एक
.ruby-version
की खोज करता है स्क्रिप्ट की निर्देशिका और उसके पैरेंट में फ़ाइल तब तक रखें जब तक कि वह रूट डायरेक्टरी में न आ जाए। - एक
.ruby-version
की खोज करता है फ़ाइल$PWD
. में और इसकी मूल निर्देशिका जब तक यह रूट निर्देशिका को हिट नहीं करती। - वैश्विक फ़ाइल का उपयोग करता है
~/.rbenv/version
।
प्राथमिकता ऊपर से नीचे तक जाती है। ~/.rbenv/version
अंतिम फ़ॉलबैक है और इसे वैश्विक संस्करण के रूप में माना जाता है। नीचे देखें:
# Inside First Project Root
# Select ruby version for project
$ touch .ruby-version && echo "2.7.1" >> .ruby-version
# Verify selected version
$ ruby --version
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin20] # Result
$ rbenv version
2.7.1 (set by /path/to/current/directory/.ruby-version) # Result
# Change selected version
$ : >> .ruby-version && echo "2.6.1" >> .ruby-version
# Verify selection change
$ ruby --version
ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-darwin20] # Result
$ rbenv version
2.6.1 (set by /path/to/current/directory/.ruby-version)
# Change selection with RBENV_VERSION while .ruby-version is present
$ export RBENV_VERSION=2.5.1
# Verify selection change
# .ruby-version is ignored.
$ ruby --version
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin20] # Result
$ rbenv version
2.5.1 (set by RBENV_VERSION environment variable) # Result
# Change to a version that is not installed & remove RBENV_VERSION
$ unset RBENV_VERSION & : >> .ruby-version && echo "2.4.1" >> .ruby-version
# Verify selection change
$ ruby --version
rbenv: version `2.4.1' is not installed (set by full/path/to/current/directory/.ruby-version) # Result
शिम्स और रीहैशिंग
डीबग करने में सक्षम होने के लिए इन दो अवधारणाओं को ठीक से समझने की आवश्यकता है rbenv
प्रभावी ढंग से।
शिम्स हल्के बैश स्क्रिप्ट हैं जो आपके PATH
. में मौजूद हैं कमांड को इंटरसेप्ट करना और उन्हें निष्पादन के लिए उपयुक्त संस्करण में रूट करना। उच्च स्तर पर, प्रत्येक आदेश (उदा., rspec
) का अनुवाद rbenv exec rspec
. में किया गया है . नीचे विवरण देखें।
सबसे पहले, rbenv
सभी कमांड के लिए एक शिम बनाता है (rspec
, bundle
, आदि) सभी स्थापित रूबी संस्करणों में संस्करण की परवाह किए बिना सीएलआई को कॉल को इंटरसेप्ट करने के लिए। ये शिम ~/.rbenv/shims
. पर मिल सकते हैं . हर शिम में वही बैश स्क्रिप्ट होती है, जैसा कि नीचे दिखाया गया है:
#!/usr/bin/env bash
set -e
[ -n "$RBENV_DEBUG" ] && set -x
program="${0##*/}"
if [ "$program" = "ruby" ]; then
for arg; do
case "$arg" in
-e* | -- ) break ;;
*/* )
if [ -f "$arg" ]; then
export RBENV_DIR="${arg%/*}"
break
fi
;;
esac
done
fi
export RBENV_ROOT="/home/directory/.rbenv"
exec "/usr/local/Cellar/rbenv/1.1.2/libexec/rbenv" exec "$program" "$@"
इसके बाद, ऊपर की स्क्रिप्ट मोटे तौर पर निम्नलिखित में बदल जाती है:
- यदि प्रोग्राम का नाम
ruby
है तर्क के साथ-e
,- अनुवाद करें
rbenv exec ruby <args>
- अनुवाद करें
- यदि प्रोग्राम का नाम
ruby
है स्क्रिप्ट के पथ के साथ,RBENV_DIR
सेट करें स्क्रिप्ट की निर्देशिका में। यह सक्षम करता हैrbenv
.ruby-version
. को खोजने के लिए$PWD
. से पहले स्क्रिप्ट की निर्देशिका में . यदि एक.ruby-version
दोनों स्थानों में निर्दिष्ट है,rbenv
स्क्रिप्ट की निर्देशिका का चयन करता है।
- यदि प्रोग्राम का नाम रूबी नहीं है,
- अनुवाद करें
rbenv exec <program-name> <args>
।
- अनुवाद करें
अंत में, rbenv exec <command-name> <args>
RBENV_VERSION
. को चेक करके कमांड को पास करने के लिए सही संस्करण की पहचान करता है पर्यावरणपरिवर्ती तारक। याद रखें, RBENV_VERSION
ऊपर परिभाषित एल्गोरिथम द्वारा सेट किया गया है।
आपके PATH
. पर शर्म आती है प्रीपेड होना चाहिए; यह सुनिश्चित करता है कि वे आपके रूबी निष्पादन योग्य के लिए संपर्क का पहला बिंदु हैं और ठीक से इंटरसेप्ट कर सकते हैं। आपके PATH
. को समझने का सबसे अच्छा तरीका मैंने पाया सेटअप करें और जानें कि आपके शिम ठीक से इंटरसेप्ट कर रहे हैं या नहीं:
$ which -a bundle
/path/to/home/.rbenv/shims/bundle
/usr/bin/bundle
which -a bundle
:यह भोलेपन से आपके PATH
. को देखता है और जिस क्रम में यह पाया जाता है, उस स्थान पर प्रिंट आउट करता है जहां bundle
पाया जा सकता है। अगर ~/.rbenv/shims
. में किसी भी चीज़ से पहले कुछ छपा हुआ है , इसका मतलब है कि आपके शिम ठीक से सेट नहीं हैं। rbenv which bundle
इसे प्रकट नहीं करेगा क्योंकि कमांड rbenv
. के संदर्भ में काम करता है अपना PATH
नहीं खोज रहे हैं ।
रीहैशिंग शिम बनाने की प्रक्रिया है। जब आप एक रूबी रत्न स्थापित करते हैं जो निष्पादन योग्य प्रदान करता है, जैसे rspec
, आपको rbenv rehash
चलाने की आवश्यकता है शिम बनाने के लिए ताकि बाद में rspec
. पर कॉल किया जा सके rbenv
. द्वारा इंटरसेप्ट किया जा सकता है और उपयुक्त रूबी संस्करण पर चला गया।
रूबीजेम्स
इसके बाद रूबीगेम्स है। यह आधिकारिक रूबी साइट से उपलब्ध है। RubyGems एक रूबी पैकेजिंग प्रणाली है जिसे पुस्तकालयों के निर्माण, साझाकरण और स्थापना की सुविधा के लिए डिज़ाइन किया गया है; कुछ मायनों में, यह एक वितरण पैकेजिंग प्रणाली है, कहते हैं, उपयुक्त-प्राप्त करें, लेकिन रूबी सॉफ़्टवेयर पर लक्षित है। RubyGems रत्नों को साझा करने का वास्तविक तरीका है। वे आमतौर पर ~/.rbenv/versions/{version-number}/lib/ruby/gems/{minor-version}/
पर इंस्टॉल किए जाते हैं। , या इसका संस्करण, इस पर निर्भर करता है कि किस संस्करण प्रबंधक का उपयोग किया गया है। रूबी की डिफ़ॉल्ट आवश्यक विधि Kernel.require
रत्न स्थापना निर्देशिका से रत्न लोड करने के लिए कोई तंत्र प्रदान नहीं करता है। RubyGems बंदर-पैच Kernel.require
करने के लिए
- सबसे पहले,
$LOAD_PATH
में रत्न खोजें । - अगर नहीं मिला, तो
GEMS INSTALLATION DIRECTORY
में रत्न खोजें .- एक बार मिल जाने पर, पथ को
$LOAD_PATH
. में जोड़ें ।
- एक बार मिल जाने पर, पथ को
यह "मूल रूप से" काम करता है क्योंकि रूबी डिफ़ॉल्ट रूप से 1.9 संस्करण के बाद से RubyGems के साथ आया है; पिछले रूबी संस्करणों को रूबीजम्स को मैन्युअल रूप से स्थापित करने की आवश्यकता थी। हालांकि यह मूल रूप से काम करता है, डिबगिंग करते समय इस अंतर को जानना भी महत्वपूर्ण है।
एक रत्न एक विशिष्ट समस्या को हल करने के लिए उपयोग किए जाने वाले संबंधित कोड का एक समूह है। रत्न स्थापित करें और रत्न पर्यावरण के बारे में निम्न प्रकार से जानकारी प्राप्त करें:
$ gem install gemname
$ gem env
RubyGems Environment:
- RUBYGEMS VERSION: 3.1.2
- RUBY VERSION: 2.7.1 (2020-03-31 patchlevel 83) [x86_64-darwin20]
- INSTALLATION DIRECTORY: /path/to/home/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0
- USER INSTALLATION DIRECTORY: /path/to/home/.gem/ruby/2.7.0
- RUBY EXECUTABLE: /path/to/home/.rbenv/versions/2.7.1/bin/ruby
- GIT EXECUTABLE: /usr/bin/git
- EXECUTABLE DIRECTORY: /path/to/home/.rbenv/versions/2.7.1/bin
- SPEC CACHE DIRECTORY: /path/to/home/.gem/specs
- SYSTEM CONFIGURATION DIRECTORY: /path/to/home/.rbenv/versions/2.7.1/etc
- RUBYGEMS PLATFORMS:
- ruby
- x86_64-darwin-20
- GEM PATHS:
- /path/to/home/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0
- /path/to/home/.gem/ruby/2.7.0
- GEM CONFIGURATION:
...
- REMOTE SOURCES:
- https://rubygems.org/
- SHELL PATH:
- /path/to/home/.rbenv/versions/2.7.1/bin
RubyGems इस समस्या को कैसे हल करता है? यह बंदर Kernel
को पैच कर देता है अपने स्वयं के require
with के साथ सिस्टम की आवश्यकता है तरीका। इस जगह के साथ, जब require honeybadger
कहा जाता है, यह रत्न फ़ोल्डर के माध्यम से honeybadger.rb
के लिए खोज करता है और रत्न मिलने पर सक्रिय हो जाता है।
उदाहरण के लिए, require 'honeybadger'
निम्न के जैसा कुछ उत्पन्न करता है:
spec = Gem::Specification.find_by_path('honeybadger')
spec.activate
किसी रत्न को सक्रिय करने का सीधा सा अर्थ है उसे $LOAD_PATH
. में डालना . RubyGems, मणि को डाउनलोड करने से पहले, रत्न की सभी निर्भरताओं को डाउनलोड करने में भी मदद करता है।
इसके अलावा, Rubygems एक अच्छी सुविधा के साथ जहाज करता है जो आपको संबंधित रत्न की निर्देशिका को gem open <gem-name>
के साथ खोलने में सक्षम बनाता है।; उदाहरण के लिए,
यह हमें हमारे ऐप द्वारा संदर्भित रत्न के विशिष्ट संस्करण को आसानी से ढूंढने/ट्रेस करने की अनुमति देता है।
बंडलर
इस स्तर पर, बंडलर हमारी सभी परियोजना निर्भरताओं को आसानी से निर्दिष्ट करने में हमारी सहायता करता है और वैकल्पिक रूप से प्रत्येक के लिए एक संस्करण निर्दिष्ट करता है। फिर, यह हमारे रत्नों को हल करता है, साथ ही इसे और इसकी निर्भरता को स्थापित करता है। वास्तविक दुनिया के अनुप्रयोगों का निर्माण पूर्व-बंडलर कई चुनौतियों के साथ आया, जैसे कि निम्न:
- हमारे एप्लिकेशन कई निर्भरता के साथ मौजूद हैं, और इन निर्भरताओं में कई अन्य निर्भरताएं और उनके संबंधित संस्करण हैं। एक रत्न का गलत संस्करण स्थापित करने से हमारा ऐप आसानी से टूट जाएगा, और इस समस्या को ठीक करने में बहुत सारे आँसू शामिल थे।
- साथ ही, हमारी निर्भरता के दो(2) समान तृतीय-स्तरीय निर्भरता को संदर्भित कर सकते हैं। संगतता ढूँढना एक समस्या थी, और यदि कोई थी, तो यह एक समस्या थी।
- जहां हमारे पास एक ही मशीन पर कई एप्लिकेशन हैं, विभिन्न निर्भरता के साथ, हमारा एप्लिकेशन मशीन पर इंस्टॉल किए गए किसी भी रत्न तक पहुंच सकता है, जो कम से कम विशेषाधिकार के सिद्धांत के खिलाफ जाता है और मशीन पर स्थापित सभी रत्नों के लिए हमारे एप्लिकेशन को उजागर करता है, चाहे कुछ भी हो क्या वे दुर्भावनापूर्ण हैं।
बंडलर तीनों समस्याओं को हल करता है और हमें निम्न कार्य करके अपनी ऐप निर्भरता को प्रबंधित करने का एक समझदार तरीका देता है।
बंडलर निर्भरता को हल करता है और एक लॉकफाइल बनाता है:
# Gemfile
gem 'httparty'
अगर हम bundle
run चलाते हैं या bundle install
, यह लॉकफाइल उत्पन्न करेगा:
GEM
specs:
httparty (0.18.1)
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
mime-types (3.3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2020.1104)
multi_xml (0.6.0)
PLATFORMS
ruby
DEPENDENCIES
httparty
BUNDLED WITH
2.1.4
ऊपर से, बंडलर httparty
. का संस्करण तैयार करता है स्थापित करने के लिए, साथ ही साथ Gemfile.lock.
. में अपनी निर्भरताएं यह फ़ाइल हमारी ऐप निर्भरता का खाका है और इसे संस्करण नियंत्रण में चेक किया जाना चाहिए। यह सुनिश्चित करता है कि हमारी परियोजना निर्भरताएं पूरे वातावरण (विकास, मंचन, या उत्पादन) के अनुरूप हों।
बंडलर निर्भरता के बीच संगतता का समाधान करता है
यह httparty
. के लिए निर्भरता का समाधान करता है इसकी निर्भरता के लिए एक उपयुक्त संस्करण ढूंढकर और उन्हें निर्दिष्ट करके। बंडलर रत्नों के बीच निर्भरता को हल करने का भी प्रयास करता है। उदाहरण के लिए,
# Gemfile
gem 'httparty' # That relies on gem 'mime-types', '>= 3.0.1, < 4.0.1'
gem 'rest-client' # That relies on gem 'mime-types', '>= 2.0.1, < 3.0'
ऊपर दिया गया उदाहरण मनमाना है और इसके परिणामस्वरूप एक त्रुटि होगी, जैसे कि निम्न:
Bundler could not find compatible versions for gem "mime-types":
In Gemfile:
httparty was resolved to 0.18.1, which depends on
mime-types ('>= 3.0.1, < 4.0.1')
rest-client was resolved to 2.0.4, which depends on
mime-types ('>= 2.0.1, < 3.0')
ऐसा इसलिए है क्योंकि दो रत्नों में ऐसी निर्भरताएँ होती हैं जो संगत नहीं होती हैं और जिन्हें स्वचालित रूप से हल नहीं किया जा सकता है।
बंडलर स्थापित रत्नों तक पहुंच को प्रतिबंधित करता है लेकिन हमारे Gemfile
में निर्दिष्ट नहीं है।
निम्न की तरह एक नमूना जेमफाइल में,
# Gemfile
gem 'httparty'
# irb
require 'rest-client'
# raises
LoadError (cannot load such file -- rest-client)
यह सुनिश्चित करता है कि केवल हमारे Gemfile
. में निर्दिष्ट निर्भरताएँ हमारी परियोजना के लिए आवश्यक हो सकता है।
बंडल निष्पादन
जब आप rspec
run चलाते हैं किसी प्रोजेक्ट निर्देशिका में, Gemfile
में निर्दिष्ट किए गए संस्करण के अलावा किसी भिन्न संस्करण को चलाने की संभावना है . ऐसा इसलिए है क्योंकि Gemfile
. में निर्दिष्ट संस्करण बनाम चलाने के लिए नवीनतम संस्करण का चयन किया जाएगा . bundle exec rspec
सुनिश्चित करता है rspec
उस प्रोजेक्ट के संदर्भ में चलाया जाता है (यानी, जेमफाइल में निर्दिष्ट रत्न)।
बंडल बिनस्टब्स
अक्सर, हम ऐसे लेख पढ़ते हैं जहां हम ./bin/rails
. जैसे कमांड चलाते हैं; यह कमांड bundle exec rails
के समान है . Binstubs bundle exec
. के उपयोग को आसान बनाने के लिए रूबी एक्ज़ीक्यूटिव के चारों ओर रैपर हैं ।
एक बिनस्टब रन उत्पन्न करने के लिए, bundle binstubs gem-name
का उपयोग करें . यह ./bin
. में एक बिनस्टब बनाता है फ़ोल्डर लेकिन --path
. के साथ कॉन्फ़िगर किया जा सकता है निर्देशिका अगर सेट है।
संदर्भ
अधिक जानने के लिए, इन संदर्भों को देखें:
- रत्न कैसे काम करते हैं?
- आरबीएनवी
- रूबीजेम्स
- बंडलर