آشنایی با بلوک Ruby – به زبان ساده


یکی از قابلیتهای منحصر به فرد Ruby که غالباً به درستی درک نشده است، قابلیت بلوکهای Ruby است. در واقع بلوکها همان نسخه کلوژر در Ruby هستند و میتوان از آنها برای افزایش قابلیت استفاده مجدد از کد و کاهش حجم نوشتاری کد استفاده کرد. اما کلیدواژههایی مانند yield در نگاه نخست ممکن است غریب به نظر بیایند و موجب شوند که این کارکرد برای ما نامأنوس باشد. در این مقاله به توضیح مفاهیم مقدماتی بلوک Ruby میپردازیم تا دانشمان در این مورد افزایش یابد.
بلوک چیست؟
بلوکها تابعهای بینامی هستند که مقدار بازگشتی آنها روی متدی که آنها را فراخوانی کرده اعمال میشود. این تعریف شاید چندان روشن نباشد، بنابراین در ادامه آن را بیشتر توضیح میدهیم.
بلوکها شامل کدی بین مجموعهای از آکولادها یا یک جفت do/end هستند. آکولادها یک تعریف تکخطی ارائه میکنند و جفت do/end یک تعریف چندخطی در اختیار ما قرار میدهد:
تعریف تکخطی به طور عمده برای کدهای تکخطی استفاده میشود. به منظور انسجام کد، در همه بخشهای این راهنما از ساختار do/end استفاده کردهایم. اگر قبلاً تجربه کار با زبان برنامه نویسی روبی را داشته باشید، حتماً با بلوکها مواجه شدهاید. متدهای each و map دو مورد از رایجترین تکرارکنندهها هستند که کاربرد بلوک را اجرا میکنند:
چگونه بلوک بسازیم؟
اگر بخواهیم یک تابع ساده بسازیم که یک ورودی که داخل “⭐️” قرار گرفته است را پرینت کند، باید چیزی مانند زیر بنویسیم:
اگر بخواهیم این تابع را با استفاده از نمادگذاری بلوک بازنویسی کنیم، به صورت زیر عمل میکنیم:
چنان که میبینید، مقدار بازگشتی محتوای بلوک، آن چیزی است که به کلیدواژه yield تابع ارسال شده است. همچنین میتوانیم بلوک را با ارسال پارامترهایی به تابعی که ایجاد کردهایم، سفارشیسازی کنیم:
اگر بخواهیم به مقدار خروجی تابع خود در بلوک الصاقی ارجاع بدهیم، میتوانیم آرگومانهایی به yield ارسال کرده و در پارامترهای بلوک به آنها ارجاع بدهیم:
مزیت بلوک نسبت به تابع معمولی چیست؟
تا به اینجا کار خاصی با بلوک انجام ندادهایم که یک متد معمولی نتواند انجام ندهد. بلوکها در مواردی که بخواهیم منطق اشتراکی را روی چارچوبهای مختلف به روشی آسان اعمال کنیم، مفید واقع میشوند.
برای نمونه فرض کنید، میدانیم که همواره باید خروجی یک سری از دستورها را بین یک مجموعه “⭐⭐⭐” پرینت کنیم. در این حالت میتوانیم از بلوکها استفاده کرده و منطق مورد نظر را روی چارچوبهای مختلف بدون نیاز به تابعهای کمکی اعمال کنیم:
چنان که در کد فوق میبینید ستارهها همواره پیش و پس از کد اجرا شده در بلوک پرینت میشوند. حتی با این که قلب قرمز به روشی بسیار متفاوت از قلب بنفش واکشی میشود، اما متد star_wrap به ما امکان میدهد که منطق پوششی ستاره را روی هر دو چارچوب به روشی یکسان اعمال کنیم.
مدیریت خطای بلوک
هر متدی میتواند یک بلوک بپذیرد، هر چند در تابع ارجاع نیافته باشد. در این حالت محتوای بلوک کاری انجام نمیدهد.
ما میتوانیم همه بلوکها را در مثالهای فوق فراخوانی کنیم، زیرا از کلیدواژه yield استفاده کردهایم. بنابراین شاید بپرسید اگر از کلیدواژه yield استفاده کنیم و بلوکی ارائه نکنیم، چه اتفاقی میافتد؟ در این حالت یک خطا ایجاد میشود.
با استفاده از عبارت ?block_given برای بررسی کاربرد بلوک، میتوانیم از بروز این خطا جلوگیری کنیم:
ارسال بلوک به عنوان یک پارامتر
اگر بخواهیم در مورد فراخوانی یک بلوک با صراحت عمل و یک ارجاع به آن بدهیم، باید آن را به صورت یک پارامتر به متدی ارسال کنیم:
در این نمونه، بلوک به شیء Proc تبدیل میشود که میتوان با استفاده از.call آن را فراخوانی کرد. استفاده از بلوکها به این ترتیب در مواردی مفید است که بخواهیم بلوکها را بین تابعها ارسال کنیم. بدین ترتیب پارامتر بلوک را به عنوان آخرین آرگومان و الصاق یک & ارسال میکنیم.
در ادامه متدهای star_wrap_a و star_wrap_b دقیقاً همین کار را انجام میدهند:
کاربرد عملی بلوکها
در یک اپلیکیشن پیشفرض روبی، نمای application.html.erb برای هر صفحهای که کنترلر آن از ApplicationController ارثبری میکند بارگذاری خواهد شد. اگر یک کنترلر فرزند ApplicationController اقدام به رندر یک نما بکند، محتوای آن به application.html.erb ارسال میشود. با توجه به این کارکرد، کد HTML آماده که باید روی همه صفحههای اپلیکیشن اعمال شود، به سهولت انجام مییابد.
برای نمونه در وبسایت زیر، نوار فوقانی آبی رنگ در یک فایل نمای پایه قرار دارد که لیآوت متفاوتی برای هر مسیر ایجاد میکند.
سخن پایانی
لزومی نیست که بلوکها دارای منطق پیچیدهای باشد تا بتوانیم از آنها استفاده کنیم. بلوکها به طور معمول برای تجرید منطق مشترکی که باید روی چارچوبهای مختلف اعمال شود، مورد استفاده قرار میگیرند. اگر بلوکها را به طرز فکرشدهای بنویسیم، کد اصل DRY را بهتر رعایت میکند و خوانایی کد افزایش مییابد.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی
- راهنمای سریع متدهای آرایه در Ruby — از صفر تا صد
- مجموعه آموزشهای دروس علوم و مهندسی کامپیوتر
- ساخت اپلیکیشن اینستاگرام با Ruby on Rails (بخش اول) — از صفر تا صد
- ساختمان های داده در روبی (Ruby) — درخت های دودویی
==