আপনি হয়তো রুবি মেটাপ্রোগ্রামিং নিয়ে পড়েছেন।
কিন্তু…
এটি কিছুটা কনফিউজিং হতে পারে যদি আপনার হাতে কয়েকটি স্পেসিফিক উদাহরণ না থাকে।
ইসিলিয়ে এই আর্টিকেলে:
আমরা কিছু জনপ্রিয় ওপেন-সোর্স প্রজেক্ট দেখব যেগুলো রুবি মেটাপ্রোগ্রামিং ব্যবহার করে।
প্রজেক্টগুলো হল:
- রেইলস (Rails)
- সিনাত্রা (Sinatra)
- পেপারক্লিপ জেম (Paperclip gem)
এগুলোর সবই কোনো না কোনো ফর্মে মেটাপ্রোগ্রামিং ব্যবহার করে।
চলুন কোডগুলো দেখি এবং বের করি সত্যিকারের কী করছে!
রেইলস উদাহরণ
রেইলস মেটাপ্রোগ্রামিং এর ব্যাপক ব্যবহার করে, তাই এটি শুরু করার জন্য ভালো জায়গা।
উদাহরণস্বরূপ:
আপনি যখন আপনার রেইলস অ্যাপে বর্তমান এনভায়রনমেন্ট চেক করতে চান, তখন আপনি কিছু এইভাবে করুন।
Rails.env.production?
কিন্তু env কী? এবং এটি কীভাবে কাজ করে?
উত্তরগুলো আছে StringInquirer ক্লাসে, যা String-এর সাবক্লাস। এই ক্লাস method_missing ব্যবহার করে যাতে আপনি env.production? কল করতে পারেন বরং env == production লিখতে হয়।
কোডটি এমন দেখায়:
def method_missing(method_name, *arguments) if method_name[-1] == '?' self == method_name[0..-2] else super end end
এটি বলে:
“যদি মেথডের নাম কোয়েশ্চন মার্ক দিয়ে শেষ হয় তবে কম্পেরিজন করো, অন্যথায় উপরে আনসেস্টর চেইনে যাও।”
মূল কোডটি এখানে পাওয়া যাবে।
সিনাত্রা ডেলিগেশন
আপনি যদি সিনাত্রা ব্যবহার করে থাকেন তবে জানতে পারেন রুট ডিফাইন করার দুটি পদ্ধতি আছে:
get/postমেথডগুলো সরাসরি ব্যবহার করা, যেকোনো ক্লাসের বাইরে।Sinatra::Applicationথেকে ইনহেরিট করে একটি ক্লাস ডিফাইন করা।
সিনাত্রা DSL (ডোমেন-স্পেসিফিক ল্যাঙ্গুয়েজ) মেথডগুলো Sinatra::Application-এর ভেতরে ডিফাইন করা আছে, তাহলে আপনি এই ক্লাসের বাইরে থেকে এগুলো কীভাবে ব্যবহার করছেন?
এখানে দুটি জিনিস হচ্ছে:
- মেটাপ্রোগ্রামিং
- মডিউল এক্সটেনশন
সিনাত্রা base.rb ফাইলে Sinatra::Delegator নামে একটি মডিউল ডিফাইন করে যা একটি target-এ মেথড কল ডেলিগেট করতে ব্যবহৃত হয়।
টার্গেট ডিফল্টভাবে Sinatra::Application-এ সেট করা থাকে।
Sinatra::Delegator-এ ডিফাইন করা delegate ক্লাস মেথডের একটি সিম্পলিফাইড ভার্শন:
def self.delegate(*methods) methods.each do |method_name| define_method(method_name) do |*args, &block| Delegator.target.send(method_name, *args, &block) end end end delegate :get, :patch, :put, :post, :delete
এই কোডটি একটি সেট মেথড তৈরি করে ( define_method ব্যবহার করে) যা মেথড কলগুলো Sinatra::Application ( Delegator.target-এর ডিফল্ট ভ্যালু) এ ফরওয়ার্ড করবে।
তারপর main অবজেক্টকে Sinatra::Delegator-এ ডিফাইন করা মেথডগুলোর সাথে এক্সটেন্ড করা হয়, যা সিনাত্রা DSL কে Sinatra::Application ক্লাসের বাইরে উপলব্ধ করে দেয়।
দ্রষ্টব্য: রুবিতে মেথড ডেলিগেশনের জন্য দুটি বিল্ট-ইন ক্লাস রয়েছে, প্রয়োজন হলে ব্যবহার করতে পারেন: Delegator এবং Forwardable।
পেপারক্লিপ জেম
পেপারক্লিপ হল একটি জেম যা আপনার অ্যাপ্লিকেশনকে ফাইল আপলোড হ্যান্ডল করতে দেয়। ফাইলগুলো ActiveRecord মডেলের সাথে asoshiate করা থাকে।
আপনি একটি মডেলে আট্যাচড ফাইল ডিফাইন করতে পারেন has_attached_file মেথড ব্যবহার করে।
এভাবে:
class User has_attached_file :avatar, :styles => { :normal => "100x100#" } end
এই মেথডটি paperclip.rb-এ ডিফাইন করা আছে এবং এটি মেটাপ্রোগ্রামিং ব্যবহার করে মডেলে একটি মেথড ডিফাইন করে।
এই মেথডটি ফাইল আট্যাচমেন্ট এক্সেস করতে ব্যবহার করা হয় (যেটি Paperclip::Attachment ক্লাসের একটি ইনস্ট্যান্স)।
উদাহরণস্বরূপ, আট্যাচড ফাইল যদি :avatar হয়, তবে Paperclip মডেলে একটি avatar মেথড ডিফাইন করবে।
এখানে define_instance_getter মেথডটি দেওয়া হলো, যা এই কাজের জন্য দায়িত্ববহন করে:
# @name => আট্যাচমেন্টের নাম # @klass => वह ActiveRecord মডেল যেখানে এই মেথড ডিফাইন হচ্ছে def define_instance_getter name = @name options = @options @klass.send :define_method, @name do |*args| ivar = "@attachment_#{name}" attachment = instance_variable_get(ivar) if attachment.nil? attachment = Attachment.new(name, self, options) instance_variable_set(ivar, attachment) end end end
এই কোড থেকে আমরা দেখতে পাচ্ছি যে আট্যাচমেন্ট অবজেক্টটি @attachment_#{name} ইনস্ট্যান্স ভেরিয়েবলে সংরক্ষিত হয়।
আমাদের উদাহরণে সেটি হবে @attachment_avatar।
তারপর এটি চেক করে আট্যাচমেন্ট ইতিমধ্যে আছে কিনা, এবং যদি না থাকে তবে একটি নতুন Attachment অবজেক্ট তৈরি করে ইনস্ট্যান্স ভেরিয়েবল সেট করে দেয়।
মূল সোর্স কোড এখানে পাওয়া যাবে।
উপসংহার
আপনি দেখেছেন, মেটাপ্রোগ্রামিং একটি খুব পাওয়ারফুল এবং ফ্লেক্সিবল টেকনিক, কিন্তু আপনি যখন এটির দিকে হাত বড়াবেন তখন সেই কোটেশনটি মনে রাখুন: “মহান ক্ষমতায় মহান দায়িত্ব আসে”।
এই পোস্টটি ভালো লাগলে আমার নিউজলেটার সাবস্ক্রাইব করা ভুলবেন না 🙂