Ruby: requir_relative ile vs gerektirir - hem Ruby <1.9.2 hem de> = 1.9.2'de çalışan geçici çözüm için en iyi uygulama


153

requireRuby'de göreceli bir dosyaya ve 1.8.x ve> = 1.9.2 sürümlerinde çalışmasını istiyorsanız en iyi uygulama nedir ?

Birkaç seçenek görüyorum:

  • sadece yap $LOAD_PATH << '.'ve her şeyi unut
  • yapmak $LOAD_PATH << File.dirname(__FILE__)
  • require './path/to/file'
  • eğer onay RUBY_VERSION1.9.2 <ardından tanımlamak require_relativeolarak require, kullanım require_relativeher yerde sonradan duyulan yere
  • require_relativezaten var olup olmadığını kontrol edin , eğer varsa, önceki durumda olduğu gibi ilerlemeye çalışın
  • alas gibi Ruby konstrüksiyonunda işe yaramaz gibi garip yapıları kullanın , çünkü, örneğin:
    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>'
  • Garip yapı bile: işe yarıyor gibi görünüyor, ama garip ve iyi görünmüyor.
    require File.join(File.expand_path(File.dirname(__FILE__)), 'path/to/file')
  • Backports mücevher kullanın - biraz ağır, rubygems altyapısı gerektirir ve sadece diğer tonları içerir, sadece istiyorumrequire göreli dosyalarla çalışmak .

Bir var StackOverflow'daki yakından ilişkili soru biraz daha fazla örnek verir, ancak net bir cevap vermez - en iyi uygulamadır.

Uygulamamın hem Ruby <1.9.2 hem de> = 1.9.2 üzerinde çalışmasını sağlamak için herkes tarafından kabul edilen iyi bir evrensel çözüm var mı?

GÜNCELLEME

Açıklama: Sadece "X yapabilirsin" gibi cevaplar istemiyorum - aslında, söz konusu seçeneklerin çoğundan daha önce bahsetmiştim. İstediğim mantığı , yani neden o diğerleri arasında seçilmelidir neden onun artıları ve eksileri vardır ve ne iyi yöntem vardır.


3
Merhaba ben yeniyim. Birisi en başından itibaren açıklayabilir mi - requireve arasındaki fark require_relativenedir?
Albay Panik

3
Dosyayı çalıştırdıysanız a.rbve b.rbgeçerli dizindeki (genellikle ile aynı dizinde) tercüman okuma ve ayrıştırma yapmak istiyorsanız, eski Ruby 1.8'de a.rb, sadece yazardınız require 'b've varsayılan arama yolu geçerli dizinin dahil olduğu gibi iyi olurdu. Daha modern Ruby 1.9'da, require_relative 'b'bu durumda require 'b'yalnızca standart kütüphane yollarında arama yapacağınız gibi yazmak zorunda kalacaksınız . Bu, düzgün yüklenmeyecek daha basit komut dosyaları için ileri ve geri uyumluluğu bozan şeydir (örneğin, komut dosyalarını kendiniz yükleyin ).
GreyCat

Artık backportssadece require_relativecevabımı kullanabilirsin , cevabımı gör ...
Marc-André Lafortune

Yanıtlar:


64

Bunun için bir çözüm sadece 'aws' gem'e eklendi, bu yazıdan esinlenerek paylaşacağımı düşündüm.

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

Bu, require_relativeyakut 1.8 ve 1.9.1'deki yakut 1.9.2'deki gibi kullanmanızı sağlar .


3
Requir_relative.rb dosyasına nasıl ihtiyacınız var? Requir_relative.rb'yi ve ardından gereksinimlerin geri kalanını request_relative gerekir. Yoksa bir şey mi kaçırıyorum?
ethicalhack3r

7
require_relativeFonksiyon Yakut çekirdek kütüphanelere bir uzatma projesi dahildir, burada bulundu: rubyforge.org/projects/extensions Sen onları yüklemek mümkün olmalıdır gem install extensions. Daha sonra kodunuza aşağıdaki satırı ekleyin require_relative: gerektirir 'uzantıları / tümü' ( burada Aurril'in gönderisinden alınmıştır )
thegreendroid

@ ethicalhack3r sadece bu kodu yakut betiğinizin üstüne kopyalayın ve yapıştırın veya raylarda, en üst ortama atın. rb veya başka bir şey.
Travis Reeder

46

1.9.2 'e atlamadan önce, aşağıdaki akrabalar için kullandım:

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

İlk gördüğünüzde biraz garip, çünkü başlangıçta ekstra bir '..' var gibi görünüyor. Bunun nedeni, expand_pathikinci argümana göre bir yolu genişletecek ve ikinci argüman bir dizinmiş gibi yorumlanacaktır. __FILE__Açıkçası bir dizin değil, ama expand_pathdosyaların var olup olmadığını umursamadığından bu önemli değil, sadece aşağıdaki gibi şeyleri genişletmek için bazı kurallar uygulayacak.. , .ve~ . Eğer ilk "waitaminute orada fazladan ..yok mu?" Yukarıdaki çizginin oldukça iyi çalıştığını düşünüyorum.

Varsayılırsa __FILE__olduğunu /absolute/path/to/file.rbne olur yani, expand_pathdize inşa edecek /absolute/path/to/file.rb/../relative/pathve ardından söyleyen bir kural uygulamak ..(ondan önce yol bileşenini kaldırmak gerekir file.rbdönen, bu durumda)/absolute/path/to/relative/path .

Bu en iyi yöntem mi? Bununla ne demek istediğine bağlı, ancak tüm Rails kod tabanı üzerinde görünüyor, bu yüzden en azından yeterince yaygın bir deyim olduğunu söyleyebilirim.


1
Bunu da yaygın olarak görüyorum. Çirkin, ama iyi çalışıyor gibi görünüyor.
yfeldblum

12
biraz temizleyici: File.expand_path ('relative / path', File.dirname ( FILE )) gerekir
Yannick Wurm

1
Çok daha temiz olduğunu düşünmüyorum, sadece daha uzun. Her ikisi de cehennem gibi çirkin ve iki kötü seçenek arasında seçim yaparken daha az yazmayı gerektiren birini tercih ederim.
Theo

6
Daha ayrıntılı olmasına rağmen File.expand_path ('../ relpath.x', File.dirname ( FILE )) daha iyi bir deyim gibi görünüyor . Fazladan varolmayan bir dizine sahip bir dizin yolu olarak yorumlanan bir dosya yolunun tartışmalı olarak bozuk işlevselliğine güvenmek, bu işlev düzeltildiğinde / düzeltildiğinde bozulabilir.
jpgeek

1
Belki kırık, ama UNIX'te sonsuza dek böyle oldu. Bir dizin ve bir dosya arasında yollar ve '..' çözünürlüğü konusunda hiçbir fark yoktur - bu yüzden üzerinde herhangi bir uyku kaybetmiyorum.
Theo

6

Kazma'nın bunun için bir snippet'i var 1.8. İşte burada:

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

Temel olarak Theo'nun cevapladığı şeyi kullanır, ancak yine de kullanabilirsiniz require_relative.


Bu pasajın etkinleştirilip etkinleştirilmeyeceği nasıl kontrol edilir? Kullanarak $RUBY_VERSIONveya require_relativedoğrudan var olup olmadığını kontrol ederek ?
GreyCat

1
Her zaman ördek tipi, require_relativetanımlı olup olmadığını kontrol edin .
Theo

@Theo @GreyCat evet, gerekli olup olmadığını kontrol ederdim. Ben sadece pasajı insanların göstermesi için buraya koyuyordum. Şahsen, Greg'in cevabını yine de kullanırdım, gerçekten sadece bunu gönderiyordum çünkü birisi kendisinden bahsetmemişti.
Paul Hoffer

6
$LOAD_PATH << '.'

$LOAD_PATH << File.dirname(__FILE__)

Bu iyi bir güvenlik alışkanlığı değildir: Neden tüm dizininizi ortaya çıkarmalısınız?

require './path/to/file'

RUBY_VERSION <1.9.2 ise bu işe yaramaz

gibi garip yapılar kullanın

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

Hatta garip yapı:

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

Backports mücevher kullanın - biraz ağır, rubygems altyapısı gerektirir ve diğer göreceli dosyalarla çalışmak isterken, tonlarca başka geçici çözüm içerir.

Bunların neden en iyi seçenek olmadığını zaten cevapladınız.

RUBY_VERSION <1.9.2 olup olmadığını kontrol edin, sonra requir_relative değerini gerektiği gibi tanımlayın, daha sonra ihtiyaç duyulan her yerde requir_relative kullanın

requir_relative öğesinin zaten mevcut olup olmadığını kontrol edin, varsa önceki durumda olduğu gibi ilerlemeye çalışın

Bu işe yarayabilir, ancak daha güvenli ve daha hızlı bir yol vardır: LoadError istisnasıyla başa çıkmak için:

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

Ben rbx-requir-relative gem ( kaynak ) kullanarak hayranıyım . Başlangıçta Rubinius için yazılmıştır, ancak MRI 1.8.7'yi de destekler ve 1.9.2'de hiçbir şey yapmaz. Bir mücevher gerekli basit ve benim proje içine kod parçacıkları atmak zorunda değilim.

Gemfile'ınıza ekleyin:

gem "rbx-require-relative"

Sonra require 'require_relative'senden önce require_relative.

Örneğin, test dosyalarımdan biri şuna benzer:

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

Bu, bu IMO'lardan herhangi biri için en temiz çözümdür ve mücevher backport kadar ağır değildir.


4

backportsMücevher şimdi backports bireysel olarak yüklenmesini sağlar.

Daha sonra şunları yapabilirsiniz:

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

Bu require, yeni sürümleri etkilemez veya başka yerleşik yöntemleri güncellemez.


3

Başka bir seçenek de tercümana hangi yolları arayacağını söylemek

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

3

__FILE__ tabanlı çözümlerle dikkat çekmediğim bir konu, sembolik bağlantılarla ilgili kopmalarıdır. Örneğin ben var diyelim:

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

Ana komut dosyası, giriş noktası, uygulama foo.rb. Bu dosya benim $ PATH olan ~ / Scripts / foo ile bağlantılı. 'Foo' yürüttüğümde bu zorunlu ifade bozuk:

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

__FILE__, ~ / Scripts / foo olduğundan yukarıdaki zorunlu ifade, açıkça var olmayan ~ / Scripts / foo / lib / someinclude.rb dosyasını arar. Çözüm basit. __FILE__ sembolik bir bağlantıysa, kayıttan çıkarılması gerekir. Yol adı # realpath bize bu durumla ilgili yardımcı olacaktır:

"yol adı" gerektir
File.join gerektirir (File.dirname (Pathname.new (__ FILE __). realpath), "lib / someinclude")

2

Bir mücevher inşa ediyorsanız, yük yolunu kirletmek istemezsiniz.

Ancak, bağımsız bir uygulama söz konusu olduğunda, geçerli dizini ilk 2 örnekte yaptığınız gibi yükleme yoluna eklemeniz çok uygundur.

Oyum listedeki ilk seçeneğe gidiyor.

Bazı sağlam Ruby en iyi uygulama literatürünü görmek isterim.


1
Re: "Ruby'nin en iyi uygulama literatürünü görmek isterim." Gregory Brown'ın Ruby Best Practices'i indirebilirsiniz . Ayrıca Rails Best Practices sitesine de bakabilirsiniz .
Michael Stalker

1

Ben relative_requireyoksa (yani 1.8 altında) kendi tanımlamak ve daha sonra her yerde aynı sözdizimini kullanın.


0

Ruby on Rails yolu:

config_path = File.expand_path("../config.yml", __FILE__)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.