রেল একটি বড় কাঠামো, এবং এটি প্রতি বছর বড় হয়। এটি কিছু সহায়ক বৈশিষ্ট্যের জন্য অলক্ষিত দ্বারা স্লিপ করা সহজ করে তোলে। এই সিরিজে, আমরা নির্দিষ্ট কাজের জন্য রেলে তৈরি কিছু স্বল্প পরিচিত কার্যকারিতা দেখব।
এই সিরিজের প্রথম প্রবন্ধে, আমরা Rails.env.test?
কে কীভাবে কল করা হয় তা দেখে নেব। আসলে অল্প-পরিচিত StringInquirer
ব্যবহার করে কাজ করে ActiveSupport থেকে ক্লাস। আরও এক ধাপ এগিয়ে, আমরা StringInquirer
-এর মাধ্যমেও হাঁটব এটি কীভাবে কাজ করে তা দেখার জন্য সোর্স কোড, যা (স্পয়লার সতর্কতা) বিশেষ method_missing
এর মাধ্যমে রুবির মেটাপ্রোগ্রামিংয়ের একটি সাধারণ উদাহরণ পদ্ধতি।
The Rails.env সহায়ক
আপনি সম্ভবত ইতিমধ্যেই এমন কোড দেখেছেন যা রেলের পরিবেশ পরীক্ষা করে:
if Rails.env.test?
# return hard-coded value...
else
# contact external API...
end
যাইহোক, কি test?
আসলে কি, এবং এই পদ্ধতি কোথা থেকে আসে?
যদি আমরা Rails.env
চেক করি একটি কনসোলে, এটি একটি স্ট্রিংয়ের মতো কাজ করে:
=> Rails.env
"development"
এখানে স্ট্রিং হল RAILS*ENV এনভায়রনমেন্ট ভেরিয়েবল যেটাই সেট করা হোক না কেন; যদিও এটি _শুধু* একটি স্ট্রিং নয়। কনসোলে ক্লাস পড়ার সময়, আমরা দেখতে পাই:
=> Rails.env.class
ActiveSupport::StringInquirer
Rails.env
আসলে একটি StringInquirer.
StringInquirer
৷StringInquirer-এর কোডটি সংক্ষিপ্ত এবং ভালভাবে নথিভুক্ত। এটি কীভাবে কাজ করে, যদিও, আপনি রুবির মেটাপ্রোগ্রামিং ক্ষমতার সাথে পরিচিত না হওয়া পর্যন্ত স্পষ্ট নাও হতে পারে। আমরা এখানে যা ঘটছে তার মধ্য দিয়ে হেঁটে যাব।
class StringInquirer < String
...
end
প্রথমত, আমরা দেখতে পাই যে StringInquirer হল String-এর একটি সাবক্লাস। এই কারণেই Rails.env
যখন আমরা এটিকে কল করি তখন একটি স্ট্রিংয়ের মতো কাজ করে। স্ট্রিং থেকে উত্তরাধিকারসূত্রে, আমরা স্বয়ংক্রিয়ভাবে সমস্ত স্ট্রিং-এর মতো কার্যকারিতা পাই, তাই আমরা এটিকে একটি স্ট্রিংয়ের মতো আচরণ করতে পারি। Rails.env.upcase
কাজ করে, যেমন করে ActiveRecordModel.find_by(string_column: Rails.env)
.
যখন Rails.env
StringInquirer-এর একটি সহজ, অন্তর্নির্মিত উদাহরণ, আমরা আমাদের নিজস্ব তৈরি করতেও স্বাধীন:
def type
result = "old"
result = "new" if @new
ActiveSupport::StringInquirer.new(result)
end
তারপরে, আমরা প্রত্যাবর্তিত মানের প্রশ্ন-চিহ্নের পদ্ধতিগুলি পাই:
=> @new = false
=> type.old?
true
=> type.new?
false
=> type.testvalue?
false
=> @new = true
=> type.new?
true
=> type.old?
false
method_missing
৷
method_missing
এখানে আসল গোপন সস। রুবিতে, যখনই আমরা একটি বস্তুর উপর একটি পদ্ধতি কল করি, রুবি পদ্ধতিটির জন্য বস্তুর সমস্ত পূর্বপুরুষ (যেমন, বেস ক্লাস বা অন্তর্ভুক্ত মডিউল) দেখে শুরু করে। যদি একটি পাওয়া না যায়, রুবি কল করবে method_missing
, যে পদ্ধতিটি খুঁজছে তার নামে পাস করা, যেকোনো আর্গুমেন্ট সহ।
ডিফল্টরূপে, এই পদ্ধতিটি শুধুমাত্র একটি ব্যতিক্রম উত্থাপন করে। আমরা সবাই সম্ভবত NoMethodError: undefined method 'test' for nil:NilClass
এর জন্য অনির্ধারিত পদ্ধতি 'পরীক্ষা'-এর সাথে পরিচিত ত্রুটি বার্তার ধরন। আমরা আমাদের নিজস্ব method_missing
বাস্তবায়ন করতে পারি এটি একটি ব্যতিক্রম উত্থাপন করে না, যা ঠিক StringInquirer
করে:
def method_missing(method_name, *arguments)
if method_name.end_with?("?")
self == method_name[0..-2]
else
super
end
end
যেকোনো এর জন্য পদ্ধতির নাম যা শেষ হয় ?
, আমরা self
এর মান পরীক্ষা করি (অর্থাৎ, স্ট্রিং) ?
ছাড়া পদ্ধতির নামের বিপরীতে . অন্য উপায়ে বলুন, যদি আমরা StringInquirer.new("test").long_test_method_name?
কল করি , ফেরত দেওয়া মান হল "test" == "long_test_method_name"
.
যদি পদ্ধতির নাম না করে একটি প্রশ্ন চিহ্ন দিয়ে শেষ, আমরা মূল method_missing
-এ ফিরে যাই (একটি যে একটি ব্যতিক্রম উত্থাপন করবে)।
respond_to_missing?
ফাইলটিতে আরও একটি পদ্ধতি আছে:respond_to_missing?
. আমরা বলতে পারি যে এটি method_missing
এর একটি সহচর পদ্ধতি . যদিও method_missing
আমাদের কার্যকারিতা দেয়, আমাদের রুবিকে বলার একটি উপায়ও প্রয়োজন যে আমরা এই প্রশ্ন-চিহ্ন-শেষ পদ্ধতিগুলি গ্রহণ করি।
def respond_to_missing?(method_name, include_private = false)
method_name.end_with?("?") || super
end
এটি কার্যকর হয় যদি আমরা respond_to?
কল করি এই বস্তুর উপর। এটি ছাড়া, যদি আমরা StringInquirer.new("test").respond_to?(:test?)
কল করি , ফলাফল হবে false
কারণ আমাদের কাছে test?
নামে কোনো সুস্পষ্ট পদ্ধতি নেই . এটি স্পষ্টতই বিভ্রান্তিকর কারণ আমি Rails.env.respond_to?(:test?)
কল করলে এটি সত্য হবে বলে আশা করব .
respond_to_missing?
যা আমাদের রুবিকে "হ্যাঁ, আমি সেই পদ্ধতিটি পরিচালনা করতে পারি" বলার অনুমতি দেয়। যদি পদ্ধতির নাম একটি প্রশ্ন চিহ্নে শেষ না হয়, আমরা সুপারক্লাস পদ্ধতিতে ফিরে যাই।
ব্যবহারিক ব্যবহারের ক্ষেত্রে
এখন আমরা জানি যে কিভাবে StringInquirer কাজ করে, চলুন দেখে নেওয়া যাক যেখানে এটি কার্যকর হতে পারে:
1. এনভায়রনমেন্ট ভেরিয়েবল
এনভায়রনমেন্ট ভেরিয়েবল দুটি মানদণ্ড পূরণ করে যা তাদের StringInquirer-এর জন্য দুর্দান্ত পছন্দ করে। প্রথমত, তাদের প্রায়ই সীমিত, পরিচিত সম্ভাব্য মানগুলির সেট থাকে (যেমন একটি enum
), এবং দ্বিতীয়ত, আমাদের প্রায়শই শর্তযুক্ত যুক্তি থাকে যা তাদের মূল্যের উপর নির্ভর করে।
ধরা যাক আমাদের অ্যাপটি একটি পেমেন্ট এপিআই-এর সাথে যুক্ত, এবং আমাদের কাছে শংসাপত্রগুলি পরিবেশের ভেরিয়েবলে সংরক্ষিত আছে। আমাদের উত্পাদন ব্যবস্থায়, এটি স্পষ্টতই আসল API, কিন্তু আমাদের স্টেজিং বা বিকাশ সংস্করণে, আমরা তাদের স্যান্ডবক্স API ব্যবহার করতে চাই:
# ENV["PAYMENT_API_MODE"] = sandbox/production
class PaymentGateway
def api_mode
# We use ENV.fetch because we want to raise if the value is missing
@api_mode ||= ENV.fetch("PAYMENT_API_MODE").inquiry
end
def api_url
# Pro-tip: We *only* use production if MODE == 'production', and default
# to sandbox if the value is anything else, this prevents us using production
# values if the value is mistyped or incorrect
if api_mode.production?
PRODUCTION_URL
else
SANDBOX_URL
end
end
end
উল্লেখ্য যে উপরে, আমরা ActiveSupport এর String#inquiry
ব্যবহার করছি পদ্ধতি, যা সহজে একটি স্ট্রিংকে আমাদের জন্য একটি স্ট্রিংইনকোয়ারারে রূপান্তর করে।
2. API প্রতিক্রিয়া
উপরে থেকে আমাদের পেমেন্ট API উদাহরণ অব্যাহত রেখে, API আমাদের একটি প্রতিক্রিয়া পাঠাবে যাতে কিছু সাফল্য/ব্যর্থতার অবস্থা অন্তর্ভুক্ত থাকে। আবার, এটি দুটি মানদণ্ড পূরণ করে যা এটিকে StringInquirer-এর প্রার্থী করে:সম্ভাব্য মানগুলির একটি সীমিত সেট এবং শর্তযুক্ত যুক্তি যা এই মানগুলি পরীক্ষা করবে৷
class PaymentGateway
def create_charge
response = JSON.parse(api_call(...))
result = response["result"].inquiry
if result.success?
...
else
...
end
# result still acts like a string
Rails.logger.info("Payment result was: #{result}")
end
end
উপসংহার
StringInquirer হল আপনার পিছনের পকেটে থাকা একটি আকর্ষণীয় টুল, কিন্তু ব্যক্তিগতভাবে, আমি এটির জন্য প্রায়ই পৌঁছাতে পারি না। এটির কিছু ব্যবহার রয়েছে, তবে বেশিরভাগ সময়, একটি বস্তুর উপর একটি স্পষ্ট পদ্ধতি আপনাকে একই ফলাফল দেয়। একটি সুস্পষ্টভাবে নামকরণ পদ্ধতিরও কয়েকটি সুবিধা রয়েছে; মান পরিবর্তন করার প্রয়োজন হলে, আপনাকে শুধুমাত্র একটি স্থান আপডেট করতে হবে, এবং কোন বিকাশকারী পদ্ধতিটি সনাক্ত করার চেষ্টা করলে এটি কোডবেসকে অনুসন্ধান করা সহজ করে তোলে।
যদিও এটি StringInquirer-এর উপর ফোকাস করে, এই নিবন্ধটি method_missing
ব্যবহার করে রুবির কিছু মেটাপ্রোগ্রামিং ক্ষমতার একটি মৃদু পরিচয় দেওয়ার উদ্দেশ্যে করা হয়েছে। . আমি বলব যে আপনি সম্ভবত method_missing
ব্যবহার করতে চান না আপনার আবেদনে। যাইহোক, এটি প্রায়শই ফ্রেমওয়ার্কগুলিতে ব্যবহৃত হয়, যেমন রেল বা রত্ন দ্বারা প্রদত্ত ডোমেন-নির্দিষ্ট-ভাষা, তাই যখন আপনি সমস্যার সম্মুখীন হন তখন "কিভাবে সসেজ তৈরি হয়" তা জানা খুব সহায়ক হতে পারে।