یک تعاونی تعمیر دوچرخه در تبریز کارهای هفته را در یک فهرست نگه میدارد. خلاصه کردنش سه سطر است، و هر سه به تکهای از کد ختم میشوند که به یک متد داده شده:
tamirat.sum { |t| t[:daghighe] }عدد ۱۲۰ میدهدtamirat.group_by { |t| t[:moshtari] }پژو را با دو کار و ۸۰ دقیقه و رخش را با یکی میدهد، چون group_by یک هش برمیگرداند از مقدار بلوک به عضوهای متناظرشtamirat.select { |t| t[:daghighe] > 38 }.map { |t| t[:kar] }جواب[:charkh, :tormoz]میدهد
آکولاد، حرکت تعیینکننده این زبان است. بلوک تکهای از کد است که به یک متد داده میشود، نوشتهشده داخل آکولاد یا میان do و end، و همین که این دیده شود کتابخانه دیگر شبیه فهرستی از توابع نیست و شبیه مجموعهای از متدهاست که همهشان دستور میگیرند. sum و group_by و select و map یک ایدهاند چهار بار، و متد خود شما با یک کلمه به آنها میپیوندد: yield بلوکی را اجرا میکند که فراخوان داده است.
دومین چیزی که باید دید این است که قاعده «همه چیز شی است» استثنا ندارد. 25.class برابر Integer است، nil.class برابر NilClass و :tormoz.class برابر Symbol، پس هیچ چیز اینجا یک مقدار اولیه نیست که از نحو فراخوانی متد قایم شده باشد. nil.to_a یک آرایه خالی است، که دلیل این است که nil در روبی بهندرت برنامه را میایستاند، جوری که در جاوا میایستاند. از یک عدد صحیح که تبارش را بپرسید، جواب میدهد Integer و Numeric و Comparable و Object و Kernel و BasicObject.
سمبل رشته نیست، و همین تفاوت نکته اصلی است
:tormoz و "tormoz" شبیه هماند و برای دو کار جدا به کار میروند. سمبل یک نام است که یک بار ساخته میشود و دوباره به کار میرود، و رشته متنی است که ممکن است کسی ویرایشش کند. پس سمبل برای کلید یک هش یا هویت یک کار درست است، و رشته برای نام دوچرخه. سوابق آن تعاونی عمداً از هر دو استفاده میکنند: نوع کار سمبل است چون ششتاست و هیچوقت عوض نمیشود، و نام مشتری رشته است چون هرکسی هرچه بخواهد مینویسد.
بیشترِ آنچه کد روبی را برای کسی که ننوشته خواندنی میکند همین تمایز است. بخش دیگرش این است که زبان حول خواندن طراحی شده نه نوشتن، که دلیل این است که آن زنجیره select و map مثل یک جمله خوانده میشود و تقریباً هر متدی که مقدار درست یا نادرست برمیگرداند به علامت پرسش ختم میشود.
نسخهای که با دستگاه میآید همانی نیست که باید به کار برد
این تله عملی است و ارزش دارد پیش از هر چیز دیگری با آن روبهرو شوید. روی مک، /usr/bin/ruby نسخه 2.6.10 است که در سال ۲۰۲۲ منتشر شد و چهار نسخه اصلی عقب است، و اپل آن را منسوخ اعلام کرده بدون اینکه جایگزینی نام ببرد. هر چیزی که بالاتر نوشته شد رویش اجرا میشود. هر چیزی که در پنج سال اخیر نوشته شده باشد اغلب نه.
دو نمونه، اجراشده روی همان مفسر در سوم سپتامبر ۲۰۲۶. یک تعریف متد بدون بدنه، def jam(a) = a.sum، جواب میدهد syntax error, unexpected '='. تطبیق الگو، همان شکل case و in، جواب میدهد syntax error, unexpected in, expecting when. تطبیق الگو و متد بدون بدنه هر دو در روبی ۳٫۰ در دسامبر ۲۰۲۰ آمدند. هیچکدام عجیب نیستند و هر دو در کد معمولیِ نوشتهشده از آن به بعد پیدا میشوند. روی توزیعهای لینوکس هم همین شکل تکرار میشود با عددهای دیگر، پس این مسئله مکینتاش نیست، مسئله «نسخهای که سیستم میدهد» است.
پس اولین حرکت در این زبان اصلاً یک سطر روبی نیست: یک مدیر نسخه نصب کنید، یک نسخه ۳ نصب کنید، و هیچوقت نسخه سیستم را صدا نزنید. انجام دادن این کار در بعدازظهر اول، دو هفته خطای نحوی گیجکننده را به هیچ تبدیل میکند.
اجراشده روی مفسری که مک میدهد
روی /usr/bin/ruby چه کار میکند، آزموده نه فرضشده
هر سطر پایین روی نسخه 2.6.10 در سوم سپتامبر ۲۰۲۶ اجرا شد، و شکستها خطای نحویاند نه هشدار.
روبی 2.6.10، نسخهای که از قبل روی دستگاه هست
- بلهبلوک، yield، سمبلکل بخش اول بدون تغییر اجرا میشودبله
- بلهsum و group_by و select و mapهمان ۱۲۰ دقیقه و همان دو سمبل، دقیقاً مثل بالابله
- خیرتعریف متد بدون بدنهخطای نحوی سر علامت مساوی. روبی ۳٫۰، دسامبر ۲۰۲۰.خیر
- خیرتطبیق الگوخطای نحوی سر in، که انتظار when داشت. همان نسخه.خیر
- بررسی نشدهاینکه هیچوقت نسخه تازهتری بیاید یا نهمنسوخ اعلام شده، بدون نام بردن از جایگزین. بیرون از اپل کسی نمیداند.بررسی نشده
سطر آخر خط تیره است نه ضربدر، چون هیچجا جوابی به آن داده نشده، نه اینکه آزموده و رد شده باشد. همین هم دلیل این است که جواب، مدیر نسخه است و نه صبر کردن.
ابزار، و سالی که این حرف درست است
rbenv، رایگان و متنباز از سال ۲۰۱۱، نسخه مفسر را برای هر پروژه نصب و عوض میکند. جای استفاده از روبیای را گرفت که با سیستمعامل آمده، و تمام کارش همان بخش بالاست. Bundler که رایگان است، gemهای یک پروژه را حل میکند و در یک فایل قفل سنجاق میکند؛ جای نصب سراسری gem و بعد فهمیدن روی ماشین بعدی که چه نسخههایی فرض شده بوده را گرفت. روبی ۳٫۰ از دسامبر ۲۰۲۰ هم خطی است که باید این طرفش بود.
و یک نکته که در فارسی باید گفته شود و در انگلیسی لازم نیست: کار محلی روبی در ایران تقریباً وجود ندارد. تقریباً هر چیزی که با این زبان نوشته میشود یک فریمورک وب است و کاری که با آن گرفته میشود دورکاری برای بیرون است. این را میشود دوست داشت یا نداشت، ولی تصمیم یاد گرفتن روبی اینجا در عمل تصمیم یاد گرفتن آن فریمورک و کار کردن با کارفرمای خارجی است، و بهتر است از روز اول همینطور دیده شود تا سال دوم.
اشتباه: خواندن یک بلوک بهشکل تعریف یک تابع
کسی که از زبان دیگری میآید { |t| t[:daghighe] } را یک تابع بینام میخواند که بهعنوان آرگومان داده شده، که آنقدر نزدیک هست که به کار بیاید و در یک چیز غلط است. بلوک آرگومان نیست. چیز دومی است که فراخوانی با خودش حمل میکند، نام ندارد، جایی در فهرست پارامترها ندارد، و یک متد یا به آن yield میکند یا کاملاً نادیدهاش میگیرد بدون هیچ خطایی.
به همین دلیل است که tamirat.each بدون بلوک بهجای اعتراض یک شمارنده برمیگرداند، و به همین دلیل متدی که بلوک میگیرد و متدی که نمیگیرد سر محل فراخوانی یکسان به نظر میرسند. نشانهای که باید یاد گرفت: بلوک بعد از پرانتز بسته نوشته میشود، هرگز داخلش، و در هر فراخوانی دقیقاً یکی هست.
چیزی که این صفحه جواب نمیدهد این است که آن فریمورک روی سرور واقعاً چه میکند، که زیر وب است؛ و مسئله نسخه و وابستگی بالا حالت خاصی از مسئلهای عمومی است که زیر انتشار و استقرار حل میشود. زبانی هم که همان جای کاری را پر میکند و در ایران کار محلی دارد پایتون است، و آنکه بیشترین کار محلی وب را دارد PHP، و جای همهشان کنار هم زبانهای برنامهنویسی.