Dlaczego Ruby 1.9.2 usuwa „.” z LOAD_PATH i jaka jest alternatywa?

154

Najnowsze zestawy zmian w Rubim 1.9.2 nie powodują już, że bieżący katalog jest .częścią twojego LOAD_PATH. Mam nietrywialną liczbę plików Rakefile, które zakładają, że .jest to część LOAD_PATHpliku, więc to je zepsuło (zgłosili „brak takiego pliku do załadowania” dla wszystkich instrukcji, które są oparte na ścieżce projektu). Czy było jakieś szczególne uzasadnienie, aby to zrobić?

Jeśli chodzi o poprawkę, dodawanie $: << "."wszędzie działa, ale wydaje się niesamowicie hakerskie i nie chcę tego robić. Jaki jest preferowany sposób, aby moje pliki Rakefiles 1.9.2+ były kompatybilne?

John Feminella
źródło

Odpowiedzi:

141

Uznano to za zagrożenie „bezpieczeństwa”.

Możesz to obejść, używając ścieżek absolutnych

File.expand_path(__FILE__) et al

lub robić

require './filename' (ironically).

lub używając

require_relative 'filename'

lub dodanie katalogu „include”

ruby -I . ...

lub to samo, używając irb;

$irb -I .
rogerdpack
źródło
27
Skończyło się na używaniu require_relative. Dzięki.
John Feminella
11
Czy jest to podobne do większości unixów, które nie uwzględniają bieżącego katalogu w ścieżce do uruchamiania plików wykonywalnych?
Andrew Grimm
5
require './filename'działa tylko wtedy, gdy skrypt jest wykonywany z katalogiem roboczym ustawionym na ten sam katalog, w którym znajduje się skrypt. Często tak nie jest w projektach z wieloma katalogami.
mxcl
34

Są dwa powody:

  • solidność i
  • bezpieczeństwo

Oba opierają się na tej samej podstawowej zasadzie: ogólnie rzecz biorąc, po prostu nie możesz wiedzieć, jaki jest bieżący katalog, kiedy twój kod jest uruchamiany. Oznacza to, że gdy potrzebujesz pliku i zależy od tego, czy znajduje się on w bieżącym katalogu, nie masz możliwości kontrolowania, czy ten plik w ogóle tam będzie, czy też jest to plik, którego faktycznie się tam spodziewasz.

Jörg W Mittag
źródło
5
Nie sądzę, że wymuszanie, aby dwa pliki znajdowały się w tej samej lokalizacji względem siebie, jest koniecznie złym wymaganiem. Gdyby to była prawda, nie mielibyśmy pożytku z katalogów.
John Feminella
4
@John Feminella: co to ma wspólnego z umieszczaniem plików w ścieżkach względem siebie? Chodzi o umieszczenie ich względem ., czyli bieżącego katalogu roboczego. Jeśli użytkownik znajduje cdsię w innym katalogu, bieżący katalog roboczy zmienia się, a teraz są require zupełnie inne pliki w zależności od tego, w jakim katalogu znajdował się użytkownik, gdy wywołał twój skrypt. Myślę, że to nie jest dobry pomysł.
Jörg W Mittag
Aby więc zachować przyzwoity interfejs, powinieneś to zrobić? $: << File.dirname(__FILE__)
Joshua Cheek
4
@Joshua Cheek: Osobiście mi się to nie podoba. (Ale proszę, nie patrz na mój starszy kod, ponieważ jest zaśmiecony takimi rzeczami :-)). Po prostu udaję, że libkatalog znajduje się na, $LOAD_PATHa następnie requirewszystkie pliki względem lib. Innymi słowy: pozostawiam administratorowi ustalenie, jak $LOAD_PATHpoprawnie ustawić . Jeśli używasz RubyGems, jest to trywialne, ponieważ RubyGems automatycznie robi to za Ciebie, a jeśli używasz pakietów Debiana, to jest to zadanie opiekuna pakietu. W sumie wygląda na to, że całkiem nieźle się układa.
Jörg W Mittag,
8
@Joshua Cheek: Ponadto, jako swego rodzaju przeciwwaga do usuwania .z $LOAD_PATH, Ruby 1.9.2 wprowadza, require_relativektóry… niespodzianka… jest requireplik w stosunku do lokalizacji aktualnie wykonywanego pliku (tj. Względem File.dirname(__FILE__)).
Jörg W Mittag,
16

Jak wskazują inne odpowiedzi, jest to zagrożenie bezpieczeństwa, ponieważ .ścieżka ładowania odnosi się do obecnego katalogu roboczego Dir.pwd, a nie do katalogu aktualnie ładowanego pliku. Więc ktokolwiek wykonuje twój skrypt, może to zmienić, przechodząc po prostu cddo innego katalogu. Niedobrze!

Używam pełnych ścieżek zbudowanych z __FILE__jako alternatywy.

require File.expand_path(File.join(File.dirname(__FILE__), 'filename'))

W przeciwieństwie do require_relativetego jest wstecznie kompatybilny z Rubim 1.8.7.

Jonathan Tran
źródło
4
Jest też ta odmiana (którą osobiście uważam za bardziej czytelną): require Pathname.new(__FILE__).dirname + 'filename'
Tyler Rick
8

Posługiwać się require_relative 'file_to_require'

Wrzuć to do swojego kodu, aby require_relative działał w 1.8.7:

unless Kernel.respond_to?(:require_relative)
  module Kernel
    def require_relative(path)
      require File.join(File.dirname(caller.first), path.to_str)
    end
  end
end
Tyler Brock
źródło
3

Uznałem, że jest to kłopotliwa zmiana, dopóki nie zdałem sobie sprawy z kilku rzeczy.

Możesz ustawić RUBYLIB w swoim .profile (Unix) i żyć dalej tak, jak robiłeś to wcześniej:

export RUBYLIB="."

Ale jak wspomniano powyżej, od dawna uważano to za niebezpieczne.

W większości przypadków możesz uniknąć problemów, po prostu wywołując swoje skrypty Ruby z przedrostkiem „”. np ./scripts/server.

Dylan
źródło
3

Jak zauważył Jörg W Mittag, myślę, że to, czego chcesz używać, to require_relativetak, aby żądany plik był powiązany z plikiem źródłowym requiredeklaracji, a nie bieżącym katalogiem roboczym.

Twoje zależności powinny być względne w stosunku do pliku kompilacji rake.

Jaskółka oknówka
źródło