সিনাট্রা একটি রুবি ওয়েব ফ্রেমওয়ার্ক।
এটা Rails ছোট ভাইয়ের মত…
আসুন সিনাট্রা কীভাবে কাজ করে তা অন্বেষণ করি :
- আপনার প্রজেক্টে সিনাত্রার প্রয়োজন হলে কি হবে?
- রুট ম্যাচিং কিভাবে কাজ করে?
- অনুরোধ এবং প্রতিক্রিয়া কিভাবে প্রক্রিয়া করা হয়?
অনেক প্রশ্ন, কিন্তু এত কম সময়…
কোন সমস্যা নেই!
আমি আপনার জন্য কঠোর পরিশ্রম করেছি এবং এই নিবন্ধটি একসাথে রেখেছি যেখানে আমি এই প্রশ্নগুলির উত্তর দিয়েছি যাতে আপনি দ্রুত শিখতে পারেন!
সিনাট্রা ইনিশিয়ালাইজেশন
এটি সব একটি ফাইল দিয়ে শুরু হয়: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 "== Someone is already performing on port #{port}!"
raise
end
# Part of base.rb `run!` method
ওহ এবং আরেকটি গুরুত্বপূর্ণ জিনিস এখানে ঘটে:
extend Sinatra::Delegator
Sinatra::Delegator একটি মডিউল যা সিনাট্রা ডিএসএল পদ্ধতিগুলিকে সংজ্ঞায়িত করে যেমন get , post &set .
এজন্য আপনি এটি করতে পারেন:
get '/' do puts "Hello World!" end
সিনাট্রা বিশ্বব্যাপী main প্রসারিত করে এই মডিউল সহ অবজেক্ট।
অনুরোধ এবং প্রতিক্রিয়া প্রক্রিয়াকরণ
ঠিক আছে, তাই এই মুহুর্তে আমাদের কাছে একটি চলমান সার্ভার রয়েছে যা নতুন সংযোগগুলি গ্রহণ করার জন্য প্রস্তুত৷
কিন্তু একটি নতুন সংযোগ প্রাপ্ত হলে কি হবে?
ওয়েল সিনাট্রা, রেল এবং অন্যান্য রুবি ওয়েব ফ্রেমওয়ার্কের মতো, সমস্ত নিম্ন স্তরের জিনিসগুলি পরিচালনা করতে র্যাক ব্যবহার করে৷
র্যাক একটি call আশা করে পদ্ধতি আপনার আবেদনে উপলব্ধ। এটি শুধুমাত্র একটি বস্তু যা আপনি র্যাককে দেন যখন আপনি এটি শুরু করেন।
সিনাট্রার ক্ষেত্রে এই বস্তুটি হল Sinatra::Base ক্লাস।
এখানে পদ্ধতি :
# Rack call interface.
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
# Modified version of Sinatra's call method (for clarity)
মনে হচ্ছে আমাদের 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
# Edited down to the important parts
অনুরোধটি ৪টি ধাপে বিভক্ত :
- স্ট্যাটিক ফাইলগুলি প্রথমে চেক করা হয়। এগুলো হল css, js এবং images এর মত ফাইল। এই সেটিংটি ডিফল্টরূপে সক্রিয় থাকে যদি "পাবলিক" নামে একটি ডিরেক্টরি বিদ্যমান থাকে ৷
- ফিল্টার চালানোর আগে
- রুটের মিল
- ফিল্টার পরে চালানো হয়
এখন আমরা আরও বিশদে কী ঘটতে পারে তা দেখতে প্রতিটি ধাপে খনন করতে পারি।
স্ট্যাটিক ফাইল পরিবেশন করা
static! পদ্ধতিটি বেশ সহজ:
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
এই কোডটি অনুরোধ করা ফাইলটি বিদ্যমান কিনা তা পরীক্ষা করে, তারপর এটি "ক্যাশ কন্ট্রোল" HTTP শিরোনাম সেট করে৷
শেষ লাইনে এটি send_file কল করে এবং নাম যা বলে তা ঠিক তাই করে 🙂
ফিল্টার করার আগে
একটি বিফোর ফিল্টার আপনাকে একটি মিলিত রুট খোঁজার চেষ্টা করার আগে কোড চালানোর অনুমতি দেয়৷
এইভাবে একটি ফিল্টার যোগ করা হয়:
# Define a before filter.
# Runs before all requests within the same context as route handlers
# and may access/modify the request and response.
@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! কি ?
এই পদ্ধতিটি 3টি উপাদান সহ একটি অ্যারে প্রদান করে:একটি প্যাটার্ন, শর্তগুলির একটি অ্যারে এবং একটি মোড়ক৷
রুট তৈরি করার জন্য একই পদ্ধতি ব্যবহার করা হয় (যখন আপনি একটি 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
# Methods edited for clarity
এটি থেকে আমরা শিখতে পারি যে সিনাট্রা ফিল্টারগুলি রুটগুলির মতো একইভাবে আচরণ করে এবং কাজ করে৷
রুট ম্যাচিং
অনুরোধ প্রক্রিয়াকরণ চক্রের পরবর্তী ধাপ হল রুট ম্যাচিং:
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
# Edited method
এই কোডটি অনুরোধের পদ্ধতির সাথে মেলে এমন প্রতিটি রুটে যায় (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 রুট) এবং রুট ম্যাচিং প্রক্রিয়া শেষ করে।
# Run a route block and throw :halt with the result. def route_eval throw :halt, yield end
এটি অস্বাভাবিক catch ব্যবহার করে / throw প্রবাহ নিয়ন্ত্রণের প্রক্রিয়া।
আমি এটির বিরুদ্ধে সুপারিশ করব কারণ এটি কোডের প্রবাহ অনুসরণ করা খুব বিভ্রান্তিকর হতে পারে, তবে এই বৈশিষ্ট্যটির ব্যবহারে বাস্তব-বিশ্বের উদাহরণ দেখতে আকর্ষণীয়৷
প্রতিক্রিয়া বিল্ডিং
অনুরোধ চক্রের শেষ ধাপ হল প্রতিক্রিয়া প্রস্তুত করা।
তাহলে প্রতিক্রিয়া কোথায় যায়?
invoke পদ্ধতি এইভাবে প্রতিক্রিয়া সংগ্রহ করে:
res = catch(:halt) { yield }
এই ফলাফলটি body ব্যবহার করে প্রতিক্রিয়া বডিতে বরাদ্দ করা হয়েছে পদ্ধতি:
body(res)
এখন যদি আমরা ফিরে দেখি যেখানে আমরা শুরু করেছি, call পদ্ধতি, আমরা কোডের এই লাইনটি খুঁজে পাব:
@response.finish
এটিকে finish বলে @response-এ পদ্ধতি , যা একটি Rack::Response বস্তু।
অন্য কথায়, এটি আসলে ক্লায়েন্টকে পাঠানোর প্রতিক্রিয়াকে ট্রিগার করবে।
বোনাস:সেট পদ্ধতি কিভাবে কাজ করে
সেট পদ্ধতিটি সিনাট্রার ডিএসএল (ডোমেন-স্পেসিফিক ল্যাঙ্গুয়েজ) এর অংশ এবং এটি আপনাকে আপনার সিনাট্রা অ্যাপ্লিকেশনের যেকোনো জায়গায় কনফিগারেশন বিকল্পগুলি সেট করতে দেয়৷
উদাহরণ :
set :public_folder, '/var/www'
প্রতিবার আপনি set ব্যবহার করুন সিনাট্রা 3টি পদ্ধতি তৈরি করে (মেটাপ্রোগ্রামিংয়ের মাধ্যমে):
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= ) যদি এটি ইতিমধ্যেই বিদ্যমান থাকে:
if respond_to?("#{option}=") && !ignore_setter
return __send__("#{option}=", value)
end
মনে রাখবেন যে মেটাপ্রোগ্রামিং বিনামূল্যে নয়, তাই আমি শুধু একটি options দিয়ে থাকব হ্যাশ আপনার সেই অভিনব পদ্ধতির দরকার নেই।
সারাংশ
আপনি শিখেছেন কীভাবে সিনাত্রা শুরু হয়, কীভাবে এটি একটি অনুরোধ পরিচালনা করে এবং প্রতিক্রিয়া তৈরি না হওয়া পর্যন্ত বিভিন্ন পদক্ষেপ নেওয়া হয়। এটি আপনাকে রুবির কয়েকটি কৌশল শিখতে এবং সিনাট্রাকে আরও ভালভাবে বুঝতে সাহায্য করবে!
এই পোস্টটি শেয়ার করতে ভুলবেন না৷ অন্যান্য রুবি বিকাশকারীদের সাথে যাতে তারাও এটি থেকে শিখতে পারে 🙂