क्या आप जानते हैं कि रूबी आपकी स्क्रिप्ट को डेटा के स्रोत के रूप में अपनी स्रोत फ़ाइल का उपयोग करने का एक तरीका प्रदान करती है? यह एक साफ-सुथरी चाल है जो आपको एकबारगी स्क्रिप्ट और अवधारणा के प्रमाण लिखते समय कुछ समय बचा सकती है। आइए इसे देखें!
डेटा और END
नीचे दिए गए उदाहरण में, मैं __END__
. नामक एक अजीब कीवर्ड का उपयोग कर रहा हूं . नीचे सब कुछ __END__
रूबी दुभाषिया द्वारा अनदेखा कर दिया जाएगा। लेकिन अधिक दिलचस्प बात यह है कि रूबी आपको DATA
. नामक एक IO ऑब्जेक्ट प्रदान करता है , जो आपको __END__
. के नीचे सब कुछ पढ़ने देता है ठीक वैसे ही जैसे आप किसी अन्य फाइल से पढ़ सकते हैं।
निम्नलिखित उदाहरण में, हम प्रत्येक पंक्ति पर पुनरावृति करते हैं और उसे प्रिंट करते हैं।
DATA.each_line do |line|
puts line
end
__END__
Doom
Quake
Diablo
इस तकनीक का मेरा पसंदीदा व्यावहारिक उदाहरण DATA
. का उपयोग करता है एक ईआरबी टेम्पलेट शामिल करने के लिए। यह वाईएएमएल, सीएसवी आदि के साथ भी काम करता है। एम
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 # prints the entire source file
__END__
meh
एकाधिक फ़ाइल delimma
इस तकनीक का एक बड़ा नुकसान यह है कि यह वास्तव में तभी काम करता है जब आपकी स्क्रिप्ट एकल स्रोत फ़ाइल में फ़िट हो जाती है, और आप उस फ़ाइल को शामिल करने के बजाय सीधे चला रहे हैं।
नीचे दिए गए उदाहरण में, मेरे पास दो फाइलें हैं, जिनमें से प्रत्येक का अपना __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 # Won't output anything, since first.rb read the entire file
end
__END__
Second end clause
snhorne ~/tmp $ ruby first.rb
First file
----------------------
First end clause
Second file
----------------------
एकाधिक फ़ाइलों के लिए वैकल्पिक समाधान
सिनात्रा में एक बहुत अच्छी सुविधा है जो आपको अपने ऐप्स में एक __END__
के बाद डालकर कई इनलाइन टेम्प्लेट जोड़ने की अनुमति देती है। बयान। यह इस तरह दिखता है:
# This code is from the Sinatra docs at 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
. का उपयोग करने का एक तरीका निकाला होगा कई फाइलों के साथ।
हालाँकि, यदि आप सिनात्रा स्रोत में थोड़ी खुदाई करते हैं, तो आप देखेंगे कि वे एक तरह से धोखा दे रहे हैं। वे DATA
. का उपयोग नहीं कर रहे हैं बिल्कुल भी। इसके बजाय वे नीचे दिए गए कोड के समान कुछ कर रहे हैं।
# I'm paraphrasing. See the original at https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1284
app, data = File.read(__FILE__).split(/^__END__$/, 2)
यह वास्तव में थोड़ा अधिक जटिल है, क्योंकि वे __FILE__
. पढ़ना नहीं चाहते हैं . वह सिर्फ sinatra/base.rb फ़ाइल होगी। इसके बजाय वे उस फ़ाइल की सामग्री प्राप्त करना चाहते हैं जिसने एक फ़ंक्शन का आह्वान किया था। वे इसे कॉलर के परिणाम को पार्स करके प्राप्त करते हैं।
कॉलर फ़ंक्शन आपको बताएगा कि वर्तमान में चल रहे फ़ंक्शन को कहां लागू किया गया था। यहां एक त्वरित उदाहरण दिया गया है:
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__
बहुत उपयोगी हो सकता है।