মডিউল (এবং ক্লাস) নেস্ট করার জন্য বানানো হয়েছে। ActiveRecord::RecordNotFound এর মত কোড ফ্র্যাগমেন্ট এতটাই সাধারণ যে আমরা তাদের সম্পর্কে দ্বিবার চিন্তা করি না। কিন্তু রুবির নেস্টিং ইমপ্লিমেন্টেশন - এবং রেলসের অটোলোড সিস্টেম - এর মধ্যে কিছু ট্র্যাপ লুকানো আছে যা আপনার কোডকে আশ్చর্যjande странь এবং চমৎকারভাবে ব্যর্থ করতে পারে। এই পোস্টে, আমরা এই ট্র্যাপের উৎপত্তি এবং কীভাবে আপনি এগুলো এড়াতে পারেন তা আলোচনা করব।
কনস্ট্যান্ট কী?
এই পোস্ট মডিউল সম্পর্কে, কিন্তু সেগুলো বুঝতে হলে কনস্ট্যান্ট বুঝতে হবে। অধিকাংশ ভাষায়, কনস্ট্যান্ট শুধু ছোট ডেটা সংরক্ষণের জন্য ব্যবহৃত হয়, নিচের উদাহরণের মত:
# এগুলো সিম্পল কনস্ট্যান্ট
MAX_RETRIES = 5
DEFAULT_LANGUAGE = "en"
কিন্তু রুবিতে, ক্লাস এবং মডিউলও কনস্ট্যান্ট। আমি এটি প্রদর্শন করার জন্য একটি ছোট উদাহরণ লিখেছি। নিচের মডিউলে তিনটি কনস্ট্যান্ট আছে: একটি নাম্বার, একটি ক্লাস এবং একটি নেস্টেড মডিউল। যখন আপনি একটি নেস্টেড ক্লাস বা মডিউল অ্যাক্সেস করেন, রুবি এটি খুঁজে বের করতে उन्हीं নিয়মগুলো ব্যবহার করে যা সিম্পল নмериক কনস্ট্যান্টের সাথে ব্যবহার করত।
module MyModule
MY_FAVORITE_NUMBER = 7
# ক্লাসগুলো কনস্ট্যান্ট
class MyClass
end
# মডিউলও কনস্ট্যান্ট
module MyEmbeddedModule
end
end
puts MyModule.constants.inspect
# => [:MY_FAVORITE_NUMBER, :MyClass, :MyEmbeddedModule]
প্রায়শই, মডিউলদের তাদের পেরেন্টে ডিফাইন করা কনস্ট্যান্টগুলোর অ্যাক্সেস থাকে। এটাই কারণ আপনি নিচের কোড লিখতে পারেন:
module X
MARCO = "polo"
module Y
def self.n
puts MARCO
end
end
end
X::Y.n() # => "polo"
কিন্তু আপনি ভুল করছেন যদি মনে করেন যে এই পেরেন্ট/চাইল্ড সম্পর্কই Y-কে X-এর কনস্ট্যান্ট MARCO অ্যাক্সেস করতে দেয়।
একটি সাধারণ সমস্যা
যদি আমরা উপরের কোডটি কিছুটা ভিন্নভাবে রিরাইট করি, তবে কিছু আশ্চর্য ঘটে। Y আর X::MARCO অ্যাক্সেস করতে পারে না। এখানে কী হচ্ছে?
module A
MARCO = "polo"
end
module A::B
def self.n
puts MARCO # => uninitialized constant A::B::MARCO (NameError)
end
end
A::B.n()
প্রকাশ পেলো যে, পেরেন্টের কনস্ট্যান্ট চাইল্ড দ্বারা "ইনহেরিট" হওয়া পেরেন্ট/চাইল্ড সম্পর্কের কারণে নয়। এটি লেক্সিক্যাল। এর মানে হলো এটি আপনার কোডের স্ট্রাকচারের ওপর ভিত্তি করে, আপনার কোড যা অবজেক্ট তৈরি করছে তার স্ট্রাকচারের ওপর নয়।
নেস্টিং পরীক্ষা
যদি আপনি রুবি কীভাবে নেস্টেড কনস্ট্যান্ট সার্চ করে তার গভীর বোঝাপড়া পেতে চান, তবে Module.nesting ফাংশন দেখতে পারেন।
এই ফাংশন একটি অ্যারে রিটার্ন করে যা একটি প্রদত্ত স্কোপে কনস্ট্যান্টের "সার্চ পাথ" গঠন করে। চলুন আমাদের আগের উদাহরণগুলোতে নেস্টিং পরীক্ষা করি।
আমাদের প্রথম উদাহরণে, আমরা দেখি নেস্টিং হলো [A::B, A]। এর মানে যদি আমরা MARCO কনস্ট্যান্ট ব্যবহার করি, তবে রুবি প্রথমে A::B-এ খুঁজবে, তারপর A-তে।
module A
MARCO = "polo"
module B
def self.n
puts Module.nesting.inspect # => [A::B, A]
puts MARCO # => "polo"
end
end
end
দ্বিতীয় উদাহরণে, আমরা দেখি নেস্টিং শুধু A::B-কে ইনক্লুড করে, A-কে নয়। যদিও B A-র "চাইল্ড", আমি কোডটি যেভাবে লিখেছি সেটি সেগুলোকে নেস্টেড দেখায় না, তাই এই উদ্দেশ্যে সেগুলো নেস্টেড নাও হতে পারে।
module A
MARCO = "polo"
end
module A::B
def self.n
puts Module.nesting.inspect # => [A::B]
puts MARCO # => uninitialized constant A::B::MARCO (NameError)
end
end
রেলস অটোলোড জটিলতা
আপনি কি লক্ষ্য করেছেন যে রেলস ব্যবহার করার সময় আপনাকে ফাইল ইনক্লুড করতে হয় না? আপনি যদি একটি মডেল ব্যবহার করতে চান, তবে শুধু তা ব্যবহার করুন।
এটি সম্ভব কারণ রেলস একটি অটোলোড সিস্টেম ইমপ্লিমেন্ট করে। এটি Module.const_missing ব্যবহার করে ডিটেক্ট করে যখন আপনি একটি কনস্ট্যান্ট রেফারেন্স করার চেষ্টা করেন যা লোড نشده। তারপর এটি সেই ফাইলগুলো লোড করে যেগুলোতে কনস্ট্যান্ট থাকা উচিত বলে মনে করে। এটি অধিকাংশ সময় কাজ করে, কিন্তু একটি ক্যাচ আছে।
রελস অনুমান করে যে একটি মডিউল সবচেয়ে বড় সম্ভাব্য নেস্টিং নিয়ে থাকবে। এটি অনুমান করে যে মডিউল A::B::C-র নেস্টিং হবে [A::B::C, A::B, A]। যদি না হয়, তবে আপনি অপ্রত্যাশিত আচরণ পাবেন।
নিচের কোডে, মডিউল B-কে A::MARCO অ্যাক্সেস করতে পারা উচিত নয়। সাধারণ রুবিতে, এটি অ্যাক্সেস করতে পারত না কারণ এর নেস্টিং হলো [A::B]। তাই আপনার এক্সেপশন পেতে হতো। কিন্তু রেলসের অটোলোড এক্সেপশন থ্রো করে না। বদলে, এটি A::MARCO রিটার্ন করে।
# a.rb
module A
MARCO = "polo"
end
# a/b.rb
module A::B
def self.n
puts MARCO # => "polo"
end
end
# some_controller.rb
A::B.n()
উপসংহার?
এই সব বিষয় চিন্তা করার জন্য অনেক কিছু। আমি সেখানে চিন্তা এড়াতে চাই যেখানে সম্ভব, তাই আমি মডিউল A::B সিনট্যাক্স এড়াতে চেষ্টা করি। আমি এমন কোনো কেস ভাবতে পারি না যেখানে আমি ইচ্ছাকৃতভাবে মডিউল নেস্টিং ম্যানিপুলেট করতে চাইব। আপনি যদি কেনো জানেন, আমাকে জানাতে ভুলবেন না!