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

গভীর অন্বেষণ: সিন্যাত্রার অভ্যন্তরীণ কর্মকাণ্ড বোঝা

সিন্যাত্রা একটি রুবি ওয়েব ফ্রেমওয়ার্ক।

এটি রেলস-এর ছোট ভাইয়ের মতো…

চলুন জানি সিন্যাত্রা কীভাবে কাজ করে:

  • আপনার প্রোজেক্টে সিন্যাত্রা রিকвайার করলে কী ঘটে?
  • রাউট ম্যাচিং কীভাবে কাজ করে?
  • অনুরোধ ও প্রতিক্রিয়া কীভাবে প্রক্রিয়া করা হয়?

প্রশ্ন অনেক, কিন্তু সময় কম…

সমস্যা নেই!

আমি আপনার জন্য কঠিন কাজটি করেছি এবং এই নিবন্ধটি লিখেছি যেখানে আমি এই প্রশ্নের উত্তর দিয়েছি যাতে আপনি দ্রুত শিখতে পারেন!

সিন্যাত্রা আরম্ভকরণ

সবকुछ শুরু হয় একটি ফাইল থেকে: sinatra.rb।

এই ফাইলটি শুধু main.rb রিকוויার করে, তেমন 흥미로운 কিছু নেই, ঠিক?

এখন বিষয়টি আরও আকর্ষণীয় হচ্ছে!

main.rb-এর মধ্যে আপনি base.rb এর জন্য একটি রিকোয়ার এবং অপশন পার্সিং (পোর্ট, এনভায়রনমেন্ট, কোয়েট মোড ইত্যাদি) এর কোড পাবেন।

সিন্যাত্রা রুবির স্ট্যান্ডার্ড লাইব্রেরির optparse ব্যবহার করে।

এখানে আরও কী আছে?

এই at_exit ব্লকে এক নজর দিন:

 at_exit { Application.run! if $!.nil? && Application.run? } 

প্রোগ্রাম শেষ হলে রান হওয়া কোডের একটি টুকরো এটি।

হ্যাঁটা হলো আপনার সारा কোড রুবি পড়ে এবং যেহেতু আপনার কোনো লুপ, স্লিপ বা এমন কিছু নেই, আপনার প্রোগ্রাম স্বাভাবিকভাবে শেষ হয়।

…কিন্তু ঠিক শেষ হওয়ার আগে at_exit ব্লকটি ট্রিগার হয়!

তারপর সিন্যাত্রা দায়িত্ব নেয় এবং অনুরোধ হ্যান্ডল করার জন্য একটি ওয়েব সার্ভার শুরু করে।

এটি করার কোডটি:

 begin start_server(handler, server_settings, handler_name, &block) rescue Errno::EADDRINUSE $stderr.puts "== কেউ ইতিমধ্যে পোর্ট #{port}-এ পারফর্ম করছে!" raise end # base.rb `run!` মেথডের অংশ 

ওহ এবং এখানে আরেকটি গুরুত্বপূর্ণ ঘটনা ঘটে:

 extend Sinatra::Delegator 

Sinatra::Delegator একটি মডিউল যা সিন্যাত্রা DSL মেথডগুলোর সংজ্ঞা দেয় যেমন get, post ও set।

সেই কারণে আপনি এটি করতে পারেন:

 get '/' do puts "Hello World!" end 

সিন্যাত্রা গ্লোবাল main অবজেক্টকে এই মডিউল দিয়ে এক্সটেন্ড করে।

অনুরোধ ও প্রতিক্রিয়া প্রক্রিয়াকরণ

ঠিক আছে, এই পয়েন্টে আমাদের पास একটি রানিং সার্ভার আছে যা নতুন সংযোগ গ্রহণ করার জন্য প্রস্তুত।

কিন্তু একটি নতুন সংযোগ আসলে কী ঘটে?

সিন্যাত্রা, রেলস এবং অন্যান্য রুবি ওয়েব ফ্রেমওয়ার্কের মতো, নিচের স্তরের সব কন্ট্রোল র্যাক (Rack) এর হাতে দেয়।

র্যাক আপনার অ্যাপ্লিকেশনে একটি call মেথড থাকাকে আশা করে। এটি একটি অবজেক্ট যা আপনি র্যাক ইনিশিয়ালাইজ করার সময় দেন।

সিন্যাত্রার ক্ষেত্রে এই অবজেক্টটি হলো Sinatra::Base ক্লাস।

মেথডটি এখানে:

 # Rack কল ইন্টারফেস। def call!(env) @env = env @request = Request.new(env) @response = Response.new invoke { dispatch! } invoke { error_block!(response.status) } unless @env['sinatra.error'] @response.finish end # সিন্যাত্রার call মেথডের সংশোধিত সংস্করণ (স্পষ্টতার জন্য) 

দেখায় dispatch! মেথডটি অন্বেষণ করতে হবে যাতে বোঝা যায় একটি অনুরোধ কীভাবে হ্যান্ডল হয়।

মেথডটি এখানে:

 def dispatch! invoke do static! if settings.static? && (request.get? || request.head?) filter! :before route! end rescue ::Exception => boom invoke { handle_exception!(boom) } ensure filter! :after unless env['sinatra.static_file'] end # গুরুত্বপূর্ণ অংশগুলো রেখে সংক্ষিপ্ত করা হয়েছে 

অনুরোধ ৪ ধাপে ভাঙানো হয়:

  1. স্ট্যাটিক ফাইলগুলো প্রথমে চেক করা হয়। এগুলো হলো CSS, JS এবং ছবি जैसे ফাইল। এটি ডিফল্টভাবে সক্রিয় থাকে যদি "public" নামের একটি ডিরেক্টরি থাকে।
  2. বিফোর ফিল্টার রান করা হয়।
  3. রাউট ম্যাচিং।
  4. আফ্টার ফিল্টার রান করা হয়।

এখন প্রতিটি ধাপে গভীরে যেতে পারি।

স্ট্যাটিক ফাইল সার্ভ করা

static! মেথডটি khá সরল:

 def static!(options = {}) return if (public_dir = settings.public_folder).nil? path = File.expand_path("#{public_dir}#{URI_INSTANCE.unescape(request.path_info)}" ) return unless File.file?(path) cache_control(*settings.static_cache_control) if settings.static_cache_control? send_file(path, options) end 

এই কোডটি চেক করে অনুরোধকৃত ফাইলটি আছে কিনা, তারপর "Cache Control" HTTP হেডার সেট করে।

সর্বশেষ লাইনে send_file কল করে এবং এটি নাম অনুযায়ী কাজ করে 🙂

বিফোর ফিল্টার

একটি বিফোর ফিল্টার আপনাকে একটি মিলে যাওয়া রাউট খুঁজে বের করার আগে কোড চালানোর অনুমতি দেয়।

ফিল্টার যোগ করার উপায়:

 # একটি বিফোর ফিল্টার সংজ্ঞায়িত করুন। # একই কন্টেক্সটে সমস্ত অনুরোধের আগে রান করে যেন রাউট হ্যান্ডলার # এবং অনুরোধ ও প্রতিক্রিয়া অ্যাক্সেস/মডিফাই করতে পারে। @filters = {:before => [], :after => []} def before(path = /.*/, **options, &block) add_filter(:before, path, options, &block) end def after(path = /.*/, **options, &block) add_filter(:after, path, options, &block) end def add_filter(type, path = /.*/, **options, &block) filters[type] << compile!(type, path, block, options) end 

দেখতে পাচ্ছেন filters শুধু দুটি কী সহ একটি হ্যাশ, প্রতিটি ফিল্টার টাইপের জন্য একটি।

কিন্তু compile! কী?

এই মেথডটি ৩ উপাদানের একটি অ্যারে রিটার্ন করে: একটি প্যাটার্ন, শর্তগুলোর একটি অ্যারে এবং একটি র‍্যাপার।

এই সেটি মেথডটি রাউট জেনারেট করার জন্যও ব্যবহৃত হয় (যখন আপনি get বা post ব্লক ব্যবহার করেন):

 def get(path, opts = {}, &block) route('GET', path, opts, &block) end def route(verb, path, options = {}, &block) signature = compile!(verb, path, block, options) (@routes[verb] ||= []) << signature signature end # স্পষ্টতার জন্য মেথডগুলো সম্পাদিত 

এই থেকে আমরা শিখতে পারি সিন্যাত্রা ফিল্টারها রাউটের মতোই আচরণ ও কাজ করে।

রাউট ম্যাচিং

অনুরোধ প্রক্রিয়াকরণ চক্রের পরবর্তী ধাপ হলো রাউট ম্যাচিং:

 def route!(base = settings, pass_block = nil) routes = base.routes[@request.request_method] routes.each do |pattern, conditions, block| process_route(pattern, conditions) route_eval end route_missing end # সম্পাদিত মেথড 

এই কোডটি অনুরোধ মেথড (get, post ইত্যাদি) এর সাথে মিলে যাওয়া প্রতিটি রাউটের ওপর দিয়ে যায়।

রাউট ম্যাচিং process_route মেথডের ভিতরে ঘটে:

 def process_route(pattern, keys, conditions, block = nil, values = []) route = @request.path_info route = '/' if route.empty? and not settings.empty_path_info? return unless match = pattern.match(route) end 

যেখানে pattern একটি রেগুলার এক্সপ্রেশন।

যদি একটি রাউট পাথ এবং শর্ত দুটোই মিলে যায় তবে route_eval কল হবে, যা ব্লকটি (আপনার get / post রাউটের বডি) ইভ্যালুয়েট করে এবং রাউট ম্যাচিং প্রক্রিয়াটি শেষ করে।

 # একটি রাউট ব্লক রান করুন এবং ফলাফলসহ :halt থ্রো করুন। def route_eval throw :halt, yield end 

এটি অদ্ভুত catch / throw মেকানিজম ব্যবহার করে ফ্লো কন্ট্রোলের জন্য।

আমি এর বিরুদ্ধে পরামর্শ দেব কারণ কোডের ফ্লো অনুসরণ করা খুব কঠিন হতে পারে, কিন্তু রিয়েল-ওয়ার্ল্ডে এই ফিচারের ব্যবহার দেখা আকর্ষণীয়।

প্রতিক্রিয়া তৈরি

অনুরোধ চক্রের শেষ ধাপ হলো প্রতিক্রিয়া প্রস্তুত করা।

তাহলে প্রতিক্রিয়াটি কোথায় যায়?

invoke মেথডটি প্রতিক্রিয়াটি এভাবে সংগ্রহ করে:

 res = catch(:halt) { yield } 

এই ফলাফলটি body মেথড ব্যবহার করে প্রতিক্রিয়া বডিতে অ্যাসাইন করা হয়:

 body(res) 

এখন যদি আমরা শুরুতে ফিরে যাই, call মেথডে, আমরা এই লাইনটি পাব:

 @response.finish 

এটি @response-এ finish মেথড কল করে, যা একটি Rack::Response অবজেক্ট।

অর্থাৎ, এটি আসলে ক্লায়েন্টের কাছে প্রতিক্রিয়া পাঠাতে ট্রিগার করে।

বোনাস: Set মেথড কীভাবে কাজ করে

set মেথডটি সিন্যাত্রার DSL (ডোমেন-স্পেসিফিক ল্যাঙ্গুয়েজ) এর অংশ এবং এটি আপনাকে আপনার সিন্যাত্রা অ্যাপ্লিকেশনে যেকোনো জায়গায় কনফিগারেশন অপশন সেট করতে দেয়।

উদাহরণ:

 set :public_folder, '/var/www' 

প্রতিবার আপনি set ব্যবহার করলে সিন্যাত্রা মেটাপ্রোগ্রামিং এর মাধ্যমে ৩টি মেথড তৈরি করে:

 define_singleton("#{option}=", setter) if setter define_singleton(option, getter) if getter define_singleton("#{option}?", "!!#{option}") unless method_defined? "#{option}?" 

৩টি মেথড হলো (উদাহরণস্বরূপ public_folder দিয়ে):

  • public_folder
  • public_folder=
  • public_folder?

যদি সেটার মেথড (public_folder=) ইতিমধ্যে বিদ্যমান থাকে তবে এই মেথডটি সেটার মেথডটিও কল করবে:

 if respond_to?("#{option}=") && !ignore_setter return __send__("#{option}=", value) end 

মনে রাখবেন মেটাপ্রোগ্রামিং ফ্রি নয়, তাই আমি শুধু একটি options হ্যাশের साथ থাকব। আপনাকে jene ফ্যান্সি মেথডগুলোর প্রয়োজন নেই।

সারসংক্ষেপ

আপনি শিখেছেন সিন্যাত্রা কীভাবে আরম্ভ হয়, কীভাবে এটি একটি অনুরোধ হ্যান্ডল করে এবং প্রতিক্রিয়া তৈরি করার আগে এটি যে ধাপগুলো নেয়। এটি আপনাকে কিছু রুবি ট্রিক শিখতে এবং সিন্যাত্রা ভালোভাবে বুঝতে সাহায্য করবে!

অন্য রুবি ডেভেলপারদের সাথে এই পোস্ট শেয়ার করা না ভুলেন যাতে 그들도 এটি থেকে শিখতে পারেন 🙂


  1. জিমেইল আর্কাইভিংে দক্ষ হন: ডিলিট না করে ইনবক্স সংগঠিত রাখুন

  2. এক্সেলের ডেটা অ্যানালিসিস টুলপ্যাক মাত্র ২ সহজ ধাপে ইনস্টল করুন

  3. এক্সেলের ডেটা অ্যানালিসিস টুলপ্যাক ইনস্টল: ধাপে ধাপে গাইড

  4. এন্ডপয়েন্ট সিকিউরিটি ব্যাখ্যা: ডিভাইস এবং নেটওয়ার্ক রক্ষা