मान लीजिए कि आप अपने सोर्स कोड को पार्स करके अपने सभी मेथड्स ढूंढना चाहते हैं, वे कहां परिभाषित हैं और वे कौन से तर्क लेते हैं।
आप यह कैसे कर सकते हैं?
आपका पहला विचार इसके लिए एक रेगेक्स लिखना हो सकता है…
लेकिन क्या कोई बेहतर तरीका है?

हाँ!
स्टैटिक एनालिसिस एक तकनीक है जिसका उपयोग आप तब कर सकते हैं जब आपको सोर्स कोड से जानकारी निकालने की आवश्यकता होती है।
यह सोर्स कोड को टोकन्स में बदलकर किया जाता है (पार्सिंग)।
चलिए सीधे इसमें कूदते हैं!
पार्सर जेम का उपयोग करना
रूबी के स्टैंडर्ड लाइब्रेरी पर एक पार्सर उपलब्ध है, नाम है Ripper। आउटपुट के साथ काम करना कठिन है इसलिए मैं शानदार पार्सर जेम का उपयोग करना पसंद करता हूँ। Rubocop इस जेम का उपयोग अपना जादू करने के लिए करता है।
इस जेम में एक बाइनरी भी शामिल है जिसका उपयोग आप सीधे कुछ कोड को पार्स करने और परिणामी पार्स ट्री को देखने के लिए कर सकते हैं।
यहां एक उदाहरण है:
ruby-parse -e '%w(hello world).map { |c| c.upcase }'
आउटपुट ऐसा दिखता है:
(block (send (array (str "hello") (str "world")) :map) (args (arg :c)) (send (lvar :c) :upcase))
यह उपयोगी हो सकता है यदि आप यह समझने की कोशिश कर रहे हैं कि रूबी कुछ कोड को कैसे पार्स करता है। लेकिन यदि आप अपने खुद के विश्लेषण टूल्स बनाना चाहते हैं तो आपको सोर्स फाइल पढ़नी होगी, इसे पार्स करना होगा और फिर उत्पन्न ट्री को ट्रैवर्स करना होगा।
उदाहरण:
require 'parser/current'
code = File.read('app.rb')
parsed_code = Parser::CurrentRuby.parse(code)
पार्सर आपके कोड का AST (एब्स्ट्रैक्ट सिंटैक्स ट्री) लौटाएगा। नाम से बहुत भयभीत न हों, यह जितना लगता है उससे सरल है 🙂
AST को ट्रैवर्स करना
अब जब आपने पार्सर जेम का उपयोग करके अपना कोड पार्स कर लिया है तो आपको परिणामी AST को ट्रैवर्स करने की आवश्यकता है।
आप एक क्लास बनाकर ऐसा कर सकते हैं जो AST::Processor से विरासत में मिली हो।
उदाहरण:
class Processor < AST::Processor end
फिर आपको इस क्लास को इंस्टेंटिएट करना होगा और .process मेथड कॉल करना होगा:
ast = Processor.new ast.process(parsed_code)
आपको कुछ on_ मेथड्स परिभाषित करने होंगे। ये मेथड्स AST में नोड नामों से मेल खाते हैं।
यह पता लगाने के लिए कि आपको कौन से मेथड्स परिभाषित करने हैं, आप अपने Processor क्लास में handler_missing मेथड जोड़ सकते हैं। आपको on_begin मेथड की भी आवश्यकता है।
class Processor < AST::Processor
def on_begin(node)
node.children.each { |c| process(c) }
end
def handler_missing(node)
puts "missing #{node.type}"
end
end
यहां हम हैं:
आपके पास आपका रूबी AST और एक बेसिक प्रोसेसर है, जब आप इस कोड को चलाते हैं तो आप अपने AST के लिए नोड टाइप्स देखेंगे।
अब:
आपको उन सभी on_ मेथड्स को लागू करने की आवश्यकता है जिन्हें आप उपयोग करना चाहते हैं। उदाहरण के लिए, यदि मुझे लाइन नंबरों के साथ सभी इंस्टेंस मेथड नाम चाहिए तो मैं यह कर सकता हूं:
def on_def(node)
line_num = node.loc.line
method_name = node.children[0]
puts "Found #{method_name} at line #{line_num}"
end
जब आप अब अपना प्रोग्राम चलाते हैं तो यह पाए गए सभी मेथड नाम प्रिंट करना चाहिए।
निष्कर्ष
रूबी स्टैटिक एनालिसिस टूल बनाना उतना मुश्किल नहीं है जितना दिख सकता है। यदि आप एक अधिक पूर्ण उदाहरण चाहते हैं तो मेरे class_indexer जेम पर एक नज़र डालें। अब आपकी बारी है अपने खुद के टूल्स बनाने की!
कृपया इस पोस्ट को शेयर करें यदि आपको यह पसंद आई! 🙂