রুবির বহু প্রতীক্ষিত সংস্করণ 3.0.0 অবশেষে প্রকাশিত হয়েছে। পূর্ববর্তী সংস্করণের তুলনায় 3x দ্রুত কর্মক্ষমতা বৃদ্ধি, একযোগে-সমান্তরাল পরীক্ষামূলক বৈশিষ্ট্য ইত্যাদির মতো অনেক দুর্দান্ত উন্নতির পাশাপাশি, রুবি দল রুবিতে গতিশীল টাইপিংয়ের জন্য একটি নতুন সিনট্যাক্স ভাষাও চালু করেছে:RBS৷
এটি এমন একটি বিষয় যা দলটি বছরের পর বছর ধরে আলোচনা করে আসছিল, যা স্ট্যাটিক টাইপ চেকিং যেমন সরবেটের জন্য সম্প্রদায়-উন্নত সরঞ্জামগুলির সাফল্যের উপর ভিত্তি করে৷
শরবত একটি শক্তিশালী টাইপ চেকার যা স্ট্রাইপ দ্বারা সমর্থিত। এটি RBI ফাইলগুলিকে টীকা এবং/অথবা সংজ্ঞায়িত করে আপনার কোড পরীক্ষা করে। RBI ফাইলগুলি, স্থির এবং গতিশীল উপাদানগুলির মধ্যে ইন্টারফেস হিসাবে কাজ করে যা তাদের একটি "বিবরণ" প্রদান করে (ধ্রুবক, পূর্বপুরুষ, মেটাপ্রোগ্রামিং কোড এবং আরও অনেক কিছু)।
সুতরাং, যদি শরবত বেশিরভাগই স্ট্যাটিক চেকিং নিয়ে কাজ করে এবং আরবিএস ডায়নামিক টাইপিংয়ের জন্য তৈরি করা হয়, তাদের মধ্যে পার্থক্য কী? তারা উভয়ে কিভাবে সহাবস্থান করবে? আমি কখন অন্যটির পরিবর্তে একটি ব্যবহার করব?
RBS এর প্রধান ভূমিকা সম্পর্কে এগুলি মোটামুটি সাধারণ প্রশ্ন। এই কারণেই আমরা এই লেখাটি লেখার সিদ্ধান্ত নিয়েছি। স্পষ্ট করার জন্য, অনুশীলনে, কেন এটির সক্ষমতার উপর ভিত্তি করে এটি গ্রহণ করার কথা বিবেচনা করা উচিত। আসুন সরাসরি ভিতরে ডুব দিই!
বেসিক দিয়ে শুরু
চলুন শুরু করা যাক স্ট্যাটিক টাইপিং _এবং এর মধ্যে পার্থক্য সম্পর্কে একটি পরিষ্কার বোঝার সাথে গতিশীল টাইপিং_ যদিও এটি মৌলিক, RBS এর ভূমিকা বোঝার জন্য এটি একটি মূল ধারণা।
চলুন রেফারেন্স হিসাবে স্ট্যাটিকালি টাইপ করা ভাষা থেকে একটি কোড স্নিপেট নেওয়া যাক:
➜
String str = "";
str = 2.4;
এটা কোন খবর যে এই ধরনের একটি ভাষা তার বস্তু এবং ভেরিয়েবলের প্রকারের জন্য যত্নশীল। বলা হচ্ছে, উপরের একটির মত কোড একটি ত্রুটি নিক্ষেপ করবে।
রুবি, জাভাস্ক্রিপ্ট, পাইথন এবং অবজেক্টিভ-সি-এর মতো অন্যান্য ভাষার মতো, আপনি আপনার অবজেক্টের জন্য কোন ধরনের লক্ষ্য করছেন সেদিকে তেমন মনোযোগ দেয় না।
রুবিতে একই কোড সফলভাবে চলবে, যেমনটি নীচে দেখানো হয়েছে:
➜ irb
str = ""
str = 2.4
puts str # prints 2.4
এটি সম্ভব কারণ রুবির দোভাষী জানেন কিভাবে গতিশীলভাবে এক প্রকার থেকে অন্য প্রকারে স্যুইচ করুন।
যাইহোক, দোভাষী যা অনুমতি দেয় তার একটা সীমা আছে। উদাহরণস্বরূপ, নিম্নলিখিত কোড পরিবর্তন নিন:
➜ irb
val = "6.0"
result = val + 2.0
puts result
এটি, ঘুরে, নিম্নলিখিত ত্রুটি তৈরি করবে:
ত্রুটি:স্ট্রিং-এ ফ্লোটের কোনো অন্তর্নিহিত রূপান্তর নেই
জাভাস্ক্রিপ্টের সাথে একই কোড চালানো, উদাহরণস্বরূপ, ঠিকঠাক চলবে৷
৷গল্পের নৈতিকতা:রুবি গতিশীলভাবে প্রকারগুলি অনুমান করে, প্রকৃতপক্ষে; কিন্তু, অন্যান্য প্রধান গতিশীল ভাষার বিপরীতে, এটি সবকিছু গ্রহণ করবে না। সে সম্পর্কে সচেতন হোন!
এবং সেখানেই টাইপ চেকার (স্ট্যাটিক হোক বা ডাইনামিক) কাজে লাগে।
আরবিএস বনাম শরবত
ঠিক আছে, আমি গতিশীল বনাম স্ট্যাটিক জিনিস সম্পর্কে আপনার পয়েন্ট পেয়েছি। কিন্তু, শরবতের কী হবে? এটা কি অবমূল্যায়িত হবে?
একেবারেই না. আরবিএস এবং শরবতের মধ্যে প্রাথমিক (এবং সম্ভবত সবচেয়ে গুরুত্বপূর্ণ) পার্থক্য হল যে পূর্বেরটি শুধুমাত্র একটি ভাষা, যখন পরেরটি নিজেই একটি সম্পূর্ণ টাইপ চেকার।
রুবি দল RBS-এর মূল লক্ষ্যকে গঠন বর্ণনা বলে দাবি করে আপনার কোডের। এটি টাইপ চেকিং সঞ্চালন করবে না, বরং, টাইপ চেকার (যেমন শরবত বা অন্য কোন) টাইপ চেক করতে ব্যবহার করতে পারে এমন কাঠামো নির্ধারণ করুন। কোড গঠন একটি নতুন ফাইল এক্সটেনশন — .rbs-এর মধ্যে সংরক্ষণ করা হয় .
এটি পরীক্ষা করার জন্য, আসুন একটি উদাহরণ হিসাবে নিম্নলিখিত রুবি ক্লাসটি নেওয়া যাক:
class Super
def initialize(val)
@val = val
end
def val?
@val
end
end
class Test < Super
def initialize(val, flag)
super(val)
@flag = flag
end
def flag?
@flag
end
end
এটি রুবিতে একটি সাধারণ উত্তরাধিকার প্রতিনিধিত্ব করে। এখানে লক্ষণীয় আকর্ষণীয় বিষয় হল যে flag
ছাড়া আমরা ক্লাসে ব্যবহৃত প্রতিটি বৈশিষ্ট্যের ধরন অনুমান করতে পারি না .
যেহেতু flag
একটি ডিফল্ট মান দিয়ে শুরু হয়, ডেভেলপার এবং টাইপ পরীক্ষক উভয়ই আরও অপব্যবহার রোধ করতে টাইপ অনুমান করতে পারে।
RBS ফরম্যাটে উপরোক্ত শ্রেণীটির যথাযথ উপস্থাপনা নিম্নোক্ত হবে:
class Super
attr_reader val : untyped
def initialize : (val: untyped) -> void
end
class Test < Super
attr_reader flag : bool
def initialize : (val: untyped, ?flag: bool) -> void
def flag? : () -> bool
end
এটি হজম করতে কিছুটা সময় নিন। এটি একটি ঘোষণার ভাষা, তাই শুধুমাত্র স্বাক্ষর একটি RBS ফাইলে প্রদর্শিত হতে পারে। সহজ, তাই না?
এটি একটি CLI টুল দ্বারা স্বয়ংক্রিয়ভাবে জেনারেট করা হয়েছে (পরবর্তীতে আরও) বা আপনার দ্বারা, একটি প্রকারকে untyped
হিসাবে টীকা করা নিরাপদ। যখন অনুমান করা যায় না।
আপনি যদি val
এর ধরন সম্পর্কে নিশ্চিত হন , উদাহরণস্বরূপ, আপনার RBS ম্যাপিং নিম্নলিখিতগুলিতে স্যুইচ করা যেতে পারে:
class Super
attr_reader val : Integer
def initialize : (val: Integer) -> void
end
এটি লক্ষ করাও গুরুত্বপূর্ণ যে রুবি এবং শরবেট উভয় দলই RBS তৈরি এবং উন্নতির দিকে কাজ করছিল (এবং এখনও আছে)। বছরের পর বছর ধরে সার্বেট টিমের টাইপ চেকিংয়ের অভিজ্ঞতা ছিল, যা রুবি টিমকে এই প্রকল্পের সাথে অনেক কিছু ঠিক করতে সাহায্য করেছিল।
আরবিএস এবং আরবিআই ফাইলগুলির মধ্যে আন্তঃকার্যক্ষমতা এখনও বিকাশাধীন। লক্ষ্য হল শরবত এবং অন্য যেকোনো চেকার টুলের জন্য একটি অফিসিয়াল এবং কেন্দ্রীভূত ভিত্তি অনুসরণ করা।
RBS CLI টুল
RBS ডেভেলপ করার সময় রুবি দলের একটি গুরুত্বপূর্ণ বিবেচনা ছিল একটি CLI টুল পাঠানো যা ডেভেলপারদের এটি ব্যবহার করে দেখতে এবং কীভাবে এটি ব্যবহার করতে হয় তা শিখতে সাহায্য করতে পারে। একে rbs বলা হয় এবং রুবি 3 এর সাথে ডিফল্টরূপে আসে। আপনি যদি এখনও আপনার রুবি সংস্করণ আপগ্রেড না করে থাকেন, তাহলে আপনি সরাসরি আপনার প্রকল্পে এটির মণি যোগ করতে পারেন:
➜ gem install rbs
কমান্ড rbs help
উপলব্ধ কমান্ডের সাথে কমান্ডের ব্যবহার দেখাবে।
উপলব্ধ কমান্ডের তালিকা
এই কমান্ডগুলির বেশিরভাগই রুবি কোড স্ট্রাকচার পার্সিং এবং বিশ্লেষণের উপর ফোকাস করে। উদাহরণস্বরূপ, ancestors
কমান্ড একটি প্রদত্ত শ্রেণির শ্রেণীবিন্যাসের কাঠামোকে তার পূর্বপুরুষের জন্য পরীক্ষা করে:
➜ rbs ancestors ::String
::String
::Comparable
::Object
::Kernel
::BasicObject
কমান্ড methods
একটি প্রদত্ত শ্রেণীর সমস্ত পদ্ধতি কাঠামো প্রদর্শন করে:
➜ rbs methods ::String
! (public)
!= (public)
!~ (public)
...
Array (private)
Complex (private)
Float (private)
...
autoload? (private)
b (public)
between? (public)
...
একটি নির্দিষ্ট পদ্ধতি কাঠামো দেখতে চান? methods
এ যান :
➜ rbs method ::String split
::String#split
defined_in: ::String
implementation: ::String
accessibility: public
types:
(?::Regexp | ::string pattern, ?::int limit) -> ::Array[::String]
| (?::Regexp | ::string pattern, ?::int limit) { (::String) -> void } -> self
যারা আজ RBS দিয়ে শুরু করছেন তাদের জন্য, কমান্ড prototype
ইতিমধ্যে বিদ্যমান ক্লাসের জন্য ভারা ধরনের সঙ্গে অনেক সাহায্য করতে পারে. কমান্ড RBS ফাইলের প্রোটোটাইপ তৈরি করে।
আগের Test < Super
নেওয়া যাক উত্তরাধিকার উদাহরণ এবং appsignal.rb নামে একটি ফাইলে কোড সংরক্ষণ করুন . তারপর, নিম্নলিখিত কমান্ডটি চালান:
➜ rbs prototype rb appsignal.rb
যেহেতু কমান্ড rb এর জন্য অনুমতি দেয় , rbi , এবং রানটাইম জেনারেটর, আপনাকে prototype
-এর ঠিক পরেই আপনি যে নির্দিষ্ট ধরনের ফাইল ভারাচ্ছেন তা প্রদান করতে হবে কমান্ড, ফাইলের পাথনেম দ্বারা অনুসরণ করুন।
নিম্নোক্ত মৃত্যুদন্ডের ফলাফল:
class Super
def initialize: (untyped val) -> untyped
def val?: () -> untyped
end
class Test < Super
def initialize: (untyped val, ?flag: bool flag) -> untyped
def flag?: () -> untyped
end
আমাদের প্রথম আরবিএস সংস্করণের মতোই। আগেই উল্লেখ করা হয়েছে, টুলটি untyped
হিসেবে চিহ্নিত যে কোন প্রকার অনুমান করা যায়নি।
এটি পদ্ধতি রিটার্নের জন্যও গণনা করে। flag
এর রিটার্ন টাইপ লক্ষ্য করুন সংজ্ঞা একজন বিকাশকারী হিসাবে, আপনি সম্ভবত নিশ্চিত যে পদ্ধতিটি সর্বদা একটি বুলিয়ান প্রদান করে, কিন্তু রুবির গতিশীল প্রকৃতির কারণে, টুলটি 100% বলতে অক্ষম যে এটি তাই।
এবং তখনই আরেকটি রুবি 3 শিশু উদ্ধারে আসে:TypeProf.
TypeProf টুল
TypeProf হল রুবির জন্য একটি টাইপ বিশ্লেষণ টুল যা কিছু সিনট্যাক্স ট্রি ব্যাখ্যার উপরে তৈরি করা হয়েছিল।
এখনও পরীক্ষামূলক হওয়া সত্ত্বেও, আপনার কোড কী করার চেষ্টা করছে তা বোঝার ক্ষেত্রে এটি অত্যন্ত শক্তিশালী বলে প্রমাণিত হয়েছে৷
আপনার যদি এখনও রুবি 3 না থাকে, তাহলে কেবল আপনার প্রকল্পে রত্নটি যোগ করুন:
➜ gem install typeprof
এখন, একই appsignal.rb চালাই এর বিরুদ্ধে ফাইল করুন:
➜ typeprof appsignal.rb
এটি হল আউটপুট:
# Classes
class Super
@val: untyped
def initialize: (untyped) -> untyped
def val?: -> untyped
end
class Test < Super
@val: untyped
@flag: true
def initialize: (untyped, ?flag: true) -> true
def flag?: -> true
end
কিভাবে flag
লক্ষ্য করুন এখন ম্যাপ করা হয়। এটি শুধুমাত্র সম্ভব কারণ, RBS প্রোটোটাইপ যা করে তার বিপরীতে, TypeProf সেই নির্দিষ্ট ভেরিয়েবলের উপর কী কাজ করা হচ্ছে তা বোঝার চেষ্টা করে পদ্ধতির বডি স্ক্যান করে। যেহেতু এটি এই ভেরিয়েবলের কোন সরাসরি পরিবর্তন সনাক্ত করতে পারেনি, তাই TypeProf নিরাপদে পদ্ধতি রিটার্নটিকে বুলিয়ান হিসাবে ম্যাপ করেছে৷
উদাহরণ স্বরূপ, ধরুন যে TypeProf অন্য ক্লাসে অ্যাক্সেস পাবে যেগুলি তাৎক্ষণিক এবং Test
ব্যবহার করে ক্লাস এটি হাতে রেখে, এটি আপনার কোডের আরও গভীরে যেতে পারে এবং এর ভবিষ্যদ্বাণীগুলিকে সূক্ষ্ম সুর করতে পারে৷ বলুন যে appsignal.rb-এর শেষে নিম্নলিখিত কোড স্নিপেট যোগ করা হয়েছে ফাইল:
testSub = Test.new("My value", "My value" == "")
testSup = Super.new("My value")
এবং আপনি initialize
পরিবর্তন করেছেন পদ্ধতি স্বাক্ষর নিম্নলিখিত:
def initialize(val, flag)
যখন আপনি কমান্ড পুনরায় চালান, এটি আউটপুট হওয়া উচিত:
# Classes
class Super
@val: String
def initialize: (String) -> String
def val?: -> String
end
class Test < Super
@val: String
@flag: bool
def initialize: (String val, bool flag) -> bool
def flag?: -> bool
end
সুপার কুল!
TypeProf উত্তরাধিকারসূত্রে প্রাপ্ত বৈশিষ্ট্যগুলিকে খুব ভালভাবে মোকাবেলা করতে পারে না। তাই আমরা একটি নতুন Super
চালু করছি বস্তু অন্যথায়, এটি সেই val
পাবে না একটি String
.
TypeProf এর প্রধান প্রো হল এর নিরাপত্তা। যখনই এটি নিশ্চিতভাবে কিছু বের করতে অক্ষম হয়, তখন untyped
ফেরত দেওয়া হবে।
আংশিক RBS স্পেসিফিকেশন
অফিসিয়াল ডক্স থেকে একটি গুরুত্বপূর্ণ সতর্কবার্তায় বলা হয়েছে যে, যদিও TypeProf খুবই শক্তিশালী, RBS কোডের পরিপ্রেক্ষিতে এটি কী তৈরি করতে পারে এবং কী করতে পারে না সে সম্পর্কে আপনার সীমাবদ্ধতা সম্পর্কে সচেতন হওয়া উচিত।
উদাহরণস্বরূপ, রুবি ডেভেলপারদের মধ্যে একটি সাধারণ অভ্যাস হল মেথড ওভারলোডিং যেখানে আপনি একটি পদ্ধতির আর্গুমেন্টের উপর নির্ভর করে ভিন্ন ভিন্ন আচরণের আহ্বান জানান।
একটি নতুন পদ্ধতি spell
বিবেচনা করুন Super
-এ যোগ করা হয়েছে ক্লাস, যা একটি Integer
প্রদান করে অথবা একটি String
পরামিতি প্রকারের উপর ভিত্তি করে:
def spell(val)
if val.is_a?(String)
""
else
0
end
end
RBS আপনাকে ইউনিয়ন টাইপ (একটি মান যা একাধিক সম্ভাব্য প্রকারের প্রতিনিধিত্ব করে) সিনট্যাক্সের মাধ্যমে ওভারলোডিং মোকাবেলা করার অনুমতি দিয়ে এই অনুশীলনটি গ্রহণ করে:
def spell: (String) -> String | (Integer) -> Integer
TypeProf শুধুমাত্র পদ্ধতির শরীর বিশ্লেষণ করে এটি অনুমান করতে পারে না। এটিকে সাহায্য করার জন্য, আপনি ম্যানুয়ালি আপনার RBS ফাইলে এই ধরনের একটি সংজ্ঞা যোগ করতে পারেন এবং TypeProf সর্বদা নির্দেশাবলীর জন্য প্রথমে সেখানে পরীক্ষা করবে।
এর জন্য, আপনাকে কমান্ডের শেষে RBS ফাইল পাথ যোগ করতে হবে:
typeprof appsignal.rb appsignal.rbs
নতুন আউটপুট নীচে দেখুন:
class Super
...
def spell: (untyped val) -> (Integer | String)
end
এছাড়াও, আমরা Kernel#p
-এর মাধ্যমে রানটাইমের সময় প্রকৃত প্রকারগুলি যাচাই করতে পারি appsignal.rb-এর শেষে পরবর্তী দুটি লাইন যোগ করে ওভারলোডিং কাজ করছে কিনা তা পরীক্ষা করতে ফাইল:
p testSup.spell(42)
p testSup.spell("str")
এটি আউটপুট হওয়া উচিত:
# Revealed types
# appsignal.rb:11 #=> Integer
# appsignal.rb:12 #=> String
...
আরও তথ্যের জন্য অফিসিয়াল ডক্স উল্লেখ করতে ভুলবেন না, বিশেষ করে TypeProf সীমাবদ্ধতা সংক্রান্ত বিভাগ।
হাঁস টাইপিং
আপনি আগে যে শুনেছেন. যদি একটি রুবি বস্তু একটি হাঁস যা কিছু করে, তবে এটি একটি হাঁস৷
যেমনটি আমরা দেখেছি, রুবি আপনার বস্তুগুলিকে কী বোঝানো হয়েছে তা নিয়ে চিন্তা করে না। প্রকারগুলি গতিশীলভাবে পরিবর্তন করতে পারে সেইসাথে বস্তুর উল্লেখও।
যদিও সহায়ক, হাঁসের টাইপিং কঠিন হতে পারে। আসুন একটি উদাহরণ দেখি।
ধরুন, এখন থেকে, val
আপনি Super
-এর জন্য ঘোষণা করেছেন এমন বৈশিষ্ট্য ক্লাস, যা একটি String
, সর্বদা একটি পূর্ণসংখ্যাতে রূপান্তরযোগ্য হতে হবে।
বিকাশকারীরা সর্বদা রূপান্তরের গ্যারান্টি দেবে বলে বিশ্বাস করার পরিবর্তে (হয়তো, অন্যথায় একটি ত্রুটি নিক্ষেপ), আপনি একটি ইন্টারফেস তৈরি করতে পারেন উল্লেখ করে যে:
interface _IntegerConvertible
def to_int: () -> Integer
end
ইন্টারফেসের প্রকারগুলি এক বা একাধিক পদ্ধতি প্রদান করে যা কংক্রিট ক্লাস এবং মডিউলগুলি থেকে বিচ্ছিন্ন। এইভাবে, আপনি যখন একটি নির্দিষ্ট প্রকারকে সুপার ইন্সট্যান্টিয়েশনে প্রেরণ করতে চান, তখন আপনি কেবল নিম্নলিখিতগুলি করতে পারেন:
class Super
attr_reader val : _IntegerConvertible
def initialize : (val: _IntegerConvertible) -> void
end
কংক্রিট ক্লাস বা মডিউল যা এই ইন্টারফেসটি প্রয়োগ করে তা নিশ্চিত করতে হবে যে সঠিক বৈধতা সম্পন্ন হয়েছে৷
মেটাপ্রোগ্রামিং
সম্ভবত রুবির সবচেয়ে গতিশীল বৈশিষ্ট্যগুলির মধ্যে একটি হল কোড তৈরি করার ক্ষমতা যা রানটাইমের সময় নিজেই কোড তৈরি করে। এটি মেটাপ্রোগ্রামিং।
জিনিসের অনিশ্চিত প্রকৃতির কারণে, RBS CLI টুল মেটাপ্রোগ্রামিং কোডের বাইরে RBS তৈরি করতে সক্ষম নয়।
একটি উদাহরণ হিসাবে নিম্নলিখিত স্নিপেট নেওয়া যাক:
class Test
define_method :multiply do |*args|
args.inject(1, :*)
end
end
p Test.new.multiply(2, 3, 5)
এই শ্রেণীটি multiply
নামে একটি পদ্ধতিকে সংজ্ঞায়িত করে রানটাইমে এবং আর্গুমেন্টগুলি ইনজেক্ট করার জন্য এবং প্রতিটিকে পূর্ববর্তী ফলাফলের সাথে গুণ করার নির্দেশ দেয়৷
একবার আপনি RBS prototype
চালান কমান্ড, এটি আউটপুট হওয়া উচিত:
class Test
end
আপনার মেটাপ্রোগ্রামিং কোডের জটিলতার উপর নির্ভর করে, TypeProf এখনও এটি থেকে কিছু বের করার জন্য যথাসাধ্য চেষ্টা করবে। কিন্তু এটা সবসময় নিশ্চিত নয়।
মনে রাখবেন, আপনি সবসময় RBS ফাইলে আপনার নিজস্ব টাইপ ম্যাপিং যোগ করতে পারেন এবং TypeProf সেগুলি আগে থেকেই মেনে চলবে। এটি মেটাপ্রোগ্রামিংয়ের জন্যও বৈধ।
সর্বশেষ সংগ্রহস্থল পরিবর্তনের সাথে আপডেট রাখাও গুরুত্বপূর্ণ কারণ দলটি ক্রমাগত নতুন বৈশিষ্ট্য প্রকাশ করছে, যার মধ্যে মেটাপ্রোগ্রামিং-এর আপডেট অন্তর্ভুক্ত থাকতে পারে।
এটি বলা হচ্ছে, যদি আপনার কোডবেসে কিছু ধরণের মেটাপ্রোগ্রামিং অন্তর্ভুক্ত থাকে তবে এই সরঞ্জামগুলির সাথে সতর্ক থাকুন। অন্ধভাবে তাদের ব্যবহার করবেন না!
র্যাপিং আপ
আমরা এখন পর্যন্ত যা আলোচনা করেছি সে সম্পর্কে আরও অনেক বিশদ বিবরণ রয়েছে, সেইসাথে RBS এবং TypeProf উভয়ের ক্ষেত্রেই এজ ব্যবহারের ক্ষেত্রে যা আপনার সচেতন হওয়া উচিত।
সুতরাং, এটি সম্পর্কে আরও জানতে অফিসিয়াল ডক্স উল্লেখ করতে ভুলবেন না।
RBS এখনও অনেক তাজা কিন্তু ইতিমধ্যেই রুবিস্টদের উপর ব্যাপক প্রভাব ফেলেছে যেগুলি অন্যান্য সরঞ্জামগুলির সাথে তাদের কোডবেসগুলি টাইপ করতে ব্যবহৃত হয়৷
তোমার খবর কি? আপনি এটা চেষ্টা করে দেখেছেন? RBS সম্পর্কে আপনার চিন্তা কি?
পি.এস. আপনি যদি রুবি ম্যাজিক পোস্টগুলি প্রেস থেকে বের হওয়ার সাথে সাথে পড়তে চান তবে আমাদের রুবি ম্যাজিক নিউজলেটারে সাবস্ক্রাইব করুন এবং একটি পোস্টও মিস করবেন না!