Skip to main content

প্রোগ্রামিং উইথ রুবিঃ আরেকটু Classy হোন! (পর্ব ১)

8 min read

[ডিসক্লেইমারঃ আজকে একটু বকবক বেশি করবো, এবং খুবই গুরুত্বপূর্ন বকবক। আজকে যদি সারভাইভ করতে পারেন তাহলে ধরে নিতে পারেন যে আপনি রুবি ৪৫% শিখে ফেলেছেন।]

শুন্য পর্বে বলেছিলাম, একজন প্রোগ্রামার হচ্ছে তার ভার্চুয়াল দুনিয়ার একক সম্রাট। সে চাইলেই যা খুশি তাই বানিয়ে ফেলতে পারে। শুধু দালান কেনো, রাস্তা ব্রীজ যা খুশি তাই!

আমাদের দুনিয়াতে কোন একটা জিনিস একবারে বোঝাতে সাধারণত জাতি বা কাছাকাছি কোন শব্দ ব্যবহার করি। যেমন সকল মানুষ একসাথে বোঝাতে আমরা মানুষজাতি শব্দটা ব্যবহার করি। আর আমি বা আপনি হচ্ছেন তার একটা পার্ট। চলাফেরা করা সকল জীবন্ত জিনিসকে একসাথে প্রাণীকুল, সকল জীবন্ত জিনিসকে একসাথে জীব বলা হয়! রুবিতেও আমরা একই কনসেপ্ট নিয়ে কাজ করি। তবে এখানে জাতি বা কুল শব্দ ব্যবহার করা হয় না। রুবি এই টাইপের জিনিসগুলোকে সিমপ্লিফাইড করে বলে Class। যেমন মানুষ Class, Animal Class এই টাইপের আরকি! এখানে আপনি বা আমি হব মানুষ ক্লাসের Object, যেমন Babar Object. বলার সময় অনেকটা এভাবে বলা হয়, Babar হচ্ছে মানুষ ক্লাসের একটা অবজেক্ট।

বেশি না পেচিয়ে, জাস্ট মনে রাখেন যে সিম্পল hierarchy মেইনটেইন করা হচ্ছে। রুবি দুনিয়ার সবকিছুকেই এরকম ক্লাস এবং অবজেক্ট দিয়ে ডিফাইন করে। যেমন আমরা যে গতকাল স্ট্রিং নিয়ে কাজ করেছি, ওইগুলা হলো String ক্লাসের অবজেক্ট। Integer নাম্বারগুলা হচ্ছে Fixnum ক্লাসের অবজেক্ট আর Flooting নাম্বার গুলা হচ্ছে Floot ক্লাসের অবজেক্ট। আপনি নিচের মত করে খুব সহজেই কোনটা কোন ক্লাসের অবেজক্ট সেটা নিজেই বের করে ফেলতে পারবেন।
ruby
[2] pry(main)> 5425.class
=> Fixnum
[3] pry(main)> 25725.0.class
=> Float
[4] pry(main)> "Hello Ruby".class
=> String

এখন মানুষ ক্লাসের অবেক্ট হিসেবে আমার কিছু বৈশিষ্ট আছে। যেমন মানুষ সামাজিক জীব, সো আমিও সামাজিক জীব(!), আমি একটা ফ্যামিলির সাথে বসবাস করি। নির্দিষ্ট একটা উচ্চতা আছে, সাথে আছে হাতির মত ওজন। এই বৈশিষ্টগুলা সব মানুষের মাঝেই কমন। খেয়াল করে দেখুন, একটা রিকশা ক্লাসের অবজেক্টের কিন্তু সামাজিক হওয়ার বৈশিষ্ট নেই। এইরকম বিভিন্নতা থাকার কারণেই সবগুলাকে আলাদা আলাদা ক্লাসে ভাগ করা হয়েছে। যাইহোক, এইযে আমার বিভিন্ন বৈশিষ্ট আছে, রুবিতে এইগুলাকে বলা হয় Properties. এখন এই প্রোপার্টিজ গুলাকে আবার দুইভাগে ভাগ করা যায়। যেমন মানুষ হিসেবে সব মানুষের মাঝে কমন হলো তার হাত আছে, পা আছে, সে কথা বলতে পারে এইসব। এইগুলাকে বলতে পারি মানুষ ক্লাসের প্রোপার্টিজ। আবার কিছু প্রোপার্টি আছে, যেগুলা সব মানুষেরই আছে, কিন্তু ভিন্ন ভিন্ন। যেমন সব মামুষ কথা বললেও সবাই একই ভাষায় কথা বলে না। তাহলে কি হলো? আমার ল্যাংগুয়েজ প্রোপার্টি/বৈশিষ্ট হলো বাংলা, একনজন গ্রীসের অধিবাসী মানুষ ক্লাসের অবজেক্টের ল্যাংগুয়েজ প্রোপার্টি হলো গ্রীক। তো এইরকম অবজেক্ট টু অবজেক্ট পরিবর্তনশীল প্রোপার্টিজগুলোকে আমরা অবজেক্ট প্রোপার্টি বলতে পারি। উপরে যে আপনি বিভিন্ন অবজেক্টের ক্লাস বের করতেছিলেন, ওইটাও ওই অবজেক্টের একটা প্রোপার্টি!

বিভিন্ন প্রোপার্টি থাকার পাশাপাশি মানুষ কাজকামও করে। মানুষ খায়দায়, ঘুমায় আরও কতকি! এই বিভিন্ন রকমের কাজগুলাকে রুবি বলে Methods. রুবির ভাষায় ঘুমানো/Sleep, ব্যায়াম/Excersie হচ্ছে একেকটা Method. প্রোপার্টির মত মেথডগুলোকেও আমরা ক্লাস মেথড এবং অবজেক্ট মেথড দুইভাগে ভাগ করতে পারি। যেমন আমি কোড করি কিন্তু আমার বাপজান কোড করে না। সো এইটা মানুষ ক্লাসের সকল অবজেক্টের জন্য প্রযোজ্য/কমন নয়, বরং বাবর অবজেক্টের জন্য প্রযোজ্য।

তো মেলা কথা হইছে, এইবার আসেন আমরা কিছু কোড দেখি। আজকে আমরা একটা ফাইলে কোড লিখবো। ওহ, তার আগে একটু অন্য প্রসঙ্গে বলি। সেটা হলো, আগের পর্বে আপনারা [inline-code]irb[/inline-code] তে কিছু কোড লিখতেছিলেন, সে একটা ভ্যালু রিটার্ণ করতেছিলো। কিন্তু রিটার্ণ করাই সবসময় এনাফ না। আপনি চাবেন, ইউজারকে কিছু একটা প্রিন্ট করিয়ে দেখাতে। নিচের কোডটা ট্রাই করে দেখুনঃ
[code type=ruby][7] pry(main)> Hello Ruby
=> Hello Ruby
[8] pry(main)> puts Hello Ruby
Hello Ruby
=> nil[/code]
প্রথম লাইনটা রিটার্ণ করেছে, পরের লাইনটা স্ক্রীণে প্রিন্ট করেছে। আপাতদৃষ্টিতে দুটো একই মনে হলেও আসলে এক না। স্পেশালী দেখুন, পরের লাইনে কোন কোটেশন আসে নাই আউটপুটে। আর তারও নিচে একটা [inline-code]nil[/inline-code] অবজেক্ট রিটার্ণ করেছে। [inline-code]nil[/inline-code] এর মানে হচ্ছে কোন কিছুই না। ক্যারমবোর্ডে Nil এ গেম দেয়ার মত আরকি! আমরা স্ক্রীণে কোনকিছু প্রিন্ট করার জন্য [inline-code]puts/print[/inline-code] ব্যবহার করি। যেমন আমরা [inline-code]“Hello Ruby”[/inline-code] String এর আগে [inline-code]nuts/print[/inline-code] বসিয়ে দিয়েছি। এটাও একটা মেথড। এটা হচ্ছে রুবির বিল্টইন মেথড। আমরা শুধু স্ট্রিং না, নাম্বারও প্রিন্ট করতে পারি।

[code type=ruby][11] pry(main)> puts 5745
5745
=> nil
[12] pry(main)> puts 528725.45
528725.45
=> nil[/code]
মোটের উপর কথা হচ্ছে, ফাইলে কোড লেখার সময় আমরা নরমাল ফ্লোতেই চলবো। শুধউমাত্র ইউজারকে যতটুকু জানানোর দরকার ততটুকু প্রিন্ট করবো।

তো এবার চলুন মানুষ প্রজাতিটাকে কোড করে ফেলি। সেটআপ পর্বে বানানো আপনার রুবি ফোল্ডারে একটা নতুন ফাইল সেভ করুন [inline-code]man.rb[/inline-code] নামে এবং নিচের কোডটুকু ওইফাইলে লিখে ফেলুনঃ
[code type=ruby]class Man
end[/code]

ওয়াও, আপনি তো দেখি রুবির সবচেয়ে কঠিন জিনিসগুলার একটা এত্ত সহজে পার করে ফেললেন, নতুন একটা ক্লাস পানিয়ে ফেলেছেন! কনগ্র্যাটস! বুঝতেই পারতেছেন, এটা হলো ক্লাস ডেফিনেশন, এরপর থেকে নতুন কোন ক্লাস বানাতে হলে আমরা এভাবেই লিখবো। প্রথমে [inline-code]class[/inline-code] কীওয়ার্ড, এরপরে ক্লাসের নাম এবং সর্বশেষ পরের লাইনে [inline-code]end[/inline-code] কীওয়ার্ড। খেয়াল করুন, ক্লাসের নাম কিন্তু বড় অক্ষর দিয়ে শুরু, এটাও সবসময়ই এরকমই হবে।
আচ্ছা এখন কাহিনী হলো, এই ক্লাসটা তো একেবারেই খালি। মানব প্রজাতির কিছু কমন বৈশিষ্ট (Properties) আছে, চলুন সেগুলোও ইমপ্লিমেন্ট করে ফেলি।

[code type=ruby]class Man
def initialize(name, age)
@name = name
@age = age
end
def status
Hello My name is + @name + and I am + @age + years old!
end
end[/code]

একটু বেশি কোড লিখে ফেলছি। টেনশনের কোন কারণ নাই। বুঝিয়ে দেয়ার জন্য আমি তো আছিই! প্রথমে যে [inline-code]def initialize(name, age)[/inline-code] এটা হচ্ছে একটা মেথড, মেথড শেষ হয় [inline-code]end[/inline-code] দিয়ে। পরে যখন আমরা নতুন কোন মানুষ বানাবো এই [inline-code]Man[/inline-code] ক্লাসের কোড দিয়ে, তখন এই মেথডটা সবসময়ই রান করবে। এটাকে আপনি অনেকটা ডেলিভারীর সাথে তুলনা করতে পারেন, সব মানুষ জন্মানোর জন্য ডেলিভারী হতেই হবে সেরকম। জন্মানোর সময় থেকেই তার বয়স গণনা শুরু হয়ে যায়, একটা নাম পরিয়ে দেয়া হয়। ব্যাপারটা অনেকটা ওরকমই। মানুষের জন্ম হতে হলে ভুমিষ্ঠ হতে হবে, আর কোডে নতুন মানুষ বানাতে হলে এই কোডটা রান করতে হবে। তবে সুবিধা হলো, এটা আমাদের ম্যানুয়ালী করতে হবে না। রুবি নিজেই আমাদের জন্য এটা করে দেবে!
তো এই মেথডের ভিতরে আছে হলো, [inline-code]@name[/inline-code] এবং [inline-code]@age[/inline-code] নামে দুইটা ভ্যারিয়েবল এবং দুইটা এসাইনমেন্ট স্টেটমেন্ট। আমরা যখন নতুন একটা মানুষ কোড করবো তথা এই ক্লাসের একটা অবজেক্ট বানাবো তখন এই দুইটা ভ্যারিয়েবল নাম এবং বয়স মনে রাখবে। এদেরকে অনেকসময় Object Variable বলেও ডাকা হয়। এবং এরাই হচ্ছে Man ক্লাসের অবজেক্টের Properties বা বৈশিষ্ট। একটু মনে রাখবেন অবজেক্ট ভ্যারিয়েব সবসময় এট (@) সাইন দিয়ে শুরু হয়।
এরপরে আছে [inline-code]def status[/inline-code] লাইন। এটাও আগের মতই মেথড। তবে এটা অটোমেটিক কল হয় না। একে আমরা নিজেদের সুবিধামত যখন দরকার কল করতে পারবো। এই মেথডের কাজ হচ্ছে যে কোন মানুষের ওভারঅল একটা অবস্থা আমাদের জানানো। মেথডের ভিতরের কোডটা খেয়াল করুনঃ
[code type=ruby]Hello My name is + @name + and I am + @age + years old![/code]
এই কোডটুকু আপনার পরিচিতই লাগার কথা, যদি গত পর্বটা ঠিকঠাক মত ফলো করে থাকেন! তেমন কিছুই না, সিমপ্লি দুটো ভ্যারিয়েবল এবং কিছু String জোড়া দেয়া হয়েছে পুরো একটা বাক্য গঠনের জন্য।

তো আমাদের ক্লাস ডিফাইন শেষ। এবার আমরা এই ক্লাস দিয়ে কোডের রহিম, করিম, জদু, মধু বানানো শুরু করে দেই! ক্লাস ডেফিনেশনের পরে একেবারে ফাইলের শেষের দিকে নিচের কোড লেখা শুরু করে দিনঃ
[code type=ruby]rahim = Man.new(Rahim Chowdhury, 42)
karim = Man.new(Karim Khan, 35)[/code]

পড়তে পারেন অনেকটা এইভাবে, [inline-code]rahim[/inline-code] হচ্ছে [inline-code]Man[/inline-code] ক্লাসের নতুন সদস্য যার নাম [inline-code]Rahim Chowdhury[/inline-code] আর বয়স 42। এইবার আমাদের কোডের লাস্ট পার্ট, রহিম বা করিম সাহেবের কি স্ট্যাটাস তা জানার চেষ্টা করি।
[code type=ruby]puts rahim.status
puts karim.status[/code]

ফাইলটা সেভ করুন। এবার ফাইলটা আমরা রুবি দিয়ে টার্মিনাল থেকে রান করবো। খেয়াল করে, এইবার কিন্তু [inline-code]irb[/inline-code] লিখি নাই, সরাসরি [inline-code]ruby[/inline-code] লিখেছি এবং ফাইলনেমটা পাস করে দিয়েছি!
[code type=ruby]$ ruby man.rb
Hello My name is Rahim Chowdhury and I am 42 years old!
Hello My name is Karim Khan and I am 35 years old![/code]

কনগ্র্যাটস ম্যান, আপনি তো আপনার প্রথম ডায়নামিক প্রোগ্রাম বানিয়ে ফেলেছেন অলরেডী! ওয়াও!

আচ্ছা এবার তাহলে আমরা আর অল্প একটু কাজ করি আমাদের ক্লাসটাকে আরেকটু কাজের করার জন্য। ধরুন আপনি স্ট্যাটাস না জেনে সরাসরি কারও নাম জানতে চাচ্ছেন। তাহলে কি করা যায় বলেন তো? জি ঠিক ধরেছেন, আমার [inline-code]status[/inline-code] এর মত আরেকটা মেথড বানাবো [inline-code]name[/inline-code] নামে এবং সেটাকে আমরা [inline-code]rahim.name[/inline-code] এইভাবে কল করবো! তো করে ফেলি কাজটুকু!
[code type=ruby]def name
@name
end[/code]

এবার আমরা করিম সাহেবের পুরো নাম জানতে চাইবো
[code type=ruby]puts karim.name[/code]
পুরো ফাইলটা আবার রান করে দেখুন তো কি আউটপুট দেখায়! দেখছেন কত্ত সোজা!

আজকের মত এইখানেই খতম দেই।
এইবার আপনার এসাইনমেন্ট
প্রথমটা হলো আমার তো নাম জানতে পারলাম আলাদাভাবে, এবার তাহলে বয়স জানার মেথডটাও ইমপ্লিমেন্ট করে ফেলুন নিজে নিজে। সাথে আরও দুয়েকটা প্রোপার্টিজ (যেমন জব, জাতীয়তা) ও ইমপ্লিমেন্ট করতে পারেন!
পরের এসাইনমেন্ট হলো, গার্লফ্রেন্ড প্রজাতির জন্য একটা ক্লাস বানাবেন সাথে বিভিন্ত প্রোপার্টিজ ইমপ্লিমেন্ট করবেন। এবং আপনার বর্তমান এবং পূর্ববর্তী (যদি থাকে, না চাইলে দিয়ে না, কিছু কথা থাকনা গুপন!) গার্লফ্রেন্ডএর অবজেক্ট বানিয়ে কোডটা আমাদের সবার সাথে শেয়ার করুন। তবে সাধু সাবধান, গার্লফ্রেন্ড ক্লাসে কিন্তু কোনমতেই বয়স প্রোপার্টি ইমপ্লিমেন্ট করার ট্রাই কইরেন না, সেক্ষেত্রে আপনার বর্তমানও অতীত হয়ে যেতে পারে!

এইবার দুটো টিপস দিয়ে দেই আপনাদের
টিপস ১ উপরে কোডগুলা দেখুন, ক্লাসের ভিতরে মেতডগুলা কিরকম একটু ডান দিকে চাপিয়ে দিয়ছি স্পেস দিয়ে। মেথডরে ভিতরের কোডগুলা আরেকটু ডানে। দেখতে জিনিসটা সুন্দর লাগতেছে। এইভাবে কোড সাজানোকে বলে Indentation. Rubyist রা মূলত দুটো করে স্পেস দিয়ে এইভাবে কোড ইনডেন্ট করে থাকে। আপনিও কোড করার সময় অবশ্যই ইন্ডেন্ট করবেন। একজন কোডারের ভালো অভ্যাসগুলোর মাঝে এটা একটা।
টিপস ২ কোড শেয়ার করার জন্য আপনারা Gist ব্যবহার করতে পারেন। খুবই ভালো একটা জায়গা। রেজিস্টার না করেও কোড শেয়ার করতে পারবেন, তবে আমি রিকমেন্ড করবো রেজিস্টার করে ফেলার জন্য। তাহলে আপনি পরে আপনার কোডগুলা রিভিউ করতে পারবেন একসাথে চাইলেই। আর কোন প্রবলেমে পড়লে এইভাবে শেয়ার করলে অনেকেই হেল্প করতে পারবে।

নোটঃ এই পর্বের পুরো সোর্সকোড একসাথে পাবেন এখানে Man.rb