কম্পিউটার টিউটোরিয়াল

রুবিতে অবজেক্ট মার্শালিং মাস্টার করা: একটি প্র্যাক্টিক্যাল গাইড

এই আর্টিকেলে, আমরা অবজেক্ট মার্শালিং-এ ডুব করব। আমরা ব্যাখ্যা করব এটি কী, Marshal মডিউল দেখব, এবং তারপর একটি উদাহরণের মাধ্যমে যাব। তারপর এক ধাপ গভীরে যাব _dump এবং self._load মেথডগুলোর তুলনা করব। চলুন!

অবজেক্ট মার্শালিং কী?

কোড লিখার সময়, আপনি একটি অবজেক্ট সংরক্ষণ করতে চাইতে পারেন এবং অন্য প্রোগ্রামে ট্রান্সমিট করতে বা আপনার পরবর্তী প্রোগ্রাম এক্সিকিউশনে পুনরায় ব্যবহার করতে। অবজেক্ট মার্শালিং ব্যবহার হয় Sidekiq-এ, উদাহরণস্বরূপ; যখন একটি Sidekiq জব একটি রুবি অন রেইলস অ্যাপ্লিকেশনে ইনকিউ করা হয়, তখন এই জবের একটি সিরিয়ালাইজেশন — যা কিছুই নন বরং একটি অবজেক্ট — রেডিসে ইনসার্ট করা হয়। Sidekiq প্রসেসটি তখন এই JSON ডিসিরিয়ালাইজ করে এবং মূল জবটি JSON থেকে রিকনস্টিটিউট করে।

কম্পিউটার প্রোগ্রামিং-এ, এই সিরিয়ালাইজেশন এবং ডিসিরিয়ালাইজেশন প্রক্রিয়াকে সাধারণত অবজেক্ট মার্শালিং বলা হয়। এখন, আসুন দেখি রুবি নেটিভলি কী প্রদান করে অবজেক্ট মার্শালিং হ্যান্ডেল করার জন্য।

The Marshal Module

যেহেতু রুবি একটি ফুলি অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিং ল্যাঙ্গুয়েজ, এটি Marshall মডিউল ব্যবহার করে অবজেক্ট সিরিয়ালাইজ এবং সংরক্ষণ করার একটি পদ্ধতি প্রদান করে এর স্ট্যান্ডার্ড লাইব্রেরিতে। এটি আপনাকে একটি অবজেক্টকে একটি বাইট স্ট্রিমে সিরিয়ালাইজ করতে দেয় যা সংরক্ষণ করা যেতে পারে এবং অন্য রুবি প্রসেসে ডিসিরিয়ালাইজ করা যেতে পারে।

তাহলে, আসুন একটি স্ট্রিং সিরিয়ালাইজ করি এবং সিরিয়ালাইজড অবজেক্টটিকে নিকট থেকে দেখি।

hello_world = 'hello world!' serialized_string = Marshal.dump(hello_world) # => "\x04\bI\"\x11hello world!\x06:\x06ET" serialized_string.class # => String deserialized_hello_world = Marshal.load(serialized_string) # => "hello world!" hello_world.object_id # => 70204420126020 deserialized_hello_world.object_id # => 70204419825700

আমরা তারপর Marshal.dump মডিউল মেথড কল করি আমাদের স্ট্রিং সিরিয়ালাইজ করতে। আমরা রিটার্ন ভ্যালু — যেটিতে আমাদের সিরিয়ালাইজড স্ট্রিং থাকে — serialized_string ভেরিয়েবলে স্টোর করি। এই স্ট্রিং একটি ফাইলে স্টোর করা যেতে পারে এবং ফাইলটি অন্য প্রসেসে মূল অবজেক্টটি রিকনস্টিটিউট করতে পুনরায় ব্যবহার করা যেতে পারে। আমরা তারপর Marshal.load মেথড কল করি বাইট স্ট্রিম থেকে মূল অবজেক্ট রিকনস্টিটিউট করতে।

আমরা দেখতে পাচ্ছি যে এই তাজা রিকনস্টিটিউটেড স্ট্রিং-এর একটি ভিন্ন object_id আছে hello_world স্ট্রিংর চেয়ে, অর্থাৎ এটি একটি ভিন্ন অবজেক্ট, কিন্তু এতে একই ডেটা রয়েছে।

খুব কুল! কিন্তু Marshal মডিউল স্ট্রিংটি কীভাবে রিকনস্ট্রাক্ট করতে পারে? এবং, যদি আমি কন্ট্রোল চাই কোন অ্যাট্রিবিউট সিরিয়ালাইজ এবং ডিসিরিয়ালাইজ হবে সেটা ওপর?

অবজেক্ট মার্শালিং-এর একটি কংক্রিট উদাহরণ

এই প্রশ্নগুলোর উত্তর দিতে, আসুন একটি কাস্টম স্ট্রাক্ট নামক User-এ একটি মার্শালিং স্ট্র্যাটেজি ইমপ্লিমেন্ট করি।

User = Struct.new(:fullname, :age, :roles) user = User.new('Mehdi Farsi', 42, [:admin, :operator])

User স্ট্রাক্ট ৩টি অ্যাট্রিবিউট ডিফাইন করে: fullname, age, এবং roles। এই উদাহরণের জন্য আমাদের একটি বিজনেস রুল আছে যেখানে আমরা শুধু সিরিয়ালাইজ করব যখন নিচের মাপদণ্ড পূরণ হয়:

  • fullname ৬৪ ক্যারেক্টার থেকে কম ধারণ করে
  • roles অ্যারে :admin রোল ধারণ করে না

এটি করতে, আমরা একটি User#marshal_dump মেথড ডিফাইন করতে পারি আমাদের কাস্টম সিরিয়ালাইজেশন স্ট্র্যাটেজি ইমপ্লিমেন্ট করতে। এই মেথডটি কল হবে যখন আমরা Marshal.dump মেথড আহ্বান করব User স্ট্রাক্টের একটি ইনস্ট্যান্স প্যারামিটার হিসেবে। আসুন এই মেথড ডিফাইন করি:

User = Struct.new(:age, :fullname, :roles) do def marshal_dump {}.tap do |result| result[:age] = age result[:fullname] = fullname if fullname.size <= 64 result[:roles] = roles unless roles.include? :admin end end end user = User.new(42, 'Mehdi Farsi', [:admin, :operator]) user_dump = Marshal.dump(user) # 'in User#marshal_dump' user_dump # => "\x04\bU:\tUser{\a:\bageI\"\x10Mehdi Farsi\x06:\x06ET:\rfullnamei/" 

উপরোক্ত উদাহরণে, আমরা দেখতে পাচ্ছি যে আমাদের User#marshal_dump মেথড কল হচ্ছে যখন আমরা Marshal.dump(user) আহ্বান করছি। user_dump ভেরিয়েবলে স্ট্রিং থাকে যেটি আমাদের User ইনস্ট্যান্সের সিরিয়ালাইজেশন।

এখন যেহেতু আমাদের ডাম্প আছে, আসুন এটি ডিসিরিয়ালাইজ করি আমাদের ইউজার রিকনস্টিটিউট করতে। এজন্য, আমরা একটি User#marshal_load মেথড ডিফাইন করব যা ডিসিরিয়ালাইজেশন স্ট্র্যাটেজি ইমপ্লিমেন্ট করবে User ডাম্পের। তাহলে এই মেথড ডিফাইন করি।

User = Struct.new(:age, :fullname, :roles) do def marshal_dump {}.tap do |result| result[:age] = age result[:fullname] = fullname if fullname.size <= 64 result[:roles] = roles unless roles.include? :admin end end def marshal_load(serialized_user) self.age = serialized_user[:age] self.fullname = serialized_user[:fullname] self.roles = serialized_user[:roles] || [] end end user = User.new(42, 'Mehdi Farsi', [:admin, :operator]) user_dump = Marshal.dump(user) # 'in User#marshal_dump' user_dump # => "\x04\bU:\tUser{\a:\bagei/:\rfullnameI\"\x10Mehdi Farsi\x06:\x06ET" original_user = Marshal.load(user_dump) # 'in User#marshal_load' original_user # => #<struct User age=42, fullname="Mehdi Farsi", roles=[]>

উপরোক্ত উদাহরণে, আমরা দেখতে পাচ্ছি যে আমাদের User#marshal_load method কল হচ্ছে যখন আমরা Marshal.load(user_dump) আহ্বান করছি। original_user ভেরিয়েবলে একটি স্ট্রাক্ট থাকে যেটি আমাদের ইউজার ইনস্ট্যান্সের একটি রিকনস্টিটিউশন।

নোট করুন যে original_user.roles user.roles অ্যারےর সাথে সিমিলার নন কারণ সিরিয়ালাইজেশনের সময়, user.roles :admin রোল ধারণ করছিল। তাই user.roles সিরিয়ালাইজড হয়নি user_dump ভেরিয়েবলে।

The _dump and self._load Methods

যখন Marshal.dump এবং Marshal.load আহ্বান করা হয়, এই মেথডগুলো অবজেক্টের ওপর marshal_dump এবং marshal_load মেথড কল করে যেগুলো এই মেথডগুলোর প্যারামিটার হিসেবে পাস করা হয়েছে।

কিন্তু, যদি আমি আপনাকে বলি Marshal.dump এবং Marshal.load মেথডগুলো চেষ্টা করে আরও দুটি মেথড কল করার নাম্বর _dump এবং self._load প্যারামিটার হিসেবে পাস করা অবজেক্টের ওপর?

The _dump Method

marshal_dump এবং _dump মেথডগুলোর পার্থক্যগুলো হলো:

  • _dump মেথড ব্যবহার করার সময় আপনাকে লোয়ার লেভেলে সিরিয়ালাইজেশন স্ট্র্যাটেজি হ্যান্ডেল করতে হবে — আপনাকে একটি স্ট্রিং রিটার্ন করতে হবে যেটি সিরিয়ালাইজ করার ডেটা রিপ্রেজেন্ট করে
  • marshal_dump মেথড প্রেসিডেন্স পায় _dump-এর ওপর যদি দুটোই ডিফাইন করা থাকে

নিচের উদাহরণটি দেখুন:

User = Struct.new(:age, :fullname, :roles) do def _dump level [age, fullname].join(':') end end user = User.new(42, 'Mehdi Farsi', [:admin, :operator]) Marshal.dump(user) # => "\x04\bIu:\tUser\x1342:Mehdi Farsi\x06:\x06EF"

User#_dump মেথডে, আমাদের সিরিয়ালাইজেশন অবজেক্ট ইনস্ট্যানশিয়েট এবং রিটার্ন করতে হবে — স্ট্রিং যেটি আপনার সিরিয়ালাইজেশন রিপ্রেজেন্ট করে।

নিচের উদাহরণে, আমরা User#marshal_dump এবং User#_dump মেথড দুটোই ডিফাইন করি এবং একটি স্ট্রিং রিটার্ন করি দেখতে কোন মেথড কল হচ্ছে

User = Struct.new(:age, :fullname, :roles) do def marshal_dump 'in User#marshal_dump' end def _dump level 'in User#_dump' end end user = User.new(42, 'Mehdi Farsi', [:admin, :operator]) user_dump = Marshal.dump(user) # "in User#marshal_dump"

আমরা দেখতে পাচ্ছি যে শুধু User#marshal_dump কল হচ্ছে যদিও দুটোই ডিফাইন করা আছে।

The self._load Method

এখন, আসুন marshal_load এবং _load মেথডগুলো দেখি।

marshal_load এবং _load মেথডগুলোর পার্থক্যগুলো হলো:

  • _load মেথড ব্যবহার করার সময় আপনাকে লোয়ার লেভেলে ডিসিরিয়ালাইজেশন স্ট্র্যাটেজি হ্যান্ডেল করতে হবে — আপনি মূল অবজেক্ট ইনস্ট্যানশিয়েট করার জন্য দায়িত্বপূর্ণ
  • marshal_load মেথড একটি ডিসিরিয়ালাইজড অবজেক্ট আর্গুমেন্ট হিসেবে নেয় যখন self._load মেথড সিরিয়ালাইজড স্ট্রিং আর্গুমেন্ট হিসেবে নেয়
  • marshal_load মেথড একটি ইনস্ট্যান্স মেথড যখন self._load একটি ক্লাস মেথড

নিচের উদাহরণটি দেখুন:

User = Struct.new(:age, :fullname, :roles) do def _dump level [age, fullname].join(':') end def self._load serialized_user user_info = serialized_user.split(':') new(*user_info, Array.new) end end user = User.new(42, 'Mehdi Farsi', [:admin, :operator]) user_dump = Marshal.dump(user) user_dump # => "\x04\bIu:\tUser\x1342:Mehdi Farsi\x06:\x06EF" original_user = Marshal.load(user_dump) original_user # => #<struct User age="Mehdi Farsi", fullname=42, roles=[]>

User._load মেথডে:

  • আমরা স্ট্রিং ডিসিরিয়ালাইজ করি যেটি User#_dump মেথড রিটার্ন করেছিল
  • আমরা একটি নতুন User ইনস্ট্যানশিয়েট করি ডিসিরিয়ালাইজড ইনফরমেশন পাস করে

আমরা দেখতে পাচ্ছি যে আমরা দায়িত্বপূর্ণ রিকনস্টিটিউট করা মূল অবজেক্ট alok এবং ইনস্ট্যানশিয়েট করার জন্য।

সুতরাং Marshal.load coupled to marshal_load রিকনস্টিটিউট করা মূল অবজেক্ট ইনস্ট্যানশিয়েট করার দায়িত্ব নেয়। তারপর এটি marshal_load মেথড কল করে সিরিয়ালাইজড অবজেক্ট আর্গুমেন্ট হিসেবে পাস করে নতুন ইনস্ট্যানশিয়েট করা অবজেক্টের ওপর।

বিপরীতে, Marshal.load coupled to _load ক্লাস মেথড self._load-কে দায়িত্ব দেয়:

  • _dump মেথড রিটার্ন করা ডেটা ডিসিরিয়ালাইজ করা
  • রিকনস্টিটিউট করা মূল অবজেক্ট ইনস্ট্যানশিয়েট করা

উপসংহার

আপনার প্রয়োজনের উপর নির্ভর করে, আপনি হايير বা লোয়ার সিরিয়ালাইজেশন/ডিসিরিয়ালাইজেশন স্ট্র্যাটেজি ইমপ্লিমেন্ট করতে সিদ্ধান্ত নিতে পারেন। এজন্য, আপনি Marshal মডিউল ব্যবহার করতে পারেন উপযুক্ত Marshal হুক মেথডগুলোর সাথে।

Voilà!

  1. রুবিতে বিটওয়াইজ অপারেশন মাস্টার করুন: টিপস অ্যান্ড ট্রিকস

  2. রুবিতে ল্যাম্বডা মাস্টার করুন: বেসিক থেকে অ্যাডভান্সড টেকনিক

  3. রুবি ২.৬-এ ৯টি গুরুত্বপূর্ণ উন্নতির অন্বেষণ

  4. রুবির Freeze মেথড বোঝা: অবজেক্ট মিউটেবিলিটি ব্যাখ্যা