কম্পিউটার

রুবিতে বাইন্ডিং এবং লেক্সিকাল স্কোপ

শুভ নববর্ষ, এবং রুবি ম্যাজিকে আবার স্বাগতম! এই শীতের পর্বে, আমরা বাইন্ডিং এবং স্কোপের মধ্যে ডুব দেব। তাই আপনার স্কিস পরুন এবং বনের গভীরে আমাদের অনুসরণ করুন।

গতবার, আমরা ব্লক, প্রক্স এবং ল্যাম্বডাসের তুলনা করে রুবিতে বন্ধের দিকে তাকিয়েছিলাম। তিনটি প্রকারের মধ্যে পার্থক্য বাদ দিয়ে, আমরা একটি বন্ধ কে সংজ্ঞায়িত করে তা স্পর্শ করেছি .

একটি বন্ধ একটি পরিবেশ সহ একটি প্রথম শ্রেণীর ফাংশন. পরিবেশ হল ভেরিয়েবলের একটি ম্যাপিং যা বন্ধ করার সময় বিদ্যমান ছিল। ক্লোজার এই ভেরিয়েবলগুলিতে তার অ্যাক্সেস বজায় রাখে, এমনকি যদি সেগুলি অন্য স্কোপে সংজ্ঞায়িত করা হয়।

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

লেক্সিকাল স্কোপ

প্রোগ্রামিং-এ, স্কোপ বোঝায় বাইন্ডিং কোডের একটি নির্দিষ্ট অংশে উপলব্ধ। একটি বাঁধাই, বা নাম বাঁধাই , একটি মেমরি রেফারেন্সের সাথে একটি নাম আবদ্ধ করে, যেমন একটি ভেরিয়েবলের নামের সাথে এর মান। স্কোপ self কি তা সংজ্ঞায়িত করে মানে, যে পদ্ধতিগুলিকে বলা যেতে পারে, এবং যে ভেরিয়েবলগুলি উপলব্ধ৷

রুবি, বেশিরভাগ আধুনিক প্রোগ্রামিং ভাষার মতো, একটি স্ট্যাটিক স্কোপ ব্যবহার করে, প্রায়ই বলা হয় লেক্সিক্যাল স্কোপ (গতিশীল সুযোগের বিপরীতে)। বর্তমান সুযোগ কোডের কাঠামোর উপর ভিত্তি করে এবং কোডের নির্দিষ্ট অংশে উপলব্ধ ভেরিয়েবল নির্ধারণ করে। এর মানে হল কোড যখন পদ্ধতি, ব্লক এবং ক্লাসের মধ্যে জাম্প করে তখন সুযোগ পরিবর্তিত হয়—যেমন সেগুলির সকলের বিভিন্ন স্থানীয় ভেরিয়েবল থাকতে পারে, উদাহরণস্বরূপ।

def bar
  foo = 1
  foo
end
 
bar #  => 1

এই পদ্ধতিতে, আমরা একটি স্থানীয় পরিবর্তনশীল তৈরি করি একটি পদ্ধতির ভিতরে এবং এটি কনসোলে প্রিন্ট করুন। পরিবর্তনশীলটি ক্ষেত্রে পদ্ধতির ভিতরে, যেমন এটি সেখানে তৈরি করা হয়েছে।

foo = 1
 
def bar
  foo
end
 
bar # => NameError (undefined local variable or method `foo' for main:Object)

এই উদাহরণে, আমরা পদ্ধতির বাইরে ভেরিয়েবল তৈরি করি। যখন আমরা একটি পদ্ধতির ভিতরে ভেরিয়েবলকে কল করি, তখন আমরা একটি ত্রুটি পাই, কারণ ভেরিয়েবলটি ক্ষেত্রের বাইরে . স্থানীয় ভেরিয়েবলগুলি শক্তভাবে স্কোপ করা হয়, যার অর্থ একটি পদ্ধতি তার বাইরে একটি ভেরিয়েবল অ্যাক্সেস করতে পারে না যদি না এটি একটি যুক্তি হিসাবে পাস করা হয়৷

@foo = 1
 
def bar
  @foo
end
 
bar #  => 1

স্থানীয় ভেরিয়েবল স্থানীয়ভাবে উপলব্ধ থাকলেও, উদাহরণ ভেরিয়েবল একটি ক্লাস ইন্সট্যান্সের সমস্ত পদ্ধতিতে উপলব্ধ৷

উত্তরাধিকারসূত্রে প্রাপ্ত স্কোপ এবং প্রোক বাইন্ডিং

আমরা আগের উদাহরণগুলিতে দেখেছি, সুযোগটি কোডের অবস্থানের উপর ভিত্তি করে। একটি পদ্ধতির বাইরে সংজ্ঞায়িত একটি স্থানীয় ভেরিয়েবল পদ্ধতির অভ্যন্তরে নেই তবে এটিকে একটি ইনস্ট্যান্স ভেরিয়েবলে পরিণত করে উপলব্ধ করা যেতে পারে। পদ্ধতিগুলি তাদের বাইরে সংজ্ঞায়িত স্থানীয় ভেরিয়েবলগুলিতে অ্যাক্সেস করতে পারে না কারণ পদ্ধতিগুলির নিজস্ব ব্যাপ্তি রয়েছে, তাদের নিজস্ব বাইন্ডিং সহ৷

Procs (ব্লক এবং ল্যাম্বডা সহ, এক্সটেনশন দ্বারা) ভিন্ন। যখনই একটি proc ইনস্ট্যান্ট করা হয়, তখন একটি বাঁধাই তৈরি করা হয় যা ব্লকটি তৈরি করা প্রসঙ্গে স্থানীয় ভেরিয়েবলের রেফারেন্সগুলিকে উত্তরাধিকার সূত্রে দেয়৷

foo = 1
Proc.new { foo }.call # => 1

এই উদাহরণে, আমরা foo নামে একটি ভেরিয়েবল সেট করেছি 1 এ . অভ্যন্তরীণভাবে, দ্বিতীয় লাইনে তৈরি Proc বস্তুটি একটি নতুন বাঁধাই তৈরি করে। proc কল করার সময়, আমরা ভেরিয়েবলের মান চাইতে পারি।

যেহেতু বাইন্ডিং তৈরি হয় যখন proc আরম্ভ করা হয়, তাই আমরা ভেরিয়েবল সংজ্ঞায়িত করার আগে proc তৈরি করতে পারি না, এমনকি যদি ভেরিয়েবলটি সংজ্ঞায়িত না হওয়া পর্যন্ত ব্লকটি কল না করা হয়।

proc = Proc.new { foo }
foo = 1
proc.call # => NameError (undefined local variable or method `foo' for main:Object)

proc কল করা একটি NameError তৈরি করবে৷ যেহেতু ভেরিয়েবলটি proc এর বাইন্ডিংয়ে সংজ্ঞায়িত করা হয়নি। সুতরাং, একটি proc-এ অ্যাক্সেস করা যেকোন ভেরিয়েবলগুলিকে একটি আর্গুমেন্ট হিসাবে proc তৈরি বা পাস করার আগে সংজ্ঞায়িত করা উচিত৷

foo = 1
proc = Proc.new { foo }
foo = 2
proc.call # => 2

আমরা যাইহোক, পরিবর্তনশীলটিকে মূল প্রসঙ্গে সংজ্ঞায়িত করার পরে পরিবর্তন করতে পারি যেহেতু proc এর বাইন্ডিং এটিকে অনুলিপি করার পরিবর্তে এটির একটি রেফারেন্স রাখে৷

foo = 1
Proc.new { foo = 2 }.call
foo #=> 2

এই উদাহরণে, আমরা দেখতে পাচ্ছি যে foo ভেরিয়েবল একই বস্তুর দিকে নির্দেশ করে যখন এটির বাইরে proc-এ থাকে। আমরা এটিকে proc-এর ভিতরে আপডেট করতে পারি যাতে এর বাইরের পরিবর্তনশীলটিও আপডেট করা যায়।

বাইন্ডিং

বর্তমান সুযোগের ট্র্যাক রাখতে, রুবি বাইন্ডিং ব্যবহার করে , যা কোডের প্রতিটি অবস্থানে এক্সিকিউশন প্রসঙ্গকে এনক্যাপসুলেট করে। binding পদ্ধতি একটি binding প্রদান করে বস্তু যা বর্তমান অবস্থানে বাঁধাই বর্ণনা করে।

foo = 1
binding.local_variables # => [:foo]

বাইন্ডিং অবজেক্টের #local_variables নামে একটি পদ্ধতি রয়েছে যা বর্তমান সুযোগে উপলব্ধ সমস্ত স্থানীয় ভেরিয়েবলের নাম প্রদান করে।

foo = 1
binding.eval("foo") # => 1

#eval ব্যবহার করে বাইন্ডিংয়ে কোড মূল্যায়ন করা যেতে পারে পদ্ধতি উপরের উদাহরণটি খুব দরকারী নয়, যেমনটি কেবল foo কল করা একই ফলাফল হবে। যাইহোক, যেহেতু একটি বাইন্ডিং একটি বস্তু যা চারপাশে পাস করা যেতে পারে, এটি আরও কিছু আকর্ষণীয় জিনিসের জন্য ব্যবহার করা যেতে পারে। আসুন একটি উদাহরণ দেখি।

একটি বাস্তব-জীবনের উদাহরণ

এখন যেহেতু আমরা আমাদের গ্যারেজের নিরাপত্তায় বাঁধাই সম্পর্কে শিখেছি, যেমন সেগুলিকে ঢালে নিয়ে যাওয়া এবং বরফের মধ্যে খেলা করা। রুবির অভ্যন্তরীণ ভাষা জুড়ে বাঁধাইয়ের ব্যবহার ছাড়াও, এমন কিছু পরিস্থিতিতে রয়েছে যেখানে বাঁধাই বস্তুগুলি স্পষ্টভাবে ব্যবহার করা হয়। একটি ভাল উদাহরণ হল ERB—রুবির টেমপ্লেটিং সিস্টেম।

require 'erb'
 
x = 1
 
def y
  2
end
 
template = ERB.new("x is <%= x %>, y() returns <%= y %>, self is `<%= self %>`")
template.result(binding) # => "x is 1, y() returns 2, self is `main`"

এই উদাহরণে, আমরা x নামে একটি ভেরিয়েবল তৈরি করি , y নামে একটি পদ্ধতি , এবং একটি ERB টেমপ্লেট যা উভয়কেই উল্লেখ করে। তারপরে আমরা বর্তমান বাইন্ডিংটি ERB#result-এ পাস করি , যা টেমপ্লেটে ERB ট্যাগগুলিকে মূল্যায়ন করে এবং ভেরিয়েবলগুলি ভরাট করে একটি স্ট্রিং প্রদান করে৷

হুডের নিচে, ERB Binding#eval ব্যবহার করে পাস করা বাঁধাইয়ের সুযোগে প্রতিটি ERB ট্যাগের বিষয়বস্তু মূল্যায়ন করতে। একটি সরলীকৃত বাস্তবায়ন যা উপরের উদাহরণের জন্য কাজ করে তা দেখতে এইরকম হতে পারে:

class DiyErb
  def initialize(template)
    @template = template
  end
 
  def result(binding)
    @template.gsub(/<%=(.+?)%>/) do
      binding.eval($1)
    end
  end
end
 
x = 1
 
def y
  2
end
 
template = DiyErb.new("x is <%= x %>, y() returns <%= y %>, self is `<%= self %>`")
template.result(binding) # => "x is 1, y() returns 2, self is `main`"

DiyErb ক্লাস শুরুতে একটি টেমপ্লেট স্ট্রিং নেয়। এর #result পদ্ধতি সমস্ত ERB ট্যাগ খুঁজে পায় এবং তাদের বিষয়বস্তু মূল্যায়নের ফলাফল দিয়ে প্রতিস্থাপন করে। এটি করতে, এটি Binding#eval কল করে ERB ট্যাগের বিষয়বস্তু সহ পাস করা বাঁধাইয়ে।

#result কল করার সময় বর্তমান বাইন্ডিং পাস করে পদ্ধতি, eval কলগুলি স্পষ্টভাবে পাস না করেই পদ্ধতির বাইরে এবং এমনকি ক্লাসের বাইরেও সংজ্ঞায়িত ভেরিয়েবলগুলি অ্যাক্সেস করতে পারে৷

আমরা কি তোমাকে জঙ্গলে হারিয়েছি?

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

আমাদের অনুসরণ করার জন্য ধন্যবাদ এবং অনুগ্রহ করে পরবর্তী বিকাশকারীর জন্য ছেড়ে যাওয়ার আগে আপনার বাইন্ডিংগুলি থেকে তুষার সরিয়ে দিন। আপনি যদি এই জাদুকরী ভ্রমণগুলি পছন্দ করেন, আমরা মাসে একবার একটি নতুন নিবন্ধ প্রকাশ করলে একটি ই-মেইল পেতে আপনি রুবি ম্যাজিকের সদস্যতা নিতে পারেন৷


  1. RuboCop সহ রুবি কোড লিন্টিং এবং স্বয়ংক্রিয় ফর্ম্যাটিং

  2. Logger এবং Lograge সঙ্গে রুবি লগ ইন করুন

  3. কাফকা এবং রুবি, একটি সিডেকিক প্রেমের গল্প

  4. রুবিতে বন্ধ:ব্লক, প্রক্স এবং ল্যাম্বডাস