রুবিতে ডিপেন্ডেন্সি ম্যানেজ করা সাধারণত আমাদের প্রজেক্ট যে রুবি এবং জেম ভার্সনে নির্ভর করে সেটি স্পেসিফাই করার সাথে জড়িত। রুবির সাথে কাজ করার আমার অভিজ্ঞতিতে, ডিপেন্ডেন্সি ডিবাগ করা আমার সবচেয়ে বড় চ্যালেঞ্জের একটা। ফেইলার খুব কমন নয় কারণ অনেক জিনিস "জাস্ট ওয়ার্কস" করে; তবে, যখন জিনিসগুলো ভুল হয়, সেগুলো সাধারণত অনাবশ্যকভাবে কঠিন হয় ডিবাগ ও ফিক্স করতে। এই আর্টিকেলে, আমি রুবিতে ডিপেন্ডেন্সি ম্যানেজমেন্টে জড়িত টুকরোগুলো বिछাব। এটি আপনাকে এই স্ট্রেঞ্জ ইস্যুগুলো ঘটলে ডিবাগ করতে সাহায্য করবে।

রুবি কোড লোডিং
ডিফল্টভাবে, রুবি ল্যাঙ্গুয়েজ দুটি প্রধান মেথড প্রদান করে যেকোনো অন্যথাই ডিফাইন করা কোড লোড করার জন্য: load & require।
load 'json.rb' require 'json.rb' require_relative 'json.rb' দুই লোডিং মেথডই অ্যাবসোলিউট এবং রিলেটিভ পাথ আর্গুমেন্ট হিসেবে এক্সেপ্ট করে। তবে, দুটি ডিফারেনশিয়েটিং ফ্যাক্টর রয়েছে:
load-এ একাধিক কল ফাইলটি রি-এক্সিকিউট করবে, যতক্ষণrequire-এ একাধিক কল ফাইলটি রি-এক্সিকিউট করবে না; বরং এটিfalseরিটার্ন করবে।load-এ কল শুধু অ্যাবসোলিউট এবং রিলেটিভ পাথে রেজলভ করে।require-এ কল$LOAD_PATHচেক করে যখন পাথ অ্যাবসোলিউট পাথে রেজলভ করে না।
একটি থার্ড ভ্যারিয়েন্ট হলো require_relative, যা রিলেটিভ পাথ ব্যবহার করে কোড রিকোয়ার করে বর্তমান ফাইলের লোকেশন রিলেটিভ থেকে নয় যে রুবি প্রসেসের ওয়ার্কিং ডিরেক্টরি।
Rbenv
A version manager is a tool used to manage and easily switch between versions of our interpreter (in this case, Ruby) and specify the location to find respective gems for our project. Version managers are largely language agnostic tools, and various languages have their respective implementations, such as Nvm, n for Node.js, pyenv for Python, and Rbenv, rvm, and chruby for Ruby. Now, let's take rbenv for a spin, shall we?
রুবি ভার্সন ইনস্টল
আমরা 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 # উপরের ফুল লিস্ট প্রায় ৫০০ ভার্সন, পুরো লিস্ট স্ক্রল করা একটা লোটা। # নিচের কমান্ডটি আপনার স্পেসিফিক ভার্সন fzf দিয়ে খুঁজে বের করার ইজি শর্টকাট। $ rbenv install `rbenv install -L | fzf` ভার্সন সুইচ
রুবি ভার্সন সুইচ করার কীভাবে আইডেন্টিফাই করবেন তার অনেক উপায় আছে; অবশ্যই, rbenv নিচের কাজগুলো করে:
RBENV_VERSIONচেক করে।- স্ক্রিপ্টের ডিরেক্টরি এবং তার প্যারেন্টে
.ruby-versionফাইল সার্চ করে যতক্ষণ না রুট ডিরেক্টরি হিট করে। $PWDএবং এর প্যারেন্ট ডিরেক্টরিতে.ruby-versionফাইল সার্চ করে যতক্ষণ না রুট ডিরেক্টরি হিট করে।- গ্লোবাল ফাইল
~/.rbenv/versionব্যবহার করে।
প্রায়োরিটি টপ থেকে বটম। ~/.rbenv/version ফাইনাল ফলব্যাক এবং গ্লোবাল ভার্সন হিসেবে ট্রিট করা হয়। নিচে দেখুন:
# Inside First Project Root # প্রজেক্টের জন্য রুবি ভার্সন সিলেক্ট করুন $ touch .ruby-version && echo "2.7.1" >> .ruby-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 # সিলেক্টেড ভার্সন চেঞ্জ করুন $ : >> .ruby-version && echo "2.6.1" >> .ruby-version # সিলেকশন চেঞ্জ ভেরিফাই করুন $ 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) # RBENV_VERSION দিয়ে সিলেকশন চেঞ্জ করুন .ruby-version থাকার সময় $ export RBENV_VERSION=2.5.1 # সিলেকশন চেঞ্জ ভেরিফাই করুন # .ruby-version ইগনোর হয়। $ 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 # একটি ইনস্টল না করা ভার্সনে চেঞ্জ করুন & RBENV_VERSION রিমুভ করুন $ unset RBENV_VERSION & : >> .ruby-version && echo "2.4.1" >> .ruby-version # সিলেকশন চেঞ্জ ভেরিফাই করুন $ 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, ইত্যাদি) জন্য একটি শিম তৈরি করে সমস্ত ইনস্টল করা রুবি ভার্সন জুড়ে যাতে CLI-এ কল ইন্টারসেপ্ট করা যায় ভার্সন নির্বিশেষে। এই শিমস পাওয়া যায় ~/.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। এটি অফিশিয়াল রুবি সাইট থেকে উপলব্ধ। RubyGems একটি রুবি প্যাকেজিং সিস্টেম ডিজাইন করা হয়েছে লাইব্রেরি তৈরি, শেয়ার, এবং ইনস্টল ফ্যাসিলিটেট করতে; কিছু কিছু রকমে, এটি একটি ডিস্ট্রিবিউশন প্যাকেজিং সিস্টেমের মতো, যেমন apt-get, কিন্তু রুবি সফটওয়্যার টার্গেটেড। RubyGems জেম শেয়ার করার ডি-ফ্যাক্টো মেথড। সেগুলো সাধারণত ইনস্টল থাকে ~/.rbenv/versions/{version-number}/lib/ruby/gems/{minor-version}/-এ, বা এর ভ্যারিয়েন্টে, নির্ভর করে কোন ভার্সন ম্যানেজার ব্যবহার করা হচ্ছে। রুবির ডিফল্ট রিকোয়ার্ড মেথড Kernel.require কোনো মেকানিজম প্রদান করে না জেমস ইনস্টলেশন ডিরেক্টরি থেকে লোড করার জন্য। RubyGems Kernel.require মन्कি-প্যাচ করে:
- প্রথম,
$LOAD_PATH-এ জেমস সার্চ করে। - যদি না পাওয়া যায়,
GEMS INSTALLATION DIRECTORY-এ জেমস সার্চ করে।- একবার পাওয়া যাওয়ায়, পাথ
$LOAD_PATH-এ অ্যাড করে।
- একবার পাওয়া যাওয়ায়, পাথ
এটি "নেটিভলি" কাজ করে কারণ রুবি রুবিজেমসের সাথে ডিফল্টভাবে আসে ১.৯ ভার্সন থেকে; পূর্বের রুবি ভার্সনগুলোর জন্য 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 মেথড দিয়ে মन्कি প্যাচ করে। এই ইন-প্লেস থাকার কারণে, যখন require honeybadger কল হয়, এটি জেমস ফোল্ডার সার্চ করে honeybadger.rb এবং জেম এক্টিভেট করে যখন পাওয়া যায়।
উদাহরণস্বরূপ, require 'honeybadger' কিছু নিচের মতো প্রোডিউস করে:
spec = Gem::Specification.find_by_path('honeybadger')spec.activate
একটি জেম এক্টিভেট করা সিম্পলি মানে সেটিকে $LOAD_PATH-এ রাখা। RubyGems একটি জেমের সকল ডিপেন্ডেন্সি ডাউনলোড করতে সাহায্য করে জেমটি ডাউনলোড করার আগে।
এছাড়া, Rubygems একটি সুন্দর ফিচার দিয়ে থাকে যা আপনাকে অ্যাসোসিয়েটেড জেমের ডিরেক্টরি ওপেন করতে দেয় gem open <gem-name> দিয়ে; উদাহরণস্বরূপ,

এটি আমাদের সহজে খুঁজে বের করতে দেয়/ট্রেস করতে দেয় আপনার অ্যাপ যে স্পেসিফিক ভার্সন জেম রেফারেন্স করছে।
Bundler
এই লেয়ারে, Bundler আমাদের সহজে সকল প্রজেক্ট ডিপেন্ডেন্সি স্পেসিফাই করতে দেয় এবং অপশনালি প্রতিটোর জন্য একটি ভার্সন স্পেসিফাই করতে দেয়। তারপর, এটি আমাদের জেমস রিজল্ভ করে, সেইসাথে ইনস্টল করে এটা এবং এর ডিপেন্ডেন্সি। রিয়েল-ওয়ার্ল্ড অ্যাপ্লিকেশন বিল্ড করা pre-bundler এ চ্যালেঞ্জের無數 ছিল, যেমন নিচের موارد:
- আমাদের অ্যাপ্লিকেশন অনেক ডিপেন্ডেন্সির সাথে একজিস্ট করে, এবং এই ডিপেন্ডেন্সিগুলোর বিভিন্ন অন্য ডিপেন্ডেন্সি এবং তাদের রেসপেক্টিভ ভার্সন। এক জেমের ভুল ভার্সন ইনস্টল করা সহজে আমাদের অ্যাপ ভাঙা দেবে, এবং এই সমস্যা ফিক্স করতে অনেক আঁসু লাগত।
- এছাড়া, আমাদের দুটি ডিপেন্ডেন্সি একই থার্ড-লেভেল ডিপেন্ডেন্সি রেফার করতে পারে। কম্প্যাটিবিলিটি খুঁজে বের করা একটি ইস্যু, এবং যদি কোনো থাকে, সেটি একটি সমস্যা ছিল।
- যদি একই মেশিনে একাধিক অ্যাপ্লিকেশন থাকে, বিভিন্ন ডিপেন্ডেন্সির সাথে, আমাদের অ্যাপ্লিকেশন মেশিনে ইনস্টল করা যেকোনো জেম অ্যাক্সেস করতে পারে, যা লীস্ট প্রivilেজের সিদ্ধান্তের বিপরীত যায় এবং আমাদের অ্যাপ্লিকেশনকে মেশিনে ইনস্টল করা সকল জেম এক্সপোজ করে, নির্বিশেষে সেগুলো ম্যালিশিয়াস কিনা।
Bundler সallón তিনটি সমস্যা সমাধান করে এবং আমাদের একটি sane উপায় দেয় আমাদের অ্যাপ ডিপেন্ডেন্সি ম্যানেজ করতে নিচের কাজগুলো করে।
Bundler ডিপেন্ডেন্সি রিজল্ভ করে এবং একটি লকফাইল জেনারেট করে:
# Gemfile gem 'httparty' যদি আমরা bundle বা 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-এ। এই ফাইল আমাদের অ্যাপ ডিপেন্ডেন্সির ব্লুপ্রিন্ট এবং ভার্সন কন্ট্রোলে চেক ইন করা উচিত। এটি নিশ্চিত করে যে আমাদের প্রজেক্ট ডিপেন্ডেন্সি কনসিস্টেন্ট সব এনভায়রনমেন্টে (ডেভেলপমেন্ট, স্টেজিং, বা প্রোডাকশন)।
Bundler ডিপেন্ডেন্সির মাঝে কম্প্যাটিবিলিটি রিজল্ভ করে
এটি httparty-র ডিপেন্ডেন্সি রিজল্ভ করে এর ডিপেন্ডেন্সির জন্য একটি উপযুক্ত ভার্সন খুঁজে বের করে এবং সপেসিফাই করে। বান্ডলার জেমসের মাঝে ডিপেন্ডেন্সি রিজল্ভ করার চেষ্টা ও করে। উদাহরণস্বরূপ,
# Gemfile gem 'httparty' # যা নির্ভর করে gem 'mime-types', '>= 3.0.1, < 4.0.1' gem 'rest-client' # যা নির্ভর করে 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') এটি কারণ দুটি জেমের ডিপেন্ডেন্সি কম্প্যাটিবল নয় এবং অটোমেটিকলি রিজল্ভ করা যায় না।
Bundler অ্যাক্সেস রিস্ট্রিক্ট করে জেমস ইনস্টলড কিন্তু আমাদের Gemfile-এ স্পেসিফাইড নয়
একটি স্যাম্পল জেমফাইল যেমন নিচেরটি,
# Gemfile gem 'httparty' # irb require 'rest-client' # raises LoadError (cannot load such file -- rest-client) এটি নিশ্চিত করে যে শুধু আমাদের Gemfile-এ স্পেসিফাইড ডিপেন্ডেন্সিই আমাদের প্রজেক্ট দ্বারা রিকোয়ার করা যাবে।
Bundle exec
যখন আপনি একটি প্রজেক্ট ডিরেক্টরিতে rspec রান করেন, এটি সম্ভব যে একটি ভিন্ন ভার্সন রান হয় সেটি যা Gemfile-এ স্পেসিফাইড। এটি কারণ সবচেয়ে রিসেন্ট ভার্সন সিলেক্ট হবে রান করার জন্য ভার্সন যা Gemfile-এ স্পেসিফাইড। bundle exec rspec নিশ্চিত করে rspec রান হচ্ছে সেই প্রজেক্টের কন্টেক্সটে (অর্থাৎ, Gemfile-এ স্পেসিফাইড জেমস)।
Bundle binstubs
প্রায়ই আমরা আর্টিকেল পড়ি যেখানে আমরা কমান্ডের মত ./bin/rails রান করি; এই কমান্ড bundle exec rails-এর সাদৃশ্য। Binstubs হলো রুবি এক্সিকিউটেবলের ওয়ারپر bundle exec ব্যবহারের সহজ করতে।
একটি binstub জেনারেট করতে, bundle binstubs gem-name ব্যবহার করুন। এটি ./bin ফোল্ডারে একটি binstub তৈরি করে কিন্তু --path ডিরেক্টরি দিয়ে কনফিগার করা যায় যদি সেট করা থাকে।
রেফারেন্স
আরও জানতে, এই রেফারেন্স চেক আউট করুন:
- How Do Gems Work?
- Rbenv
- RubyGems
- Bundler