Jaka jest najlepsza praktyka, jeśli chcę require
pliku względnej w Ruby i chcę go do pracy zarówno 1.8.x oraz> = 1.9.2?
Widzę kilka opcji:
- po prostu zrób
$LOAD_PATH << '.'
i zapomnij o wszystkim - robić
$LOAD_PATH << File.dirname(__FILE__)
require './path/to/file'
- sprawdź, czy
RUBY_VERSION
<1.9.2, a następnie zdefiniujrequire_relative
jakorequire
, użyjrequire_relative
później wszędzie tam, gdzie jest to potrzebne - sprawdź, czy
require_relative
już istnieje, jeśli tak, spróbuj postępować jak w poprzednim przypadku - używają dziwnych konstrukcji, takich jak - niestety nie wydaje się, aby działały w pełni w Rubim 1.9, ponieważ na przykład:
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>'
- Jeszcze dziwniejsza konstrukcja: wydaje się działać, ale jest dziwna i niezbyt ładna.
require File.join(File.expand_path(File.dirname(__FILE__)), 'path/to/file')
- Użyj klejnotów backportów - jest trochę ciężki, wymaga infrastruktury rubygemów i zawiera mnóstwo innych obejść, podczas gdy ja chcę po prostu
require
pracować z plikami względnymi.
W StackOverflow jest blisko powiązane pytanie, które zawiera więcej przykładów, ale nie daje jasnej odpowiedzi - co jest najlepszą praktyką.
Czy istnieje jakieś przyzwoite, akceptowane przez wszystkich uniwersalne rozwiązanie, które sprawi, że moja aplikacja będzie działać na Rubim <1.9.2 i> = 1.9.2?
AKTUALIZACJA
Wyjaśnienie: nie chcę tylko odpowiedzi typu „możesz zrobić X” - w rzeczywistości wspomniałem już o większości opcji, o których mowa. Chcę uzasadnienia , czyli dlaczego jest to najlepsza praktyka, jakie są jej wady i zalety oraz dlaczego należy ją wybrać spośród innych.
require
irequire_relative
?a.rb
i chciałeś, aby interpreter odczytywał i parsował zawartość plikub.rb
w bieżącym katalogu (zwykle w tym samym katalogu co wa.rb
), po prostu napiszrequire 'b'
i będzie dobrze, ponieważ domyślna ścieżka wyszukiwania zawiera bieżący katalog. W bardziej nowoczesnym Ruby 1.9 będziesz musiał pisaćrequire_relative 'b'
w tym przypadku, tak jakbyśrequire 'b'
szukał tylko w standardowych ścieżkach bibliotek. To jest coś, co łamie kompatybilność do przodu i do tyłu dla prostszych skryptów, które nie będą poprawnie instalowane (na przykład same skrypty instalacyjne ).backports
tylko dlarequire_relative
, zobacz moją odpowiedź ...Odpowiedzi:
Obejście tego problemu zostało właśnie dodane do klejnotu „aws”, więc pomyślałem, że udostępnię, ponieważ zainspirował go ten post.
https://github.com/appoxy/aws/blob/master/lib/awsbase/require_relative.rb
Pozwala to na użycie
require_relative
tak, jak w Ruby 1.9.2 w Ruby 1.8 i 1.9.1.źródło
require_relative
funkcja jest zawarta w projekcie rozszerzenia podstawowych bibliotek Ruby, które można znaleźć tutaj: rubyforge.org/projects/extensions. Powinno być możliwe ich zainstalowaniegem install extensions
. Następnie w swoim kodzie dodaj następujący wiersz przedrequire_relative
: require 'extensions / all' (pochodzi z postu Aurril tutaj )Zanim wykonałem skok do 1.9.2, użyłem następujących dla wymagań względnych:
To trochę dziwne, gdy widzisz go po raz pierwszy, ponieważ wygląda na to, że na początku jest dodatkowe „…”. Powodem jest to, że
expand_path
rozszerzy ścieżkę względem drugiego argumentu, a drugi argument zostanie zinterpretowany tak, jakby był katalogiem.__FILE__
oczywiście nie jest katalogiem, ale to nie ma znaczenia, ponieważexpand_path
nie obchodzi czy istnieją pliki, czy nie, to po prostu zastosować kilka zasad, aby rozwinąć takie rzeczy..
,.
i~
. Jeśli uda ci się przejść przez początkową „minutę oczekiwania, czy nie ma tam dodatkowej..
?” Myślę, że powyższa linia działa całkiem nieźle.Przy założeniu, że
__FILE__
to/absolute/path/to/file.rb
, co się dzieje, żeexpand_path
wybuduje ciąg/absolute/path/to/file.rb/../relative/path
, a następnie zastosować regułę, która mówi, że..
należy usunąć składnik ścieżki przed nim (file.rb
w tym przypadku), wracając/absolute/path/to/relative/path
.Czy to najlepsza praktyka? Zależy od tego, co przez to rozumiesz, ale wygląda na to, że jest to cała baza kodu Railsów, więc powiedziałbym, że jest to przynajmniej dość powszechny idiom.
źródło
Kilof ma do tego fragment dla wersji 1.8. Oto ona:
Zasadniczo używa tylko tego, co odpowiedział Theo, ale nadal możesz używać
require_relative
.źródło
$RUBY_VERSION
lub sprawdzając, czyrequire_relative
istnieje bezpośrednio?require_relative
jest zdefiniowana.To nie jest dobry nawyk bezpieczeństwa: dlaczego miałbyś ujawniać cały katalog?
To nie działa, jeśli RUBY_VERSION <1.9.2
Odpowiedziałeś już, dlaczego nie są to najlepsze opcje.
To może działać, ale istnieje bezpieczniejszy i szybszy sposób: radzenie sobie z wyjątkiem LoadError:
źródło
Jestem fanem używania klejnotu rbx-require-względny ( źródło ). Pierwotnie został napisany dla Rubiniusa, ale obsługuje także MRI 1.8.7 i nie robi nic w 1.9.2. Wymaganie klejnotu jest proste i nie muszę wrzucać fragmentów kodu do mojego projektu.
Dodaj go do swojego Gemfile:
Wtedy
require 'require_relative'
przed tobąrequire_relative
.Na przykład jeden z moich plików testowych wygląda następująco:
Jest to najczystsze rozwiązanie spośród wszystkich tych IMO, a klejnot nie jest tak ciężki jak backporty.
źródło
Plik
backports
Gem pozwala teraz indywidualny załadunek backports.Możesz wtedy po prostu:
Nie
require
wpłynie to na nowsze wersje ani nie zaktualizuje żadnych innych wbudowanych metod.źródło
Inną opcją jest poinformowanie tłumacza, które ścieżki mają przeszukiwać
źródło
Jednym z problemów, których nie zauważyłem w rozwiązaniach opartych na __FILE__, jest to, że psują się w odniesieniu do dowiązań symbolicznych. Na przykład powiedz, że mam:
Główny skrypt, punkt wejścia, aplikacja to foo.rb. Ten plik jest powiązany z ~ / Scripts / foo, który znajduje się w mojej $ PATH. Ta instrukcja wymagania jest zepsuta, kiedy wykonuję 'foo':
Ponieważ __FILE__ to ~ / Scripts / foo, więc powyższa instrukcja require szuka ~ / Scripts / foo / lib / someinclude.rb, który oczywiście nie istnieje. Rozwiązanie jest proste. Jeśli __FILE__ jest dowiązaniem symbolicznym, należy go usunąć. Pathname # realpath pomoże nam w tej sytuacji:
źródło
Gdybyś budował klejnot, nie chciałbyś zanieczyszczać ścieżki ładowania.
Ale w przypadku samodzielnej aplikacji bardzo wygodnie jest po prostu dodać bieżący katalog do ścieżki ładowania, tak jak robisz to w pierwszych 2 przykładach.
Mój głos trafia do pierwszej opcji na liście.
Bardzo chciałbym zobaczyć solidną literaturę dotyczącą najlepszych praktyk Rubiego.
źródło
Zdefiniowałbym własną,
relative_require
gdyby nie istniała (tj. Poniżej 1.8), a następnie użyłbym wszędzie tej samej składni.źródło
Sposób Ruby on Rails:
źródło