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

রুবি রিফাইনমেন্ট ব্যাখ্যা: কীভাবে লেক্সিক্যাল স্কোপ আপনার কোড আকার দেয়

আপনি যদি কখনো রিফাইনমেন্ট ব্যবহার না করে থাকেন, তবে আপনি একটি সারপ্রাইজের জন্য প্রস্তুত থাকুন। আপনি শুনে থাকতে পারেন যে রিফাইনমেন্ট মংকি প্যাচিং রিপ্লেস করার জন্য আনা হয়েছে। তাই আপনি আশা করতে পারেন যে আপনি 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

উপসংহার

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

  1. রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

  2. রুবি ডিপেন্ডেন্সি ম্যানেজমেন্ট মাস্টারিং: Rbenv, RubyGems, এবং Bundler কীভাবে ইন্টারঅ্যাক্ট করে

  3. রুবি দিয়ে ইন্সারশন সর্টিং দক্ষতা অর্জন: ধাপে ধাপে গাইড

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