रूबी का लंबे समय से प्रतीक्षित संस्करण 3.0.0 आखिरकार जारी कर दिया गया है। कई बेहतरीन सुधारों के साथ, जैसे पिछले संस्करण की तुलना में 3 गुना तेज प्रदर्शन बूस्ट, समांतर-समानांतर प्रयोगात्मक सुविधाएं इत्यादि, रूबी टीम ने रूबी में गतिशील टाइपिंग के लिए एक नई वाक्यविन्यास भाषा भी पेश की:आरबीएस।
शर्बत जैसे स्थैतिक प्रकार की जाँच के लिए समुदाय द्वारा विकसित उपकरणों की सफलता के आधार पर, टीम वर्षों से इस पर चर्चा कर रही थी।
शर्बत स्ट्राइप द्वारा समर्थित एक शक्तिशाली प्रकार का चेकर है। यह आरबीआई फाइलों को एनोटेट और/या परिभाषित दोनों करके आपके कोड की जांच करता है। आरबीआई फाइलें, बदले में, स्थिर और गतिशील घटकों के बीच इंटरफेस के रूप में काम करती हैं, जो उनका "विवरण" प्रदान करती हैं (स्थिरांक, पूर्वज, मेटाप्रोग्रामिंग कोड, और बहुत कुछ)।
तो, अगर शर्बत ज्यादातर स्थैतिक जाँच से संबंधित है और आरबीएस को गतिशील टाइपिंग को संबोधित करने के लिए बनाया गया था, तो उनके बीच क्या अंतर है? वे दोनों एक साथ कैसे रहेंगे? मुझे एक के बजाय दूसरे का उपयोग कब करना चाहिए?
आरबीएस की प्रमुख भूमिका के बारे में ये काफी सामान्य प्रश्न हैं। इसलिए हमने इस टुकड़े को लिखने का फैसला किया। स्पष्ट करने के लिए, व्यवहार में, आपको इसे अपनी क्षमता के आधार पर अपनाने पर विचार क्यों करना चाहिए। चलो सही में गोता लगाएँ!
बुनियादी बातों से शुरू करना
आइए स्थिर टाइपिंग _और . के बीच अंतर की स्पष्ट समझ के साथ शुरुआत करें गतिशील टाइपिंग_. हालांकि यह बुनियादी है, लेकिन आरबीएस की भूमिका को समझने के लिए इसे समझना एक महत्वपूर्ण अवधारणा है।
आइए एक संदर्भ के रूप में एक सांख्यिकीय रूप से टाइप की गई भाषा से एक कोड स्निपेट लें:
➜
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 ।
इसे जांचने के लिए, निम्नलिखित रूबी वर्ग को एक उदाहरण के रूप में लेते हैं:
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
डिफ़ॉल्ट मान के साथ इनिशियलाइज़ किया जाता है, डेवलपर और टाइप चेकर दोनों ही प्रकार का अनुमान लगा सकते हैं ताकि आगे के दुरुपयोग को रोका जा सके।
निम्नलिखित आरबीएस प्रारूप में उपरोक्त वर्ग का उचित प्रतिनिधित्व होगा:
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 फ़ाइल में केवल हस्ताक्षर दिखाई दे सकते हैं। आसान है, है ना?
चाहे वह किसी सीएलआई उपकरण (उस पर बाद में अधिक) द्वारा स्वत:उत्पन्न हुआ हो या आपके द्वारा, किसी प्रकार को untyped
के रूप में एनोटेट करना अधिक सुरक्षित है जब इसका अनुमान नहीं लगाया जा सकता है।
यदि आप val
. के प्रकार के बारे में सुनिश्चित हैं , उदाहरण के लिए, आपकी RBS मैपिंग को निम्न पर स्विच किया जा सकता है:
class Super
attr_reader val : Integer
def initialize : (val: Integer) -> void
end
यह भी ध्यान रखना महत्वपूर्ण है कि रूबी और शर्बत दोनों टीमें आरबीएस के निर्माण और सुधार की दिशा में काम कर रही थीं (और अभी भी हैं)। सालों से टाइप चेकिंग के साथ सॉर्बेट टीम के अनुभव ने रूबी टीम को इस प्रोजेक्ट के साथ बहुत सी चीजों को ठीक करने में मदद की।
आरबीएस और आरबीआई फाइलों के बीच इंटरऑपरेबिलिटी अभी भी विकास के अधीन है। लक्ष्य यह है कि सॉर्बेट और किसी भी अन्य चेकर टूल का पालन करने के लिए आधिकारिक और केंद्रीकृत आधार हो।
आरबीएस सीएलआई टूल
आरबीएस विकसित करते समय रूबी टीम के पास एक महत्वपूर्ण विचार था कि एक सीएलआई उपकरण शिप किया जाए जो डेवलपर्स को इसे आज़माने और इसका उपयोग करने का तरीका सीखने में मदद कर सके। इसे 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)
...
एक विशिष्ट विधि संरचना देखना चाहते हैं? method
के लिए जाएं :
➜ 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
आज आरबीएस से शुरुआत करने वालों के लिए कमांड prototype
पहले से मौजूद कक्षाओं के लिए मचान प्रकारों के साथ बहुत मदद कर सकता है। कमांड आरबीएस फाइलों के प्रोटोटाइप तैयार करता है।
आइए पिछला Test < Super
take लें विरासत उदाहरण और कोड को appsignal.rb . नामक फ़ाइल में सहेजें . फिर, निम्न कमांड चलाएँ:
➜ rbs prototype rb appsignal.rb
चूंकि कमांड rb . के लिए अनुमति देता है , आरबीआई , और रनटाइम जनरेटर, आपको 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
as के रूप में चिह्नित करता है किसी भी प्रकार का अनुमान नहीं लगाया जा सकता है।
यह विधि रिटर्न के लिए भी मायने रखता है। flag
के वापसी प्रकार पर ध्यान दें परिभाषा। एक डेवलपर के रूप में, आप शायद सुनिश्चित हैं कि विधि हमेशा एक बूलियन लौटाती है, लेकिन रूबी की गतिशील प्रकृति के कारण, टूल 100% यह कहने में असमर्थ है कि ऐसा है।
और वह तब होता है जब एक और रूबी 3 बच्चा बचाव के लिए आता है:टाइपप्रोफ।
टाइपप्रोफ टूल
टाइपप्रोफ रूबी के लिए एक प्रकार का विश्लेषण उपकरण है जिसे कुछ सिंटैक्स ट्री व्याख्या के शीर्ष पर बनाया गया था।
अभी भी प्रयोगात्मक होने के बावजूद, जब यह समझने की बात आती है कि आपका कोड क्या करने की कोशिश कर रहा है तो यह बहुत शक्तिशाली साबित हुआ है।
यदि आपके पास अभी तक रूबी 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
अब मैप किया गया है। यह केवल इसलिए संभव है क्योंकि, आरबीएस प्रोटोटाइप के विपरीत, टाइपप्रोफ विधि के शरीर को यह समझने की कोशिश कर रहा है कि उस विशिष्ट चर पर कौन सी क्रियाएं की जा रही हैं। चूंकि यह इस चर में किसी भी प्रत्यक्ष परिवर्तन की पहचान नहीं कर सका, इसलिए 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
बहुत बढ़िया!
टाइपप्रोफ विरासत में मिली विशेषताओं से बहुत अच्छी तरह से निपट नहीं सकता है। इसलिए हम एक नया Super
इंस्टेंट कर रहे हैं वस्तु। अन्यथा, वह val
नहीं मिलेगा एक String
है ।
TypeProf का प्रमुख लाभ इसकी सुरक्षा है। जब भी यह निश्चित रूप से कुछ पता लगाने में असमर्थ होता है, तो untyped
वापस कर दिया जाएगा।
आंशिक RBS विशिष्टता
आधिकारिक डॉक्स से एक महत्वपूर्ण चेतावनी में कहा गया है कि, हालांकि टाइपप्रोफ बहुत शक्तिशाली है, आपको इसकी सीमाओं के बारे में पता होना चाहिए कि यह आरबीएस कोड के संदर्भ में क्या उत्पन्न कर सकता है और क्या नहीं।
उदाहरण के लिए, रूबी डेवलपर्स के बीच एक सामान्य अभ्यास विधि ओवरलोडिंग है जिसमें आप एक विधि के विभिन्न व्यवहारों को उसके तर्कों के आधार पर लागू करते हैं।
विचार करें कि एक नई विधि spell
Super
. में जोड़ा जाता है क्लास, जो एक Integer
returns देता है या एक String
पैरामीटर प्रकार के आधार पर:
def spell(val)
if val.is_a?(String)
""
else
0
end
end
RBS आपको संघ प्रकार (एक मान जो कई संभावित प्रकारों का प्रतिनिधित्व करता है) के माध्यम से ओवरलोडिंग से निपटने की अनुमति देकर इस अभ्यास को अपनाता है:
def spell: (String) -> String | (Integer) -> Integer
टाइपप्रोफ केवल विधि के शरीर का विश्लेषण करके इसका अनुमान नहीं लगा सकता है। इसमें मदद करने के लिए, आप मैन्युअल रूप से अपनी 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
...
अधिक जानकारी के लिए आधिकारिक दस्तावेज़ों को देखना सुनिश्चित करें, विशेष रूप से टाइपप्रोफ सीमाओं से संबंधित अनुभाग।
बतख टाइपिंग
आपने इसके बारे में पहले सुना है। यदि एक रूबी वस्तु वह सब कुछ करती है जो एक बतख करता है, तो वह एक बतख है।
जैसा कि हमने देखा है, रूबी इस बात की परवाह नहीं करती है कि आपकी वस्तुओं का क्या मतलब है। प्रकार गतिशील रूप से और साथ ही वस्तु संदर्भ बदल सकते हैं।
हालांकि मददगार, बतख टाइपिंग मुश्किल हो सकती है। आइए एक उदाहरण देखें।
मान लीजिए कि, अब से, val
विशेषता जिसे आपने Super
. के लिए घोषित किया है क्लास, जो एक String
है , हमेशा एक पूर्णांक में परिवर्तनीय होना चाहिए।
यह विश्वास करने के बजाय कि डेवलपर हमेशा रूपांतरण की गारंटी देंगे (शायद, कोई त्रुटि फेंकना अन्यथा), आप एक इंटरफ़ेस बना सकते हैं यह बताते हुए कि:
interface _IntegerConvertible
def to_int: () -> Integer
end
इंटरफ़ेस प्रकार एक या अधिक विधियाँ प्रदान करते हैं जो ठोस कक्षाओं और मॉड्यूल से अलग होती हैं। इस तरह, जब आप चाहते हैं कि एक निश्चित प्रकार सुपर इंस्टेंटेशन को पास किया जाए, तो आप बस निम्न कार्य कर सकते हैं:
class Super
attr_reader val : _IntegerConvertible
def initialize : (val: _IntegerConvertible) -> void
end
इस इंटरफ़ेस को लागू करने वाले ठोस वर्ग या मॉड्यूल को यह सुनिश्चित करना होगा कि उचित सत्यापन किया गया है।
मेटाप्रोग्रामिंग
शायद रूबी की सबसे गतिशील विशेषताओं में से एक कोड बनाने की क्षमता है जो रनटाइम के दौरान स्वयं कोड बनाता है। वह मेटाप्रोग्रामिंग है।
चीजों की अनिश्चित प्रकृति के कारण, आरबीएस सीएलआई उपकरण मेटाप्रोग्रामिंग कोड से आरबीएस उत्पन्न करने में सक्षम नहीं है।
आइए निम्नलिखित स्निपेट को एक उदाहरण के रूप में लें:
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 अभी भी इससे कुछ निकालने की पूरी कोशिश करेगा। लेकिन इसकी हमेशा गारंटी नहीं होती है।
याद रखें, आप हमेशा अपनी खुद की टाइप मैपिंग को आरबीएस फाइल में जोड़ सकते हैं और टाइपप्रोफ पहले से उनका पालन करेगा। यह मेटाप्रोग्रामिंग के लिए भी मान्य है।
नवीनतम रिपॉजिटरी परिवर्तनों के साथ अपडेट रहना भी महत्वपूर्ण है क्योंकि टीम लगातार नई सुविधाएँ जारी कर रही है, जिसमें मेटाप्रोग्रामिंग पर अपडेट भी शामिल हो सकते हैं।
कहा जा रहा है, यदि आपके कोडबेस में कुछ प्रकार के मेटाप्रोग्रामिंग शामिल हैं, तो इन उपकरणों से सावधान रहें। आँख बंद करके उनका उपयोग न करें!
रैपिंग अप
अब तक हमने जो चर्चा की है, उसके बारे में और भी बहुत सारे विवरण हैं, साथ ही आरबीएस और टाइपप्रोफ दोनों के लिए एज उपयोग के मामले भी हैं जिनसे आपको अवगत होना चाहिए।
इसलिए, उस पर अधिक जानकारी के लिए आधिकारिक दस्तावेज़ों को देखना सुनिश्चित करें।
आरबीएस अभी भी इतना ताज़ा है, लेकिन पहले से ही रूबीवादियों पर एक बड़ा प्रभाव डाल चुका है जो कि अन्य उपकरणों के साथ अपने कोडबेस की जांच करने के लिए उपयोग किए जाते हैं।
आप क्या कहते हैं? क्या आपने इसे आजमाया है? आरबीएस पर आपके क्या विचार हैं?
पी.एस. यदि आप रूबी मैजिक की पोस्ट प्रेस से बाहर होते ही पढ़ना चाहते हैं, तो हमारे रूबी मैजिक न्यूजलेटर की सदस्यता लें और एक भी पोस्ट मिस न करें!