BUNDLE-EXEC(1) General Commands Manual BUNDLE-EXEC(1)

bundle-exec - اجرای یک دستور در بافت و زمینهٔ بسته (bundle)

bundle exec [--gemfile=GEMFILE] command

این دستور، دستور مشخص‌شده را طوری اجرا می‌کند که تمام gemهای تعیین‌شده در [Gemfile(5)][Gemfile(5)] برای فراخوانی توسط require در برنامه‌های Ruby در دسترس قرار گیرند.

در اصل، اگر در حالت معمول دستوری مانند rspec spec/my_spec.rb را اجرا می‌کردید و اکنون می‌خواهید از gemهای مشخص‌شده در [Gemfile(5)][Gemfile(5)] که از طریق bundle install(1) bundle-install.1.html نصب شده‌اند استفاده کنید، باید دستور bundle exec rspec spec/my_spec.rb را اجرا نمایید.

توجه داشته باشید که bundle exec نیازی ندارد که فایل اجرایی مورد نظر حتماً در متغیر $PATH پوستهٔ شما موجود باشد.

استفاده از gemfile مشخص‌شده به جای [Gemfile(5)][Gemfile(5)].

اگر از پرچم --binstubs در bundle install(1) bundle-install.1.html استفاده کنید، Bundler به‌طور خودکار دایرکتوری‌ای ایجاد می‌کند (که به‌طور پیش‌فرض app_root/bin است) شامل تمام فایل‌های اجرایی که از طریق gemهای موجود در bundle در دسترس هستند.

پس از به‌کارگیری --binstubs، اجرای bin/rspec spec/my_spec.rb دقیقاً معادل با bundle exec rspec spec/my_spec.rb خواهد بود.

دستور bundle exec تغییراتی در متغیرهای محیطی پوسته ایجاد کرده و سپس دستور مشخص‌شده توسط شما را به‌طور کامل اجرا می‌کند.

  • اطمینان حاصل می‌کند که هنوز امکان اجرای دستور bundle از درون دستوری که توسط bundle exec فراخوانی شده است وجود دارد (با استفاده از $BUNDLE_BIN_PATH)
  • دایرکتوری حاوی فایل‌های اجرایی مربوط به bundle شما (مانند rails، rspec و rackup) را در متغیر $PATH قرار می‌دهد
  • اطمینان حاصل می‌کند که اگر bundler در زیرپوسته (subshell) فراخوانی شود، از همان Gemfile استفاده کند (با تنظیم BUNDLE_GEMFILE)
  • افزودن -rbundler/setup به متغیر $RUBYOPT، که تضمین می‌کند برنامه‌های Ruby فراخوانی‌شده در زیرپوسته می‌توانند gemهای موجود در bundle را شناسایی کنند

این دستور همچنین Rubygems را به روش‌های زیر تغییر می‌دهد:

  • جلوگیری از بارگذاری gemهای اضافی که در bundle موجود نیستند
  • تغییر متد gem به‌گونه‌ای که اگر gem مطابق با نیازمندی‌ها در bundle موجود باشد، هیچ عملی انجام ندهد (no-op)، و در صورتی که موجود نباشد، خطای Gem::LoadError صادر کند
  • بی‌اثر کردن متد Gem.refresh (تنظیم به no-op)، زیرا هنگام استفاده از bundler ایندکس منبع همیشه ثابت و مسدود (frozen) است و این کار از سرایت gemهای سیستمی به محیط جلوگیری می‌کند
  • بازنویسی متد Gem.bin_path برای استفاده از gemهای درون bundle، تا فایل‌های اجرایی سیستمی به درستی کار کنند
  • افزودن تمام gemهای موجود در bundle به Gem.loaded_specs

در نهایت، اگر فایل قفل و Gemfile با یکدیگر مطابقت نداشته باشند، bundle exec فایل Gemfile.lock را نیز به‌طور ضمنی اصلاح می‌کند. ابزار Bundler برای تعیین مواردی از قبیل گروه‌های gem، autorequire و پلتفرم‌ها به Gemfile نیاز دارد و این اطلاعات در فایل قفل ذخیره نمی‌شوند. برای اجرای موفقیت‌آمیز bundle exec باید Gemfile و فایل قفل با هم همگام باشند؛ بنابراین bundle exec پیش از اجرا، فایل قفل را به‌روزرسانی می‌کند.

به‌طور پیش‌فرض، هنگام تلاش برای اجرای bundle exec روی فایلی که دارای shebang زبان روبی است، Bundler به جای استفاده از Kernel.exec آن فایل را از طریق Kernel.load بارگذاری می‌کند. در اکثر قریب به اتفاق موارد، این یک بهبود کارایی محسوب می‌شود. در موارد معدودی، این رفتار ممکن است عوارض جانبی ظریفی ایجاد کند (مانند وابستگی به مقدار دقیق $0 یا __FILE__)؛ این بهینه‌سازی را می‌توان با فعال‌سازی تنظیم disable_exec_load غیرفعال کرد.

هر کد روبی که یک زیرپوسته باز کند (مانند متد system، بک‌تیک‌ها (``) یا %x{}) به‌طور خودکار از محیط فعلی Bundler استفاده خواهد کرد. اگر نیاز دارید دستوری در پوسته اجرا کنید که جزئی از bundle فعلی شما نیست، از متد with_unbundled_env همراه با یک بلوک کد استفاده نمایید. به تمام زیرپوسته‌هایی که درون این بلوک ایجاد می‌شوند، محیطی اختصاص می‌یابد که پیش از فعال شدن Bundler وجود داشته است. برای نمونه، دستورات Homebrew کدهای Ruby را اجرا می‌کنند، اما در داخل یک bundle کارایی ندارند:

Bundler.with_unbundled_env do
  `brew install wget`
end

استفاده از with_unbundled_env همچنین در حالتی که می‌خواهید دستوری را در یک bundle دیگر اجرا کنید ضروری است. هر دستور Bundler که درون زیرپوسته اجرا شود Gemfile فعلی را به ارث می‌برد، بنابراین دستوراتی که باید در بافت یک bundle متفاوت اجرا شوند نیز نیاز به استفاده از with_unbundled_env دارند.

Bundler.with_unbundled_env do
  Dir.chdir "/other/bundler/project" do
    `bundle exec ./script`
  end
end

ابزار Bundler توابع کمکی سودمندی فراهم می‌کند که متدهای system و exec را پوشش می‌دهند و می‌توان آن‌ها را به این صورت استفاده کرد:

Bundler.unbundled_system('brew install wget')
Bundler.unbundled_exec('brew install wget')

در حال حاضر، سیستم پلاگین Rubygems هنگامی که کدی rubygems.rb را require می‌کند، نیازمند تمام فایل‌های با نام rubygems_plugin.rb در مسیر بارگذاری هر gem نصب‌شده است. این شامل فایل‌های اجرایی نصب‌شده در سیستم، نظیر rails، rackup و rspec نیز می‌شود.

از آنجا که پلاگین‌های Rubygems می‌توانند حاوی کدهای دلخواه Ruby باشند، معمولاً در نهایت باعث فعال‌سازی خود یا وابستگی‌هایشان می‌شوند.

برای نمونه، gem با نسخهٔ gemcutter 0.5 به json_pure وابسته بود. اگر آن نسخه از gemcutter را نصب داشتید (حتی اگر نسخهٔ جدیدتری بدون این مشکل را نیز نصب کرده بودید)، Rubygems نسخهٔ gemcutter 0.5 و آخرین نسخهٔ json_pure را فعال می‌کرد.

اگر Gemfile(5) شما نیز شامل json_pure بود (یا gem دیگری که به json_pure وابسته بود)، آخرین نسخهٔ موجود در سیستم شما ممکن بود با نسخهٔ تعیین‌شده در Gemfile(5) یا نسخهٔ ثبت‌شده در Gemfile.lock تداخل پیدا کند.

در صورت بروز چنین رخدادی، bundler پیام زیر را اعلام خواهد کرد:

You have already activated json_pure 1.4.6 but your Gemfile
requires json_pure 1.4.3. Consider using bundle exec.

در چنین شرایطی، تقریباً به‌طور قطع مایل خواهید بود gem پایه‌ای را که حاوی پلاگین مشکل‌ساز است حذف کنید. به‌طور کلی، توسعه‌دهندگان این پلاگین‌ها (در این مورد، gem مربوط به gemcutter) نسخه‌های جدیدتری منتشر کرده‌اند که در پلاگین‌های خود احتیاط بیشتری اعمال می‌کنند.

شما می‌توانید با اجرای دستور زیر فهرستی از تمام gemهای حاوی پلاگین‌های gem را بیابید:

ruby -e "puts Gem.find_files('rubygems_plugin.rb')"

دست‌کم، باید همهٔ نسخه‌ها به جز جدیدترین نسخه از هر پلاگین gem را حذف کرده و همچنین تمام پلاگین‌های gem را که استفاده نمی‌کنید پاکسازی نمایید (gem uninstall gem_name).

September 2025