Pourquoi Ruby 1.9.2 supprime-t-il "." de LOAD_PATH, et quelle est l'alternative?

154

Les derniers ensembles de modifications de Ruby 1.9.2 ne font plus .partie du répertoire actuel de votreLOAD_PATH . J'ai un nombre non négligeable de fichiers Rakefiles qui supposent que cela .fait partie du LOAD_PATH, donc cela les a cassés (ils ont signalé "aucun fichier à charger" pour toutes les instructions exigent basées sur le chemin du projet). Y avait-il une justification particulière pour faire cela?

En ce qui concerne un correctif, l'ajout $: << "."partout fonctionne, mais semble incroyablement piraté et je ne veux pas faire cela. Quelle est la meilleure façon de rendre mes fichiers Rakefiles 1.9.2+ compatibles?

John Feminella
la source

Réponses:

141

Il a été considéré comme un risque de «sécurité».

Vous pouvez le contourner en utilisant des chemins absolus

File.expand_path(__FILE__) et al

ou faire

require './filename' (ironically).

ou en utilisant

require_relative 'filename'

ou ajouter un répertoire "include"

ruby -I . ...

ou le même, en utilisant irb;

$irb -I .
rogerdpack
la source
27
J'ai fini par utiliser require_relative. Merci.
John Feminella
11
Cela ressemble-t-il à la plupart des Unix qui n'incluent pas le répertoire actuel dans le chemin pour exécuter les exécutables?
Andrew Grimm
5
require './filename'ne fonctionne que si votre script est exécuté avec le répertoire de travail défini sur le même répertoire que celui où réside le script. Ce n'est souvent pas le cas dans les projets multi-répertoires.
mxcl
34

Il y a deux raisons:

  • robustesse et
  • Sécurité

Les deux sont basés sur le même principe sous-jacent: en général, vous ne pouvez tout simplement pas savoir quel est le répertoire actuel, lorsque votre code est exécuté. Ce qui signifie que, lorsque vous avez besoin d'un fichier et que vous dépendez de sa présence dans le répertoire actuel, vous n'avez aucun moyen de contrôler si ce fichier sera même présent ou s'il s'agit du fichier que vous attendez réellement d'y être.

Jörg W Mittag
la source
5
Je ne pense pas qu'imposer que deux fichiers soient au même endroit l'un par rapport à l'autre soit nécessairement une mauvaise exigence. Si c'était vrai, alors nous n'aurions aucune utilité pour les répertoires.
John Feminella
4
@John Feminella: qu'est-ce que cela a à voir avec le fait de placer des fichiers dans des chemins les uns par rapport aux autres? La question est de les mettre par rapport au .répertoire de travail courant. Si l'utilisateur se trouve cddans un répertoire différent, le répertoire de travail actuel change, et vous avez maintenant des fichiers require complètement différents en fonction du répertoire dans lequel l'utilisateur se trouvait lorsqu'il a appelé votre script. Je ne pense pas que ce soit une bonne idée.
Jörg W Mittag
Donc, pour maintenir une interface décente, vous devriez le faire? $: << File.dirname(__FILE__)
Joshua Cheek
4
@Joshua Cheek: Personnellement, je n'aime pas ça. (Mais s'il vous plaît ne regardez pas mon ancien code, car il est jonché de ce genre de choses :-)) Je prétends simplement que le librépertoire est sur le $LOAD_PATH, puis requiretous les fichiers relatifs à lib. En d'autres termes: je laisse à l'administrateur le soin de déterminer comment configurer le $LOAD_PATHcorrectement. Si vous utilisez RubyGems, c'est trivial, car RubyGems le fait automatiquement pour vous, et si vous utilisez des paquets Debian, alors c'est le travail du responsable du paquet. Dans l'ensemble, cela semble très bien fonctionner.
Jörg W Mittag
8
@Joshua Cheek: Aussi, comme une sorte de contrepoids à la suppression .de $LOAD_PATH, Ruby 1.9.2 introduit require_relativequel requirefichier ... surprise ... sa par rapport à l'emplacement du fichier en cours d'exécution (c'est-à-dire par rapport à File.dirname(__FILE__)).
Jörg W Mittag
16

Comme d'autres réponses le soulignent, c'est un risque de sécurité car .dans votre chemin de chargement fait référence au répertoire de travail actuel Dir.pwd, pas au répertoire du fichier en cours de chargement. Ainsi, quiconque exécute votre script peut changer cela simplement en cdallant dans un autre répertoire. Pas bon!

J'ai utilisé des chemins complets construits à partir __FILE__d'une alternative.

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

Contrairement à require_relative, ceci est rétrocompatible avec Ruby 1.8.7.

Jonathan Tran
la source
4
Il y a aussi cette variante (que je trouve personnellement plus lisible): require Pathname.new(__FILE__).dirname + 'filename'
Tyler Rick
8

Utilisation require_relative 'file_to_require'

Ajoutez ceci dans votre code pour faire fonctionner require_relative dans la 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
la source
3

J'ai trouvé que c'était un changement déconcertant jusqu'à ce que je réalise quelques choses.

Vous pouvez définir RUBYLIB dans votre .profile (Unix) et continuer votre vie comme vous le faisiez auparavant:

export RUBYLIB="."

Mais comme mentionné ci-dessus, il a longtemps été considéré comme dangereux de le faire.

Dans la grande majorité des cas, vous pouvez éviter les problèmes en appelant simplement vos scripts Ruby avec un "." par exemple ./scripts/server.

Dylan
la source
3

Comme Jörg W Mittag l'a souligné, je pense que ce que vous voulez utiliser, c'est require_relativeque le fichier dont vous avez besoin est relatif au fichier source de la requiredéclaration et non au répertoire de travail actuel.

Vos dépendances doivent être relatives à votre fichier de construction rake.

Martin
la source