Quelle est la meilleure pratique si je veux require
un fichier relatif dans Ruby et que je veux qu'il fonctionne à la fois dans 1.8.x et> = 1.9.2?
Je vois quelques options:
- fais
$LOAD_PATH << '.'
et oublie tout - faire
$LOAD_PATH << File.dirname(__FILE__)
require './path/to/file'
- vérifier si
RUBY_VERSION
<1.9.2, puis définirrequire_relative
commerequire
, utiliserrequire_relative
partout où c'est nécessaire par la suite - vérifiez s'il
require_relative
existe déjà, si c'est le cas, essayez de procéder comme dans le cas précédent - utilisez des constructions étranges telles que - hélas, elles ne semblent pas fonctionner complètement dans Ruby 1.9, car, par exemple:
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>'
- Construction encore plus étrange: semble fonctionner, mais c'est étrange et pas très beau.
require File.join(File.expand_path(File.dirname(__FILE__)), 'path/to/file')
- Utilisez la gemme de backports - c'est un peu lourd, cela nécessite une infrastructure rubygems et inclut des tonnes d'autres solutions de contournement, alors que je veux juste
require
travailler avec des fichiers relatifs.
Il y a une question étroitement liée chez StackOverflow qui donne quelques exemples supplémentaires, mais elle ne donne pas de réponse claire - ce qui est une meilleure pratique.
Existe-t-il une solution universelle décente et acceptée par tous pour faire fonctionner mon application à la fois sur Ruby <1.9.2 et> = 1.9.2?
METTRE À JOUR
Clarification: je ne veux pas seulement des réponses comme "vous pouvez faire X" - en fait, j'ai déjà mentionné la plupart des choix en question. Je veux une justification , c'est-à-dire pourquoi c'est une meilleure pratique, quels sont ses avantages et ses inconvénients et pourquoi elle devrait être choisie parmi les autres.
require
etrequire_relative
?a.rb
et que vous vouliez que l'interpréteur lise et analyse le contenu du fichierb.rb
dans le répertoire actuel (généralement le même répertoire qu'aveca.rb
), vous écrivez simplementrequire 'b'
et ce serait bien car le chemin de recherche par défaut incluait le répertoire actuel. Dans Ruby 1.9 plus moderne, vous devrez écrirerequire_relative 'b'
dans ce cas, comme lerequire 'b'
ferait une recherche uniquement dans les chemins de bibliothèque standard. C'est ce qui rompt la compatibilité ascendante et descendante pour les scripts plus simples qui ne seront pas installés correctement (par exemple, installer les scripts eux-mêmes).backports
juste pourrequire_relative
, voir ma réponse ...Réponses:
Une solution de contournement pour cela a été juste ajoutée à la gemme 'aws', alors j'ai pensé que je la partagerais car elle était inspirée par cet article.
https://github.com/appoxy/aws/blob/master/lib/awsbase/require_relative.rb
Cela vous permet d'utiliser
require_relative
comme vous le feriez dans ruby 1.9.2 dans ruby 1.8 et 1.9.1.la source
require_relative
fonction est incluse dans un projet d'extension des bibliothèques de base Ruby, trouvé ici: rubyforge.org/projects/extensions Vous devriez pouvoir les installer avecgem install extensions
. Ensuite, dans votre code, ajoutez la ligne suivante avant lerequire_relative
: require 'extensions / all' (provenant du message d'Aurril ici )Avant de passer à la 1.9.2, j'ai utilisé ce qui suit pour les exigences relatives:
C'est un peu bizarre la première fois que vous le voyez, car on dirait qu'il y a un "..." supplémentaire au début. La raison en est que
expand_path
cela développera un chemin par rapport au second argument, et le second argument sera interprété comme s'il s'agissait d'un répertoire.__FILE__
Ce n'est évidemment pas un répertoire, mais cela n'a pas d'importance car peu importeexpand_path
si les fichiers existent ou non, il appliquera simplement quelques règles pour développer des choses comme..
,.
et~
. Si vous pouvez surmonter le "waitaminute initial, n'y a-t-il pas un supplément..
?" Je pense que la ligne ci-dessus fonctionne assez bien.En supposant que
__FILE__
c'est le cas/absolute/path/to/file.rb
, ce qui se passe est queexpand_path
cela construira la chaîne/absolute/path/to/file.rb/../relative/path
, puis appliquera une règle qui dit que..
devrait supprimer le composant de chemin avant lui (file.rb
dans ce cas), en retournant/absolute/path/to/relative/path
.Est-ce la meilleure pratique? Cela dépend de ce que vous entendez par là, mais il semble que tout soit dans la base de code de Rails, alors je dirais que c'est au moins un idiome assez courant.
la source
La pioche a un extrait pour cela pour 1.8. C'est ici:
Il utilise essentiellement ce que Theo a répondu, mais vous pouvez toujours l'utiliser
require_relative
.la source
$RUBY_VERSION
ou en vérifiant s'ilrequire_relative
existe directement?require_relative
est défini.Ce n'est pas une bonne habitude de sécurité: pourquoi devriez-vous exposer tout votre répertoire?
Cela ne fonctionne pas si RUBY_VERSION <1.9.2
Vous avez déjà expliqué pourquoi ce ne sont pas les meilleures options.
Cela peut fonctionner, mais il existe un moyen plus sûr et plus rapide: pour gérer l'exception LoadError:
la source
Je suis fan de l'utilisation de la gemme relative rbx-require-relative ( source ). Il a été écrit à l'origine pour Rubinius, mais il prend également en charge MRI 1.8.7 et ne fait rien dans 1.9.2. Exiger une gemme est simple et je n'ai pas à lancer d'extraits de code dans mon projet.
Ajoutez-le à votre Gemfile:
Puis
require 'require_relative'
devant toirequire_relative
.Par exemple, l'un de mes fichiers de test ressemble à ceci:
C'est la solution la plus propre de tous ces IMO, et le bijou n'est pas aussi lourd que les backports.
la source
La
backports
gemme permet désormais le chargement individuel des backports.Vous pourriez alors simplement:
Cela
require
n'affectera pas les versions plus récentes et ne mettra pas à jour les autres méthodes intégrées.la source
Une autre option consiste à indiquer à l'interpréteur les chemins à rechercher
la source
Un problème que je n'ai pas vu souligné avec les solutions basées sur __FILE__ est qu'elles se cassent en ce qui concerne les liens symboliques. Par exemple, disons que j'ai:
Le script principal, le point d'entrée, l'application est foo.rb. Ce fichier est lié à ~ / Scripts / foo qui se trouve dans mon $ PATH. Cette instruction require est interrompue lorsque j'exécute 'foo':
Parce que __FILE__ est ~ / Scripts / foo, l'instruction require ci-dessus recherche ~ / Scripts / foo / lib / someinclude.rb qui n'existe évidemment pas. La solution est simple. Si __FILE__ est un lien symbolique, il doit être déréférencé. Pathname # realpath nous aidera dans cette situation:
la source
Si vous construisez une gemme, vous ne voudriez pas polluer le chemin de chargement.
Mais, dans le cas d'une application autonome, il est très pratique d'ajouter simplement le répertoire actuel au chemin de chargement comme vous le faites dans les 2 premiers exemples.
Mon vote va à la première option de la liste.
J'aimerais voir une documentation solide sur les meilleures pratiques Ruby.
la source
Je définirais le mien
relative_require
s'il n'existe pas (c'est-à-dire sous 1.8) et utiliserais la même syntaxe partout.la source
Ruby on Rails façon:
la source