रूबी: आवश्यकता बनाम आवश्यकता_ संबंध - रूबी <1.9.2 और> = 1.9.2 दोनों में चलने वाले वर्कअराउंड के लिए सबसे अच्छा अभ्यास


153

यदि मैं requireरूबी में एक रिश्तेदार फाइल करना चाहता हूं और मैं इसे 1.8.x और> = 1.9.2 दोनों में काम करना चाहता हूं तो सबसे अच्छा अभ्यास क्या है ?

मुझे कुछ विकल्प दिखाई देते हैं:

  • बस करो $LOAD_PATH << '.'और सब कुछ भूल जाओ
  • करना $LOAD_PATH << File.dirname(__FILE__)
  • require './path/to/file'
  • जाँच करें कि RUBY_VERSION<1.9.2, तो इस require_relativeरूप में परिभाषित requireकरें, require_relativeहर जगह का उपयोग करें जहां इसकी आवश्यकता है
  • जांचें कि क्या require_relativeपहले से मौजूद है, अगर ऐसा होता है, तो पिछले मामले में आगे बढ़ने की कोशिश करें
  • अजीब निर्माणों का उपयोग करें - जैसे कि वे रूबी 1.9 में काम नहीं करते हैं, उदाहरण के लिए, क्योंकि:
    require File.join(File.dirname(__FILE__), 'path/to/file')
    $ cat caller.rb
    require File.join(File.dirname(__FILE__), 'path/to/file')
    $ cat path/to/file.rb
    puts 'Some testing'
    $ ruby caller
    Some testing
    $ pwd
    /tmp
    $ ruby /tmp/caller
    Some testing
    $ ruby tmp/caller
    tmp/caller.rb:1:in 'require': no such file to load -- tmp/path/to/file (LoadError)
        from tmp/caller.rb:1:in '<main>'
  • यहां तक ​​कि weirder निर्माण: काम करने लगता है, लेकिन यह अजीब है और बहुत अच्छी नहीं लग रही है।
    require File.join(File.expand_path(File.dirname(__FILE__)), 'path/to/file')
  • बैकपोर्ट मणि का उपयोग करें - यह एक तरह का भारी है, इसके लिए माणिक्य बुनियादी ढांचे की आवश्यकता होती है और इसमें अन्य वर्कअराउंड के टन शामिल होते हैं, जबकि मैं सिर्फ requireरिश्तेदार फाइलों के साथ काम करना चाहता हूं ।

StackOverflow में एक बारीकी से संबंधित प्रश्न है जो कुछ और उदाहरण देता है, लेकिन यह एक स्पष्ट जवाब नहीं देता है - जो एक सर्वोत्तम अभ्यास है।

क्या मेरे आवेदन को रूबी <1.9.2 और> = 1.9.2 दोनों पर चलाने के लिए कोई सभ्य, स्वीकृत-हर-कोई सार्वभौमिक समाधान है?

अपडेट करें

स्पष्टता: मैं केवल "आप एक्स कर सकते हैं" जैसे उत्तर नहीं चाहते हैं - वास्तव में, मैंने पहले ही प्रश्न में अधिकांश विकल्पों का उल्लेख किया है। मैं औचित्य चाहता हूं , अर्थात यह एक सर्वोत्तम अभ्यास क्यों है, इसके नियम और विपक्ष क्या हैं और इसे दूसरों के बीच क्यों चुना जाना चाहिए।


3
हाय मैं नया हूँ। क्या कोई शुरू से समझा सकता है - क्या अंतर है requireऔर require_relative?
कर्नल पैनिक

3
पुरानी रूबी 1.8 में यदि आप फ़ाइल चलाते a.rbहैं और b.rbवर्तमान निर्देशिका में फ़ाइल की सामग्री को पढ़ने और पार्स करने की व्याख्या करना चाहते हैं (आमतौर पर उसी तरह की dir a.rb), तो आप बस लिखेंगे require 'b'और यह ठीक रहेगा क्योंकि डिफ़ॉल्ट खोज पथ में वर्तमान निर्देशिका शामिल है। अधिक आधुनिक रूबी 1.9 में, आपको require_relative 'b'इस मामले में लिखना require 'b'होगा , क्योंकि यह केवल मानक पुस्तकालय पथों में खोज करेगा। यह उस तरह की सरल स्क्रिप्ट के लिए आगे और पीछे की संगतता को तोड़ता है जो ठीक से स्थापित नहीं होने जा रहे हैं (उदाहरण के लिए, स्वयं स्क्रिप्ट स्थापित करें )।
ग्रेचैट

अब आप backportsसिर्फ इसके लिए उपयोग कर सकते हैं require_relative, मेरा उत्तर देखें ...
मार्क-एंड्रे लाफ्यून

जवाबों:


64

इसके लिए एक वर्कअराउंड सिर्फ 'aws' रत्न में जोड़ा गया था ताकि मुझे लगा कि मैं इस पोस्ट से प्रेरित हूं।

https://github.com/appoxy/aws/blob/master/lib/awsbase/require_relative.rb

unless Kernel.respond_to?(:require_relative)
  module Kernel
    def require_relative(path)
      require File.join(File.dirname(caller[0]), path.to_str)
    end
  end
end

यह आपको require_relativeरूबी 1.8.2 और 1.9.1 में रूबी 1.9.2 में उपयोग करने की अनुमति देता है ।


3
आपको आवश्यकता की आवश्यकता कैसे है_relative.rb फ़ाइल? आपको आवश्यकता होती है requ_relative.rb और उसके बाद अन्य आवश्यकताओं की आवश्यकता होती है। या क्या मैं कुछ न कुछ भूल रहा हूं?
नीतिशास्त्र ३३

7
require_relativeसमारोह रूबी मुख्य लाइब्रेरीज के लिए एक विस्तार परियोजना में शामिल किया जाता है, यहां मिली: rubyforge.org/projects/extensions आप उन लोगों के साथ स्थापित करने के लिए सक्षम होना चाहिए gem install extensions। फिर अपने कोड में निम्न लाइन जोड़ें require_relative: 'एक्सटेंशन / ऑल' की आवश्यकता है ( यहां आउरिल के पोस्ट से स्रोत )
thegreendroid

@ ethicalhack3r बस उस कोड को अपनी रूबी लिपि के शीर्ष पर चिपकाएँ या यदि रेल में हैं, तो उसे शीर्ष वातावरण में फेंक दें। आरबी या कुछ और।
ट्रैविस रीडर

46

इससे पहले कि मैं 1.9.2 की छलांग लगाता, मैंने निम्न के लिए रिश्तेदार की आवश्यकता का उपयोग किया:

require File.expand_path('../relative/path', __FILE__)

पहली बार देखने पर यह थोड़ा अजीब है, क्योंकि ऐसा लगता है कि शुरुआत में एक अतिरिक्त '..' है। कारण यह है कि expand_pathदूसरे तर्क के सापेक्ष एक मार्ग का विस्तार होगा, और दूसरे तर्क की व्याख्या की जाएगी जैसे कि यह एक निर्देशिका थी। __FILE__स्पष्ट रूप से एक निर्देशिका नहीं है, लेकिन इससे कोई फर्क नहीं पड़ता क्योंकि expand_pathपरवाह नहीं है कि फाइलें मौजूद हैं या नहीं, यह सिर्फ कुछ नियमों को लागू करेगा जैसे कि .., .और ~। यदि आप आरंभिक "वेटामिन्यूट वहाँ पर एक अतिरिक्त ..नहीं है?" मुझे लगता है कि ऊपर की रेखा काफी अच्छी तरह से काम करती है।

यह मानते हुए कि क्या होता __FILE__है /absolute/path/to/file.rb, जो expand_pathस्ट्रिंग का निर्माण करेगा /absolute/path/to/file.rb/../relative/path, और फिर एक नियम लागू करता है जो कहता है कि ..इससे पहले पथ घटक को हटा देना चाहिए ( file.rbइस मामले में), लौट रहा है /absolute/path/to/relative/path

क्या यह सबसे अच्छा अभ्यास है? इस पर निर्भर करता है कि आपका क्या मतलब है, लेकिन ऐसा लगता है कि यह सब रेल कोड आधार पर है, इसलिए मैं कहूंगा कि यह कम से कम एक सामान्य पर्याप्त मुहावरा है।


1
मैं इसे आमतौर पर भी देखता हूं। यह बदसूरत है, लेकिन यह अच्छी तरह से काम करता है।
yfeldblum

12
थोड़ा सा क्लीनर: File.expand_path ('रिश्तेदार / पथ', File.dirname ( FILE )) की आवश्यकता है
यानिक वुर्म

1
मुझे नहीं लगता कि यह बहुत साफ है, यह अभी लंबा है। वे दोनों नर्क के रूप में बहुत कम हैं, और दो बुरे विकल्पों के बीच चयन करते समय मैं उस व्यक्ति को पसंद करता हूं जिसे कम टाइपिंग की आवश्यकता होती है।
थियो

6
ऐसा लगता है कि File.expand_path ('../ relpath.x', File.dirname ( FILE )) एक बेहतर मुहावरा है, हालांकि यह अधिक क्रिया है। एक अतिरिक्त पथ के साथ निर्देशिका पथ के रूप में व्याख्या की जा रही एक फ़ाइल पथ की यकीनन टूटी हुई कार्यक्षमता पर भरोसा करने पर / जब उस कार्यक्षमता को ठीक किया जाता है तो टूट सकता है।
जेपीजेक

1
टूटा हुआ, शायद, लेकिन यह यूनिक्स में हमेशा के लिए इस तरह से रहा है। जब यह रास्तों और '..' के संकल्प की बात आती है, तो बस एक निर्देशिका और एक फ़ाइल के बीच कोई अंतर नहीं है - इसलिए मैं इसके लिए कोई नींद नहीं खो रहा हूं।
थियो

6

पिकैक्स के पास 1.8 के लिए एक स्निपेट है। यह रहा:

def require_relative(relative_feature)
  c = caller.first
  fail "Can't parse #{c}" unless c.rindex(/:\d+(:in `.*')?$/)
  file = $`
  if /\A\((.*)\)/ =~ file # eval, etc.
    raise LoadError, "require_relative is called in #{$1}"
  end
  absolute = File.expand_path(relative_feature, File.dirname(file))
  require absolute
end

यह मूल रूप से सिर्फ थियो का उत्तर देता है, लेकिन आप अभी भी उपयोग कर सकते हैं require_relative


यह कैसे जांचें कि क्या यह स्निपेट सक्रिय होना चाहिए या ठीक से नहीं होना चाहिए? उपयोग $RUBY_VERSIONया जाँच करके अगर require_relativeसीधे मौजूद है?
19

1
हमेशा बतख प्रकार, जांचें कि require_relativeक्या परिभाषित किया गया है।
थियो

@ Theo @GreyCat हाँ, मैं जाँच करूँगा कि क्या इसकी आवश्यकता है। मैं यहां सिर्फ लोगों को दिखाने के लिए स्निपेट लगा रहा था। निजी तौर पर, मैं ग्रेग के उत्तर का उपयोग करता हूं, मैं वास्तव में सिर्फ यह पोस्ट कर रहा था क्योंकि किसी ने इसका उल्लेख खुद किए बिना किया था।
पॉल हॉफर

6
$LOAD_PATH << '.'

$LOAD_PATH << File.dirname(__FILE__)

यह एक अच्छी सुरक्षा आदत नहीं है: आपको अपनी पूरी निर्देशिका को क्यों उजागर करना चाहिए?

require './path/to/file'

यह काम नहीं करता है अगर RUBY_VERSION <1.9.2

जैसे अजीब निर्माण का उपयोग करें

require File.join(File.dirname(__FILE__), 'path/to/file')

यहां तक ​​कि अजीब निर्माण:

require File.join(File.expand_path(File.dirname(__FILE__)), 'path/to/file')

बैकपोर्ट रत्न का उपयोग करें - यह एक तरह का भारी होता है, इसके लिए माणिक्य बुनियादी ढांचे की आवश्यकता होती है और इसमें अन्य वर्कअराउंड शामिल होते हैं, जबकि मुझे बस रिश्तेदार फाइलों के साथ काम करने की आवश्यकता होती है।

आपने पहले ही उत्तर दे दिया है कि ये सबसे अच्छे विकल्प क्यों नहीं हैं।

जांचें कि अगर RUBY_VERSION <1.9.2 है, तो आवश्यकता के रूप में आवश्यकता के अनुसार_ को परिभाषित करें, हर जगह जहां आवश्यकता है उसका उपयोग करें।

जांच करें कि क्या requ_relative पहले से मौजूद है, यदि ऐसा होता है, तो पिछले मामले में आगे बढ़ने का प्रयास करें

यह काम कर सकता है, लेकिन अधिक सुरक्षित और तेज़ तरीका है: लोडर्रर अपवाद से निपटने के लिए:

begin
  # require statements for 1.9.2 and above, such as:
  require "./path/to/file"
  # or
  require_local "path/to/file"
rescue LoadError
  # require statements other versions:
  require "path/to/file"
end

5

मैं आरबीएक्स-आवश्यकता-सापेक्ष रत्न ( स्रोत ) का उपयोग करने का प्रशंसक हूं । यह मूल रूप से रुबिनियस के लिए लिखा गया था, लेकिन यह एमआरआई 1.8.7 का भी समर्थन करता है और 1.9.2 में कुछ भी नहीं करता है। एक मणि की आवश्यकता सरल है, और मुझे अपने प्रोजेक्ट में कोड स्निपेट फेंकने की आवश्यकता नहीं है।

इसे अपने जेमफाइल में जोड़ें:

gem "rbx-require-relative"

फिर आपके require 'require_relative'सामने require_relative

उदाहरण के लिए, मेरी एक परीक्षण फ़ाइल इस प्रकार है:

require 'rubygems'
require 'bundler/setup'
require 'minitest/autorun'
require 'require_relative'
require_relative '../lib/foo'

यह इनमें से किसी भी IMO का सबसे साफ समाधान है, और मणि बैकपोर्ट की तरह भारी नहीं है।


4

backportsमणि अब backports के अलग-अलग लोड हो रहा है की अनुमति देता है।

आप तब बस:

require 'backports/1.9.1/kernel/require_relative'
# => Now require_relative works for all versions of Ruby

यह requireनए संस्करणों को प्रभावित नहीं करेगा, और न ही यह किसी अन्य अंतर्निहित तरीकों को अपडेट करेगा।


3

एक अन्य विकल्प दुभाषिया को यह बताने का है कि कौन सा रास्ता खोजा जाए

ruby -I /path/to/my/project caller.rb

3

__FILE__ पर आधारित समाधानों के साथ एक मुद्दा जो मैंने नहीं देखा है, वह यह है कि वे सहानुभूति के संबंध में विराम देते हैं। उदाहरण के लिए मैं कहता हूं:

~/Projects/MyProject/foo.rb
~/Projects/MyProject/lib/someinclude.rb

मुख्य स्क्रिप्ट, प्रवेश बिंदु, आवेदन foo.rb है। यह फ़ाइल ~ / लिपियों / foo से जुड़ी है जो मेरे $ PATH में है। जब मुझे 'foo' निष्पादित होता है, तो इस कथन की आवश्यकता होती है:

require File.join(File.dirname(__FILE__), "lib/someinclude")

चूँकि __FILE__ ~ / Scripts / foo है, इसलिए ऊपर दिए गए विवरण की आवश्यकता है ~ / लिपियों / foo / lib / someinclude.rb के लिए जो स्पष्ट रूप से मौजूद नहीं है। समाधान सरल है। यदि __FILE__ एक प्रतीकात्मक लिंक है, तो इसे आवश्यक रूप से संदर्भित किया जाना चाहिए। Pathname # realpath इस स्थिति में हमारी सहायता करेगा:

"pathname" की आवश्यकता है
File.join की आवश्यकता होती है (File.dirname (Pathname.new (__ File __)। realpath), "lib / someinclude")

2

यदि आप एक मणि का निर्माण कर रहे थे, तो आप लोड पथ को प्रदूषित नहीं करना चाहेंगे।

लेकिन, एक स्वसंपूर्ण अनुप्रयोग के मामले में, वर्तमान निर्देशिका को लोड पथ में जोड़ना बहुत सुविधाजनक है जैसा कि आप पहले 2 उदाहरणों में करते हैं।

मेरा वोट सूची में पहले विकल्प पर जाता है।

मैं कुछ ठोस रूबी सर्वोत्तम प्रथाओं साहित्य को देखना पसंद करूंगा।


1
पुन: "मैं कुछ ठोस रूबी सर्वोत्तम प्रथाओं साहित्य को देखना पसंद करूंगा।" आप ग्रेगरी ब्राउन की रूबी सर्वश्रेष्ठ प्रथाओं को डाउनलोड कर सकते हैं । आप रेल्स बेस्ट प्रैक्टिस साइट भी देख सकते हैं ।
माइकल स्टाकर

1

relative_requireअगर यह मौजूद नहीं है तो मैं अपने को परिभाषित करूंगा (यानी 1.8 के तहत) और फिर हर जगह एक ही वाक्यविन्यास का उपयोग करूंगा ।


0

रूबी रेल पटरियों पर:

config_path = File.expand_path("../config.yml", __FILE__)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.