আপনি যদি কখনো রিফাইনমেন্ট ব্যবহার না করে থাকেন, তবে আপনি একটি সারপ্রাইজের জন্য প্রস্তুত থাকুন। আপনি শুনে থাকতে পারেন যে রিফাইনমেন্ট মংকি প্যাচিং রিপ্লেস করার জন্য আনা হয়েছে। তাই আপনি আশা করতে পারেন যে আপনি ActiveSupport-এর hours মেথডের মতো কিছু ইমপ্লিমেন্ট করতে পারবেন:
module TimeExtension
refine Fixnum do
def hours
self * 60
end
end
end
class MyFramework
using TimeExtension
end
class MyApp < MyFramework
def index
1.hours
end
end
MyApp.new.index # undefined method `hours' for 1:Fixnum (NoMethodError)
আপনি যদি উপরের কোডটি রান করেন, তবে আপনি দেখবেন এটি কাজ করে না। তাহলে কী ঘটল?
অনেক অন্য চমৎকার আইডিয়ার মত, রিফাইনমেন্টের আসল কনসেপ্টকে রিয়ালিটির সাথে কাজ করার জন্য টুইক করতে হয়েছিল।
উপরের কোডে যা আশ্চর্য আচরণ দেখেছি সেটি এই টুইকগুলির একটি കാരণ। বিশেষ করে, वो নিয়ম যা বলে রিফাইনমেন্ট লেক্সিক্যালি স্কোপড।
লেক্সিক্যাল স্কোপিং কী?
যখন আমরা কিছুকে লেক্সিক্যাল বলি, তার মানে সেটি টেক্সটের সাথে জড়িত—স্ক্রিনে কোডটি, না যে কোডটি কী মানে।
যদি দুটি লাইন লেক্সিক্যালি স্কোপড হয়, তার সরল অর্থ হচ্ছে সেগুলো একই কোড ব্লকের মধ্যে অবস্থিত—কোড ব্লকটি কী ইভ্যালুয়েট করে সেটি নির্বিশেষে।
এটি কথা বলার চেয়ে উদাহরণ দেখা সহজ:
class B
# x এবং y একই লেক্সিক্যাল স্কোপ শেয়ার করে
x = 1
y = 1
end
class B
# z-এর লেক্সিক্যাল স্কোপ x এবং y থেকে ভিন্ন, যদিও একই ক্লাসে।
z = 3
end
রিফাইনমেন্ট লেক্সিক্যালি স্কোপড
যখন আমরা using কিওয়ার্ড দিয়ে একটি রিফাইনমেন্ট অ্যাপ্লাই করি, রিফাইনমেন্টটি শুধু লেক্সিক্যাল স্কোপের ভেতরে ভিজিবল।
এখানে একটি উদাহরণ যা আমার মানে দেখাচ্ছে:
module TimeExtension
refine Fixnum do
def hours
self * 60
end
end
end
class MyApp
using TimeExtension
def index
1.hours
end
end
class MyApp
def show
2.hours
end
end
MyApp.new.show # undefined method `hour' for 1:Fixnum (NoMethodError)
যদিও index এবং show উভয় মেথড একই ক্লাসের অংশ, শুধু index মেথডটি রিফাইনমেন্ট এক্সেস করতে পারে, কারণ শুধু সেটি using স্টেটমেন্টের সাথে লেক্সিক্যাল স্কোপ শেয়ার করে।
এটি কিছুটা অদ্ভুত লাগতে পারে, কারণ রুবির প্রায় সব কিছু ডাইনামিক্যালি স্কোপড। আপনি যখন একটি ক্লাসে মেথড যোগ করেন, ক্লাস ডেফিনিশন থেকে বের হওয়ার পরও মেথডটি সেখানে থাকে। কিন্তু রিফাইনমেন্ট সেভাবে কাজ করে না।
এটির সবকিছুো результат আছে যা প্রথমে স্পষ্ট নাও হতে পারে।
আপনি রিফাইনমেন্ট মেথড ডাইনামিক্যালি ইনভোক করতে পারবেন না
কারণ send মেথডটি আপনার using স্টেটমেন্ট ধারণকারী কোড ব্লকের ভেতরে ডেফাইন করা নয়, সেটি রিফাইনমেন্ট দেখতে পায় না।
তাই এটি কাজ করে না:
class MyApp
using TimeExtension
def index
1.send(:hours)
end
end
আপনি রিফাইনমেন্ট মেথডের অস্তিত্ব কোয়েরি করতে পারবেন না
respond_to? মেথডটিও একই কোড ব্লকের ভেতরে নয়। তাই সেটিও একই কারণে কাজ করে না যেটি send মেথডে হয়।
class MyApp
using TimeExtension
def index
1.respond_to?(:hours)
end
end
উপসংহার
আশা করি এটি কিছু বিভ্রান্তি দূর করতে পারলো যা লোকেরা রিফাইনমেন্ট নিয়ে থাকে। সেগুলো নিশ্চিতভাবে রুবির একটি পোটেনশিয়ালি উপকারী ফিচার, কিন্তু আপনি যদি কখনো ব্যবহার না করে থাকেন তবে সেগুলো কিছুটা ট্রিকি হতে পারে।