$ LOAD_PATH (Ruby) 'ye bir dizin ekleme


96

Şu anda yürütülmekte olan dosyanın dizinini $ LOAD_PATH (veya $ :) öğesine eklemek için yaygın olarak kullanılan iki teknik gördüm. Bir mücevher ile çalışmıyorsanız, bunu yapmanın avantajlarını görüyorum. Biri diğerinden daha ayrıntılı görünüyor, açıkçası, ancak birinin diğerinin üzerine gitmesi için bir neden var mı?

İlk, ayrıntılı yöntem (aşırı olabilir):

$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))

ve daha basit, hızlı ve kirli:

$:.unshift File.dirname(__FILE__)

Biri diğerine geçmek için herhangi bir neden var mı?


2
Bir hafifçe birinin ayrıntılı az açıklayıcı versiyonudur:File.expand_path(File.dirname(__FILE__)).tap {|pwd| $LOAD_PATH.unshift(pwd) unless $LOAD_PATH.include?(pwd)}
Nathan Uzun

peki ya "sürece" cümlesi? Yukarıdaki ikisi nasıl eşdeğer olabilir?
inger

Buraya bunu nasıl kullanacağını anlamaya gelen biri olarak, bu çok şifreli. Örneklerde dizin adının nereden geldiğini anlamıyorum. Biri bunu açıklığa kavuşturabilirse minnettar olurum.
SlySherZ

1
Kullanılması __dir__(Ruby 2.0 itibariyle) bunlar daha Özlü herhangi yapabilirsiniz.
Nathan Long

Yanıtlar:


52

Diğerinin üzerine git diyebilirim $:.unshift File.dirname(__FILE__), çünkü kodda birinden çok daha fazla kullanıldığını gördüm $LOAD_PATHve daha da kısa!


Ruby ile ilk başladığımda, açıkça $ LOAD_PATH'ın daha iyi olduğunu düşündüm. Ancak başlangıç ​​statüsünden mezun olduktan sonra, kodumu yeni başlayanlar için daha okunaklı hale getirmeye çalışsaydım yalnızca $ LOAD_PATH kullanırdım. Yani bu bir değiş tokuş. Bellek kullanımı her biri için aynı olduğu sürece kodun ne kadar "kamuya açık" olduğuna bağlıdır, bunun esasen öyle olduğunu varsayıyorum.
boulder_ruby

9
Projeniz için takip ettiğiniz stil kılavuzuna bağlıdır. Popüler Ruby Stil Kılavuzu "Perl tarzı özel değişkenler ($ :, $ ;, vb. Gibi) kullanmaktan kaçının. Oldukça şifreli ve tek satırlık komut dosyalarından başka herhangi bir şeyde kullanılması önerilmez."
bobmagoo

153

Ruby yükleme yolu çok yaygın olarak $: olarak yazılır, ancak sadece kısa olduğu için daha iyi yapmaz. Netliği zekâya tercih ediyorsanız ya da kendi iyiliği için kısalık sizi kaşındırıyorsa, bunu sırf herkes olduğu için yapmanız gerekmez. Merhaba de ...

$LOAD_PATH

... ve veda edin ...

# I don't quite understand what this is doing...
$:

29
Ayrıca, yalnızca semboller içeren "$:" gibi dizeler Google için çok daha zordur.
DSimon

24

'Hızlı ve kirli' yolu pek sevmiyorum. Ruby'de yeni olan herkes ne $:.olduğunu düşünecek .

Bunu daha açık buluyorum.

libdir = File.dirname(__FILE__)
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)

Ya da tam yola sahip olmayı önemsiyorsam ...

libdir = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)

GÜNCELLEME 2009/09/10

Son zamanlarda aşağıdakileri yapıyorum:

$:.unshift(File.expand_path(File.dirname(__FILE__))) unless
    $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))

GitHub'a göz atarken bir sürü farklı yakut projesinde gördüm.

Kongre gibi görünüyor?


@LukeAntins, bu gerçekten harika ama uygulamada "bootstrap" load_path'i nerede bulmalıyım?
gaussblurinc

@gaussblurinc Kitaplığınızın / uygulamanızın 'üstüne yakın' bir yer, ama gerçekten bağlıdır. Her zaman kendinize göre olan bir bindosyanız varsa codeve bu bindosya tarafından çalıştırıldıysa ... bölmedeki bootstrap. Bir kitaplığınız varsa, lib/code.rbaltındaki her şeye erişmek için kitaplık kodunuzun en üstünde önyükleme yapın lib/code/. Umarım bu saçmalık yardımcı olur!
Luke Antins

1
RuboCop __dir__, mevcut dosyanın dizinine bir yol bulmak için kullanılabileceğini bildiriyor .
Raphael

8

Eğer yazarsanız script/consolesizin Raylar projede ve girmek $:, Ruby'yi yüklemek için gerekli tüm dizinleri içeren bir dizi alırsınız. Bu küçük egzersizden çıkarılacak şey, bu $:bir dizi. Bu durumda, diğer dizinlerin başına unshiftyöntem veya <<işleç eklenmesi gibi işlevler gerçekleştirebilirsiniz . Eğer açıklamada ima gibi $:ve $LOAD_PATHaynıdır.

Bahsettiğiniz gibi bunu hızlı ve kirli bir şekilde yapmanın dezavantajı şudur: önyükleme yolunuzda zaten dizin varsa, kendini tekrar edecektir.

Misal:

Todo adında oluşturduğum bir eklentim var. Rehberim şu şekilde yapılandırılmıştır:

/---SATICI
  |
  | --- / eklentiler
        |
        | --- / yapılacak
              |
              | --- / lib
                    |
                    | --- / uygulama
                          |
                          | --- / modeller
                          | --- / denetleyiciler
              |
              | --- / raylar
                    |
                    | --- init.rb

İnit.rb dosyasında aşağıdaki kodu girdim:

## In vendor/plugins/todo/rails/init.rb
    %w{ models controllers models }.each do |dir|
      path = File.expand_path(File.join(File.dirname(__FILE__), '../lib', 'app', dir))
      $LOAD_PATH << path
      ActiveSupport::Dependencies.load_paths << path
      ActiveSupport::Dependencies.load_once_paths.delete(path)
    end 

Kod bloğuna, blok içindeki eylemleri, 'modelleri' tekrarladığım 'modeller', 'denetleyiciler' ve 'modeller' dizelerine nasıl gerçekleştirdiğimi not edin. (Bilginize, Ruby'ye %w{ ... }bir dizi dizgiyi tutmasını söylemenin başka bir yolu). Koştuğumda şunu yazıyorum script/console:

>> puts $:

Ve bunu dizedeki içeriği okumayı kolaylaştırmak için yazıyorum. Aldığım çıktı:

...
...
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/controllers
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models

Gördüğünüz gibi, bu, şu anda üzerinde çalıştığım bir projeyi kullanırken oluşturabileceğim kadar basit bir örnek olsa da, dikkatli değilseniz hızlı ve kirli yol, tekrarlanan yollara yol açacaktır. Daha uzun yol, tekrarlanan yolları kontrol edecek ve bunların oluşmadığından emin olacaktır.

Deneyimli bir Rails programcısıysanız, muhtemelen ne yaptığınız hakkında çok iyi bir fikriniz vardır ve muhtemelen yolları tekrarlama hatasını yapmazsınız. Eğer bir acemi iseniz, gerçekten ne yaptığınızı anlayana kadar daha uzun yoldan giderim.


Cevabınız çok yardımcı oldu ve ayrıca iyi açıklandı. Önerilen düzenleme: yöntem load_pathsve load_once_paths.deletekullanımdan kaldırıldı. Onlara atıfta bulunan satırların güncellenmesine yardımcı olunur: ActiveSupport::Dependencies.autoload_paths << path ActiveSupport::Dependencies.autoload_once_paths.delete(path)
Uzzar

8

En iyisi, Rspec'i kullanırken göreli yol aracılığıyla bir direk eklemek için karşılaştım. Yeterince ayrıntılı buluyorum ama yine de güzel bir astar.

$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))


-2

Bu sorunun ilk sorulmasından bu yana uzun zaman geçtiğini biliyorum, ancak paylaşmak istediğim ek bir cevabım var.

Birkaç yıl boyunca başka bir programcı tarafından geliştirilmiş birkaç Ruby uygulamam var ve aynı veritabanına erişebilseler de aynı sınıfları farklı uygulamalarda yeniden kullanıyorlar. Bu, DRY kuralını ihlal ettiğinden, tüm Ruby uygulamaları tarafından paylaşılacak bir sınıf kitaplığı oluşturmaya karar verdim. Bunu ana Ruby kitaplığına koyabilirdim, ancak bu, yapmak istemediğim ortak kod tabanındaki özel kodu gizlerdi.

Önceden tanımlanmış bir "profile.rb" adıyla kullandığım sınıf arasında bir ad çakışması yaşadığım bir sorun yaşadım. Ortak kod kitaplığını oluşturmaya çalışana kadar bu çakışma bir sorun değildi. Normalde Ruby önce uygulama konumlarını arar, ardından $ LOAD_PATH konumlarına gider.

Application_controller.rb oluşturduğum sınıfı bulamadı ve bir sınıf olmadığı için orijinal tanıma bir hata verdi. Sınıf tanımını uygulamanın app / models bölümünden kaldırdığım için Ruby onu orada bulamadı ve Ruby yollarında aramaya başladı.

Bu yüzden, kullandığım kütüphane dizininin yolunu içerecek şekilde $ LOAD_PATH değişkenini değiştirdim. Bu, başlatma zamanında environment.rb dosyasında yapılabilir.

Arama yoluna eklenen yeni dizinle bile, Ruby bir hata atıyordu çünkü tercihen sistem tanımlı dosyayı önce alıyordu. $ LOAD_PATH değişkenindeki arama yolu tercihen önce Ruby yollarını arar.

Bu nedenle, arama sırasını değiştirmem gerekiyordu, böylece Ruby yerleşik kitaplıkları aramadan önce sınıfı ortak kitaplığımda bulmuştu.

Bu kod bunu environment.rb dosyasında yaptı:

Rails::Initializer.run do |config|

* * * * *

path = []
path.concat($LOAD_PATH)
$LOAD_PATH.clear
$LOAD_PATH << 'C:\web\common\lib'
$LOAD_PATH << 'C:\web\common'
$LOAD_PATH.concat(path)

* * * * *

end

Bu seviyede daha önce verilen gelişmiş kodlama yapılarından herhangi birini kullanabileceğinizi sanmıyorum, ancak uygulamanızda başlatma zamanında bir şey kurmak istiyorsanız gayet iyi çalışıyor. Yeni değişkene geri eklendiğinde, orijinal $ LOAD_PATH değişkeninin orijinal sırasını korumalısınız, aksi takdirde bazı ana Ruby sınıfları kaybolur.

Application_controller.rb dosyasında yalnızca bir

require 'profile'
require 'etc' #etc

ve bu, tüm uygulama için özel kitaplık dosyalarını yükler, yani her denetleyicide gerekli komutları kullanmak zorunda değilim.

Benim için aradığım çözüm buydu ve bilgiyi iletmek için bu yanıta ekleyeceğimi düşündüm.

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.