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

রেইলস ৫ Module#prepend পরিচয় করাচ্ছে: alias_method_chain প্রতিস্থাপন

রেইলস ৪.২ ঘোষণায় আগামী রেইলস ৫ নিয়ে কিছু ইন্তেরেস্টিং খবর ছিল: এটা সম্ভবত রুবি ২.২ রিকোয়ার করবে। যেটা এটাকে রুবি ২ থেকে সব ভালো জিনিসগুলো আধিকারিকভাবে ব্যবহার করার প্রথম রেইলস ভার্সন বানাবে।

পোস্টে গারবেজ কलेक्टেড সিম্বল এবং কিওয়ার্ড আর্গুমেন্টের কথা বলা হয়েছে। কিন্তু আমার কাছে, রুবি ২-র সবচেয়ে ইন্তেরেস্টিং ফিচার হচ্ছে Module#prepend।

alias_method_chain-র ভালো (এবং খারাপ) দিক

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

শুধু এক লাইন কোড দিয়ে, আপনি একটি মেথড কীভাবে কাজ করে সেটা পুরোপুরি পরিবর্তন করতে পারতেন। আপনাকে লাইব্রেরি হ্যাক করতে হতো না আপনার চাওয়া কোড যোগ করার জন্য, আপনি সেটা অন দ ফ্লাই যোগ করতে পারতেন। alias_method_chain আমাকে আমার প্রথম জেম প্যাচ দিয়েছিল, যেটা আমার প্রথম পুল রিকোয়েস্টে লידי করল, যেটা আমার প্রথম ওপেন সোর্স কন্ট্রিবিউশনে লیدی করল।

তবে মানকি প্যাচিংয়ের মত, alias_method_chain অত্যধিক ব্যবহার হয়েছে, এবং এর সমস্যাগুলো স্পষ্ট হতে শুরু করলো:

  • এটা যে মেথড নাম জেনারেট করে সেগুলো কনফিউজিং, যা এরর খুঁজে বের করা এবং ডিবাগ করা কঠিন করে দেয়। উদাহরণস্বরূপ:
class Person def greeting "Hello" end end module GreetingWithExcitement def self.included(base) base.class_eval do alias_method_chain :greeting, :excitement end end def greeting_with_excitement "#{greeting_without_excitement}!!!!!" end end Person.send(:include, GreetingWithExcitement)

Person#greeting-এ এরর থাকলে, ব্যাকট্রেস বলবে এরর আসলে Person#greeting_without_excitement-এ হয়েছে। কিন্তু সেই মেথডটি কোথায় ডিফাইন করা? আমি কোথাও দেখি না। আপনি কীভাবে বুঝবেন কোন greeting মেথডটিতে বাগ আছে? এবং চেইন করলে মেথড নামগুলো আরও কনফিউজিং হয়।

  • আপনি যদি একই প্যারামিটারসহ একই ক্লাসে দুবার alias_method_chain কল করেন, তবে স্ট্যাক ওভারফ্লো হতে পারে। (কেন বুঝতে পারছেন?) এটি সাধারণত হয় না, যতক্ষণ আপনার require স্টেটমেন্টগুলো কনসিস্টেন্ট থাকে পাথ নিয়ে। কিন্তু রেইলস কনসোলে কোড পেস্ট করলে এটা সুপার ইরিটেটিং।

  • এবং ইহুদা ক্যাটজের ব্লগ পোস্টে বর্ণিত বাকি জিনিসগুলো। সেই পোস্ট অনেক রেইলস ডেভেলপারকে alias_method_chain ছেড়ে মডিউল ইনহেরিটেন্স-এ যেতে কনভিন্স করলো।

তবুও, এটা কেন এখনো ব্যবহৃত হয়?

আপনি অধিকাংশ alias_method_chain রিপ্লেস করতে পারেন সেই মেথডগুলোকে একটি মডিউলে ওভাররাইড করে, এবং সেসব মডিউল আপনার চাইল্ড ক্লাসে ইনক্লুড করে। কিন্তু এটা তখনই কাজ করে যখন আপনি আপনার সুপারক্লাস ওভাররাইড করতে চান, আপনার ক্লাস নিজে না। অর্থাৎ:

class ParentClass def log puts "In parent" end end class ChildClass < ParentClass def log puts "In child" super end def log_with_extra_message puts "In child, with extra message" log_without_extra_message end alias_method_chain :log, :extra_message end

আপনি ChildClass.new.log রান করলে দেখবেন:

In child, with extra message In child In parent

আপনি যদি মডিউল ব্যবহার করে alias_method_chain-র বদলে করার চেষ্টা করেন, আপনি আউটপুট পাবেন:

In child In child, with extra message In parent

তবে আপনি ChildClass-এ log মেথড পরিবর্তন না করে অরিজিনাল আউটপুট ম্যাচ করতে পারবেন না। রুবি ইনহেরিটেন্স সেভাবে কাজ করে না। خوب, আগে করত না।

রুবি ২.০-এ কী পরিবর্তন হলো?

রুবি ২.০ পর্যন্ত, একটি ক্লাসের নিচে কোড যোগ করার কোনো উপায় নেই, শুধু উপরে যোগ করা যেত। তবে prepend দিয়ে, আপনি একটি ক্লাসের মেথডকে একটি মডিউলের মেথড দিয়ে ওভাররাইড করতে পারেন, এবং এখনও ক্লাসের ইমপ্লিমেন্টেশন অ্যাক্সেস করতে পারেন super দিয়ে। তাই, আমাদের লাস্ট উদাহরণ দিয়ে, আমরা অরিজিনাল আউটপুট পেতে পারি:

class ParentClass def log puts "In parent" end end module ExtraMessageLogging def log puts "In child, with extra message" super end end class ChildClass < ParentClass prepend ExtraMessageLogging def log puts "In child" super end end
In child, with extra message In child In parent

পারফেক্ট।

prepend এখনও যদি বুঝতে কঠিন লাগে, তবে এটাকে এমন চিন্তা করুন:

class NewChildClass < ChildClass include ExtraMessageLogging end ChildClass = NewChildClass

সिर्फ এটা আপনার ক্লাস নাম মেস আপ করে না, এবং ইতিমধ্যে এক্সিস্ট করা অবজেক্টগুলোকেও এফেক্ট করে।

(হ্যাঁ, রুবিতে ক্লাস নাম রি-অ্যাসাইন করা যায়। না, এটা সম্ভবত ভালো আইডিয়া নয়।)

রেইলসের জন্য এটা কী মানে?

তাই, alias_method_chain-র লাস্ট এক্সকিউজ রুবি ২.০-এ গেলো। আমরা রেইলসে alias_method_chain-র বাকি অল্প উদাহরণগুলো থেকে একটি নেওয়া যাক:

rails/activesupport/lib/active_support/core_ext/range/each.rb
require 'active_support/core_ext/module/aliasing' class Range #:nodoc: def each_with_time_with_zone(&block) ensure_iteration_allowed each_without_time_with_zone(&block) end alias_method_chain :each, :time_with_zone def step_with_time_with_zone(n = 1, &block) ensure_iteration_allowed step_without_time_with_zone(n, &block) end alias_method_chain :step, :time_with_zone private def ensure_iteration_allowed if first.is_a?(Time) raise TypeError, "can't iterate from #{first.class}" end end end

এটা একটি মডিউল দিয়ে রিপ্লেস করা যাক:

require 'active_support/core_ext/module/aliasing' module RangeWithTimeWithZoneSupport #:nodoc: def each(&block) ensure_iteration_allowed super(&block) end def step(n = 1, &block) ensure_iteration_allowed super(n, &block) end private def ensure_iteration_allowed if first.is_a?(Time) raise TypeError, "can't iterate from #{first.class}" end end end Range.send(:prepend, RangeSupportingTimeWithZone)

এটা ক্লিনার, Range#each রিনেম হয় না, এবং ensure_iteration_allowed মানকি-প্যাচড হয় না।

ইনহেরিটেন্স ব্যবহার করুন, প্যাচ না

রুবি আপনাকে অপ্রত্যাশিত ফ্লেক্সিবিলিটি দেয়, এবং এটাই একের কারণে আমি এটা ভালোবাসি। কিন্তু এটার একটি পাওয়ারফুল অবজেক্ট মডেলও আছে। তাই যখন আপনি আপনার নিজস্ব কোড ইনজেক্ট করতে চান, মডিউল এবং ইনহেরিটেন্সের ওপর নির্ভর করার চেষ্টা করুন হ্যাক করার আগে। আপনার কোড অনেক সহজে বোঝা এবং ডিবাগ করা যাবে, এবং আপনি alias_method_chain-এর মত কঠিন ডিটেক্ট হয়ে যাওয়া সাইড ইফেক্ট এড়াতে পারবেন।

alias_method_chain রেইলসে আমাকে পরিচয় করানো সবচেয়ে কুল মেথডগুলোর একটা ছিল। কিন্তু এর দিন gone। আমরা এরা বড় হয়ে গেলাম। এবং এটি গেলে আমি মিস করব না।

  1. উইন্ডোজ ভিস্তা সাপোর্ট শেষ: যা আপনার জানা ও করা দরকার

  2. Python ও Matplotlib ব্যবহার করে লাইনের শেষে অ্যানোটেশন যোগ করার পদ্ধতি?

  3. রুবি অন রেইলস পডকাস্টে ফিচার্ড: লেখালেখি, অভ্যাস ও স্থবিরতা দূর করুন

  4. রেইলসে ক্যারিয়ারওয়েভ দিয়ে ফাইল আপলোডে দক্ষতা অর্জন