क्या आप जानते हैं कि Ruby आपके स्क्रिप्ट को अपने स्वयं के स्रोत फ़ाइल को डेटा स्रोत के रूप में उपयोग करने का एक तरीका प्रदान करता है? यह एक साफ-सुथरी ट्रिक है जो वन-ऑफ स्क्रिप्ट और प्रूफ ऑफ कॉन्सेप्ट लिखते समय आपका कुछ समय बचा सकती है। आइए इसे देखें!
DATA और END
नीचे दिए गए उदाहरण में, मैं `__END__` नामक एक अजीब कीवर्ड का उपयोग कर रहा हूँ। `__END__` के नीचे सब कुछ Ruby इंटरप्रेटर द्वारा अनदेखा किया जाएगा। लेकिन अधिक दिलचस्प बात यह है कि Ruby आपको `DATA` नामक एक IO ऑब्जेक्ट प्रदान करता है, जो आपको `__END__` के नीचे सब कुछ पढ़ने देता है जैसे आप किसी अन्य फ़ाइल से पढ़ सकते हैं।
निम्नलिखित उदाहरण में, हम प्रत्येक लाइन पर पुनरावृति करते हैं और इसे प्रिंट करते हैं।
DATA.each_line do |line| puts line end __END__ Doom Quake Diablo
इस तकनीक का मेरा पसंदीदा व्यावहारिक उदाहरण ERB टेम्पलेट को समाहित करने के लिए `DATA` का उपयोग करता है। यह YAML, CSV आदि के साथ भी काम करता है।
require 'erb' time = Time.now renderer = ERB.new(DATA.read) puts renderer.result() __END__ The current time is <%= time %>.
आप वास्तव में `DATA` का उपयोग `__END__` कीवर्ड से ऊपर की सामग्री को पढ़ने के लिए कर सकते हैं। ऐसा इसलिए है क्योंकि `DATA` वास्तव में संपूर्ण स्रोत फ़ाइल का एक पॉइंटर है, जिसे `__END__` कीवर्ड तक फास्ट-फॉरवर्ड किया गया है। आप इसे देख सकते हैं यदि आप प्रिंट करने से पहले IO ऑब्जेक्ट को रिवाइंड करते हैं। नीचे दिया गया उदाहरण संपूर्ण स्रोत फ़ाइल प्रिंट करता है।
DATA.rewind puts DATA.read # संपूर्ण स्रोत फ़ाइल प्रिंट करता है __END__ meh
बहु-फ़ाइल दुविधा
इस तकनीक के बड़े नुकसानों में से एक यह है कि यह वास्तव में केवल तभी काम करता है जब आपका स्क्रिप्ट एक सिंगल स्रोत फ़ाइल में फिट बैठता है, और आप उस फ़ाइल को सीधे चला रहे हैं, बजाय इसे शामिल करने के।
नीचे दिए गए उदाहरण में, मेरे पास दो फ़ाइलें हैं, प्रत्येक का अपना `__END__` सेक्शन है। हालांकि केवल एक `DATA` ग्लोबल हो सकता है। इसलिए दूसरी फ़ाइल का `__END__` सेक्शन अप्राप्य है।
# first.rb require "./second" puts "First file\n----------------------" puts DATA.read print_second_data() __END__ First end clause
# second.rb def print_second_data puts "Second file\n----------------------" puts DATA.read # कुछ भी आउटपुट नहीं करेगा, चूंकि first.rb ने पूरी फ़ाइल पढ़ ली है end __END__ Second end clause
snhorne ~/tmp $ ruby first.rb First file ---------------------- First end clause Second file ----------------------
बहु-फ़ाइलों के लिए एक समाधान
Sinatra में एक बहुत अच्छी सुविधा है जो आपको अपने ऐप्स में कई इंलाइन टेम्पलेट जोड़ने की अनुमति देती है उन्हें `__END__` स्टेटमेंट के बाद रखकर। यह ऐसा दिखता है:
# यह कोड Sinatra डॉक्स से है https://www.sinatrarb.com/intro.html require 'sinatra' get '/' do haml :index end __END__ @@ layout %html = yield @@ index %div.title Hello world.
लेकिन सिनात्रा वास्तव में यह कैसे कर सकता है? आखिरकार, आपका ऐप शायद रैक द्वारा लोड किया जाएगा। आप प्रोडक्शन में `ruby myapp.rb` नहीं चलाने जा रहे हैं! उन्हें `DATA` का उपयोग बहु-फ़ाइलों के साथ करने का एक तरीका ढूंढना होगा।
हालांकि, यदि आप Sinatra स्रोत में थोड़ा खोदते हैं, तो आप देखेंगे कि वे थोड़ा धोखा दे रहे हैं। वे `DATA` का उपयोग बिल्कुल नहीं कर रहे हैं। इसके बजाय वे नीचे दिए गए कोड के समान कुछ कर रहे हैं।
# मैं पैराफ्रेसिंग कर रहा हूँ। मूल देखें https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1284 app, data = File.read(__FILE__).split(/^__END__$/, 2)
यह वास्तव में थोड़ा अधिक जटिल है, क्योंकि वे `__FILE__` पढ़ना नहीं चाहते। वह सिर्फ sinatra/base.rb फ़ाइल होगी। इसके बजाय वे उस फ़ाइल की सामग्री प्राप्त करना चाहते हैं जिसने एक फ़ंक्शन आह्वान किया। वे इसे caller के परिणाम को पार्स करके प्राप्त करते हैं।
caller फ़ंक्शन आपको बताएगा कि वर्तमान में चल रहा फ़ंक्शन कहाँ आह्वान किया गया था। यहाँ एक त्वरित उदाहरण है:
def some_method puts caller end some_method # => caller.rb:5:in `<main>'
अब फ़ाइलनाम को वहां से निकालना, और उस फ़ाइल के लिए DATA के समतुल्य कुछ निकालना एक बहुत सरल मामला है।
def get_caller_data puts File.read(caller.first.split(":").first).split("__END__", 2).last end
इसे अच्छे के लिए उपयोग करें, बुरे के लिए नहीं
उम्मीद है कि यह स्पष्ट है कि ऐसी ट्रिक्स ऐसी चीज नहीं हैं जिन्हें आप हर दिन उपयोग करना चाहेंगे। वे साफ, रखरखाव योग्य बड़े कोड बेस के लिए बिल्कुल नहीं बनाते हैं।
हालांकि कभी-कभी आपको कुछ त्वरित और गंदा चाहिए, या तो वन-ऑफ यूटिलिटी स्क्रिप्ट के लिए या प्रूफ ऑफ कॉन्सेप्ट के लिए। उस स्थिति में, `DATA` और `__END__` काफी उपयोगी हो सकते हैं।