আগের রুবি ম্যাজিকে, আমরা বুঝতে পেরেছিলাম কিভাবে ক্লাসে মডিউলগুলিকে .new
ওভাররাইট করে নির্ভরযোগ্যভাবে ইনজেক্ট করা যায় পদ্ধতি, আমাদের অতিরিক্ত আচরণের সাথে পদ্ধতিগুলি মোড়ানোর অনুমতি দেয়৷
এই সময়, আমরা সেই আচরণটিকে নিজস্ব একটি মডিউলে বের করে এটিকে আরও এক ধাপ এগিয়ে নিয়ে যাচ্ছি যাতে আমরা এটিকে পুনরায় ব্যবহার করতে পারি। আমরা একটি Wrappable
তৈরি করব মডিউল যা আমাদের জন্য ক্লাস এক্সটেনশন পরিচালনা করে এবং আমরা ক্লাস-লেভেল ইনস্ট্যান্স ভেরিয়েবল সম্পর্কে সমস্ত কিছু শিখব। আসুন সরাসরি ভিতরে ডুব দিই!
প্রবর্তন করা হচ্ছে Wrappable
মডিউল
বস্তুগুলিকে মডিউল দিয়ে মোড়ানোর জন্য যখন সেগুলি শুরু করা হয়, তখন আমাদের ক্লাসকে জানাতে হবে যে কোন মোড়কের মডেলগুলি ব্যবহার করতে হবে। চলুন শুরু করা যাক একটি সহজ Wrappable
তৈরি করে মডিউল যা একটি wrap
প্রদান করে পদ্ধতি যা প্রদত্ত মডিউলটিকে একটি ক্লাস অ্যাট্রিবিউট হিসাবে সংজ্ঞায়িত অ্যারেতে পুশ করে। উপরন্তু, আমরা new
পুনরায় সংজ্ঞায়িত করি আগের পোস্টে আলোচনা করা পদ্ধতি।
module Wrappable
@@wrappers = []
def wrap(mod)
@@wrappers << mod
end
def new(*arguments, &block)
instance = allocate
@@wrappers.each { |mod| instance.singleton_class.include(mod) }
instance.send(:initialize, *arguments, &block)
instance
end
end
একটি ক্লাসে নতুন আচরণ যোগ করতে, আমরা extend
ব্যবহার করি . extend
পদ্ধতি ক্লাসে প্রদত্ত মডিউল যোগ করে। পদ্ধতিগুলি তখন শ্রেণি পদ্ধতিতে পরিণত হয়। এই ক্লাসের দৃষ্টান্তগুলি মোড়ানোর জন্য একটি মডিউল যোগ করতে, আমরা এখন wrap
কল করতে পারি পদ্ধতি।
module Logging
def make_noise
puts "Started making noise"
super
puts "Finished making noise"
end
end
class Bird
extend Wrappable
wrap Logging
def make_noise
puts "Chirp, chirp!"
end
end
চলুন Bird
-এর একটি নতুন উদাহরণ তৈরি করে এটি চেষ্টা করে দেখি এবং make_noise
কল করছে পদ্ধতি।
bird = Bird.new
bird.make_noise
# Started making noise
# Chirp, chirp!
# Finished making noise
দারুণ! এটা প্রত্যাশিত হিসাবে কাজ করে. যাইহোক, যখন আমরা Wrappable
দিয়ে দ্বিতীয় শ্রেণী প্রসারিত করি তখন জিনিসগুলি কিছুটা অদ্ভুত আচরণ করতে শুরু করে মডিউল।
module Powered
def make_noise
puts "Powering up"
super
puts "Shutting down"
end
end
class Machine
extend Wrappable
wrap Powered
def make_noise
puts "Buzzzzzz"
end
end
machine = Machine.new
machine.make_noise
# Powering up
# Started making noise
# Buzzzzzz
# Finished making noise
# Shutting down
bird = Bird.new
bird.make_noise
# Powering up
# Started making noise
# Chirp, chirp!
# Finished making noise
# Shutting down
যদিও Machine
Logging
দিয়ে মোড়ানো হয়নি মডিউল, এটি এখনও লগিং তথ্য আউটপুট করে। কি খারাপ - এমনকি পাখিটি এখন উপরে এবং নিচের দিকে শক্তি দিচ্ছে। এটা ঠিক হতে পারে না, তাই না?
এই সমস্যার মূল যেভাবে আমরা মডিউলগুলি সংরক্ষণ করছি তার মধ্যে রয়েছে। ক্লাস ভেরিয়েবল @@wrappables
Wrappable
-এ সংজ্ঞায়িত করা হয়েছে মডিউল এবং ব্যবহার করা হয় যখনই আমরা একটি নতুন মডিউল যোগ করি, wrap
ক্লাস নির্বিশেষে ব্যবহার করা হয়।
Wrappable
-এ সংজ্ঞায়িত ক্লাস ভেরিয়েবলের দিকে তাকালে এটি আরও স্পষ্ট হয় মডিউল এবং Bird
এবং Machine
ক্লাস যখন Wrappable
একটি ক্লাস পদ্ধতি সংজ্ঞায়িত করা আছে, দুটি শ্রেণী নেই।
Wrappable.class_variables # => [:@@wrappers]
Bird.class_variables # => []
Machine.class_variables # => []
এটি ঠিক করার জন্য, আমাদের বাস্তবায়ন পরিবর্তন করতে হবে যাতে এটি ইনস্ট্যান্স ভেরিয়েবল ব্যবহার করে। যাইহোক, এগুলি Bird
এর দৃষ্টান্তে ভেরিয়েবল নয় অথবা Machine
, কিন্তু ইনস্ট্যান্স ভেরিয়েবল ক্লাসে নিজেরাই।
রুবিতে, ক্লাসগুলি কেবল বস্তু
এটি অবশ্যই প্রথমে কিছুটা মন খারাপ করে, তবে এখনও বোঝার জন্য একটি খুব গুরুত্বপূর্ণ ধারণা। ক্লাস হল Class
এর উদাহরণ এবং class Bird; end
Bird = Class.new
লেখার সমতুল্য . জিনিসগুলিকে আরও বিভ্রান্তিকর করতে Class
Module
থেকে উত্তরাধিকারসূত্রে প্রাপ্ত যা Object
থেকে উত্তরাধিকারসূত্রে পাওয়া যায় . ফলস্বরূপ, ক্লাস এবং মডিউলগুলির অন্য যে কোনও অবজেক্টের মতো একই পদ্ধতি রয়েছে। বেশিরভাগ পদ্ধতিই আমরা ক্লাসে ব্যবহার করি (যেমন attr_accessor
ম্যাক্রো) আসলে Module
এর উদাহরণ পদ্ধতি .
ক্লাসে ইনস্ট্যান্স ভেরিয়েবল ব্যবহার করা
চলুন Wrappable
পরিবর্তন করি উদাহরণ ভেরিয়েবল ব্যবহার করার জন্য বাস্তবায়ন। জিনিসগুলিকে কিছুটা পরিষ্কার রাখতে, আমরা একটি wrappers
প্রবর্তন করি পদ্ধতি যা হয় অ্যারে সেট আপ করে বা বিদ্যমান একটি রিটার্ন করে যখন ইনস্ট্যান্স ভেরিয়েবল ইতিমধ্যেই বিদ্যমান থাকে। এছাড়াও আমরা wrap
পরিবর্তন করি এবং new
পদ্ধতি যাতে তারা সেই নতুন পদ্ধতি ব্যবহার করে।
module Wrappable
def wrap(mod)
wrappers << mod
end
def wrappers
@wrappers ||= []
end
def new(*arguments, &block)
instance = allocate
wrappers.each { |mod| instance.singleton_class.include(mod) }
instance.send(:initialize, *arguments, &block)
instance
end
end
যখন আমরা মডিউলে এবং দুটি ক্লাসে ইনস্ট্যান্স ভেরিয়েবল পরীক্ষা করি, তখন আমরা দেখতে পাব যে উভয়ই Bird
এবং Machine
এখন তাদের নিজস্ব র্যাপিং মডিউলের সংগ্রহ বজায় রাখুন।
Wrappable.instance_variables #=> []
Bird.instance_variables #=> [:@wrappers]
Machine.instance_variables #=> [:@wrappers]
আশ্চর্যের বিষয় নয়, এটি আমরা আগে যে সমস্যাটি পর্যবেক্ষণ করেছি তাও সমাধান করে - এখন, উভয় শ্রেণীই তাদের নিজস্ব মডিউল দিয়ে মোড়ানো।
bird = Bird.new
bird.make_noise
# Started making noise
# Chirp, chirp!
# Finished making noise
machine = Machine.new
machine.make_noise
# Powering up
# Buzzzzzz
# Shutting down
সমর্থক উত্তরাধিকার
উত্তরাধিকার প্রবর্তিত না হওয়া পর্যন্ত এই সব মহান কাজ করে. আমরা আশা করব যে ক্লাসগুলি সুপারক্লাস থেকে র্যাপিং মডিউলগুলি উত্তরাধিকার সূত্রে পাবে। চলুন পরীক্ষা করে দেখা যাক তা হয় কিনা।
module Flying
def make_noise
super
puts "Is flying away"
end
end
class Pigeon < Bird
wrap Flying
def make_noise
puts "Coo!"
end
end
pigeon = Pigeon.new
pigeon.make_noise
# Coo!
# Is flying away
আপনি দেখতে পাচ্ছেন, এটি প্রত্যাশিতভাবে কাজ করে না, কারণ Pigeon
র্যাপিং মডিউলের নিজস্ব সংগ্রহও বজায় রাখছে। যদিও এটা বোঝা যায় যে Pigeon
-এর জন্য সংজ্ঞায়িত মোড়ক মডিউল Bird
-এ সংজ্ঞায়িত করা হয় না , আমরা যা চাই তা ঠিক নয়। আসুন সমগ্র উত্তরাধিকার শৃঙ্খল থেকে সমস্ত মোড়ক পাওয়ার একটি উপায় বের করি।
আমাদের জন্য ভাগ্যবান, রুবি Module#ancestors
প্রদান করে একটি ক্লাস (বা মডিউল) উত্তরাধিকার সূত্রে প্রাপ্ত সমস্ত ক্লাস এবং মডিউল তালিকাভুক্ত করার পদ্ধতি।
Pigeon.ancestors # => [Pigeon, Bird, Object, Kernel, BasicObject]
একটি grep
যোগ করে কল করুন, আমরা সেইগুলিকে বেছে নিতে পারি যেগুলি আসলে Wrappable
দিয়ে প্রসারিত . যেহেতু আমরা প্রথমে চেইনের উপরে থেকে র্যাপার দিয়ে দৃষ্টান্তগুলিকে মোড়ানো করতে চাই, আমরা .reverse
কল করি অর্ডার ফ্লিপ করতে।
Pigeon.ancestors.grep(Wrappable).reverse # => [Bird, Pigeon]
রুবির #===
পদ্ধতি
রুবির কিছু জাদু #===
এ নেমে আসে (বা কেস সমতা ) পদ্ধতি। ডিফল্টরূপে, এটি ঠিক #==
এর মত আচরণ করে (বা সমতা ) পদ্ধতি। যাইহোক, বেশ কিছু ক্লাস #===
ওভাররাইড করে case
-এ ভিন্ন আচরণ প্রদানের পদ্ধতি বিবৃতি এইভাবে আপনি রেগুলার এক্সপ্রেশন ব্যবহার করতে পারেন (#===
#match?
এর সমতুল্য ), অথবা ক্লাস (#===
#kind_of?
এর সমতুল্য ) সেই বিবৃতিতে। Enumerable#grep
এর মত পদ্ধতি , Enumerable#all?
, অথবা Enumerable#any?
এছাড়াও কেস সমতা পদ্ধতির উপর নির্ভর করে।
এখন আমরা flat_map(&:wrappers)
কল করতে পারি একটি একক অ্যারে হিসাবে উত্তরাধিকার শৃঙ্খলে সংজ্ঞায়িত সমস্ত মোড়কের একটি তালিকা পেতে৷
Pigeon.ancestors.grep(Wrappable).reverse.flat_map(&:wrappers) # => [Logging]
যা বাকি আছে তা হল একটি inherited_wrappers
-এ প্যাক করা মডিউল এবং নতুন পদ্ধতিটিকে সামান্য পরিবর্তন করা যাতে এটি wrappers
এর পরিবর্তে এটি ব্যবহার করে পদ্ধতি।
module Wrappable
def inherited_wrappers
ancestors
.grep(Wrappable)
.reverse
.flat_map(&:wrappers)
end
def new(*arguments, &block)
instance = allocate
inherited_wrappers.each { |mod|instance.singleton_class.include(mod) }
instance.send(:initialize, *arguments, &block)
instance
end
end
একটি চূড়ান্ত পরীক্ষা রান নিশ্চিত করে যে সবকিছু এখন প্রত্যাশিত হিসাবে কাজ করছে। র্যাপিং মডিউলগুলি শুধুমাত্র ক্লাসে প্রয়োগ করা হয় (এবং এর সাবক্লাসগুলিতে) তারা প্রয়োগ করা হয়৷
bird = Bird.new
bird.make_noise
# Started making noise
# Chirp, chirp!
# Finished making noise
machine = Machine.new
machine.make_noise
# Powering up
# Buzzzzz
# Shutting down
pigeon = Pigeon.new
pigeon.make_noise
# Started making noise
# Coo!
# Finished making noise
# Is flying away
এটা একটা মোড়ানো!
স্বীকার্য, এই কোলাহলপূর্ণ পাখিগুলি একটি তাত্ত্বিক উদাহরণ (টুইট, টুইট)। কিন্তু উত্তরাধিকারসূত্রে পাওয়া ক্লাস ইনস্ট্যান্স ভেরিয়েবলগুলি ক্লাসগুলি কীভাবে কাজ করে তা বোঝার জন্য কেবল দুর্দান্ত নয়। তারা একটি দুর্দান্ত উদাহরণ যে ক্লাসগুলি কেবল রুবিতে অবজেক্ট।
এবং আমরা স্বীকার করব যে উত্তরাধিকারসূত্রে পাওয়া ক্লাস ইনস্ট্যান্স ভেরিয়েবলগুলি বাস্তব জীবনেও বেশ কার্যকর হতে পারে। উদাহরণস্বরূপ, একটি মডেলের বৈশিষ্ট্য এবং সম্পর্কগুলিকে পরবর্তীতে আত্মদর্শন করার ক্ষমতার সাথে সংজ্ঞায়িত করার বিষয়ে চিন্তা করুন। আমাদের জন্য যাদু হল এটির সাথে খেলা করা এবং জিনিসগুলি কীভাবে কাজ করে তা আরও ভালভাবে বোঝা। এবং সমাধানের পরবর্তী স্তরের জন্য আপনার মন খুলুন। 🧙🏼♀️
বরাবরের মতো, আমরা এই বা অনুরূপ নিদর্শনগুলি ব্যবহার করে আপনি কী তৈরি করছেন তা শোনার অপেক্ষায় আছি। টুইটারে @AppSignal-এ শুধু কিচিরমিচির করুন।