web-dev-qa-db-fra.com

Ajouter un répertoire à $ LOAD_PATH (Ruby)

J'ai vu deux techniques couramment utilisées pour ajouter le répertoire du fichier en cours d'exécution à la variable $ LOAD_PATH (ou $ :). Je vois les avantages de le faire si vous ne travaillez pas avec un bijou. L'une semble plus verbeuse que l'autre, bien sûr, mais y a-t-il une raison de choisir l'un plutôt que l'autre?

La première méthode, verbeuse (pourrait être excessive):

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

et le plus simple, rapide et sale:

$:.unshift File.dirname(__FILE__)

Une raison d'aller avec l'un sur l'autre?

84
Mark W

Je dirais que go avec $:.unshift File.dirname(__FILE__) par rapport à l’autre, tout simplement parce que j’en ai vu beaucoup plus l’utilisation dans le code que le $LOAD_PATH et elle est aussi plus courte!

47
Ryan Bigg

Le chemin de chargement Ruby est très souvent vu écrit comme $:, mais ce n'est pas parce qu'il est court qu'il est meilleur. Si vous préférez la clarté à l'intelligence, ou si la brièveté en soi provoque des démangeaisons, vous n'avez pas besoin de le faire simplement parce que tout le monde le fait. Dire bonjour à ...

$LOAD_PATH

... et dire au revoir à ...

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

Je n'aime pas trop la façon rapide et sale…. Toute personne nouvelle à Ruby réfléchira à ce que $:. est.

Je trouve cela plus évident.

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

Ou si je tiens à avoir le chemin complet ...

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

MISE À JOUR2009/09/10

Récemment, j'ai fait ce qui suit:

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

Je l'ai vu dans un tas de projets Ruby différents en naviguant sur GitHub.

Semble être la convention?

21
Luke Antins

Si vous tapez script/console dans votre projet Rails et entrez $:, vous obtiendrez un tableau contenant tous les répertoires nécessaires au chargement de Ruby. La conclusion de ce petit exercice est que $: est un tableau. Cela étant, vous pouvez y exécuter des fonctions telles que l'ajout préalable de répertoires avec la méthode unshift ou l'opérateur <<. Comme vous l'avez sous-entendu dans votre déclaration, $: et $LOAD_PATH sont identiques.

L’inconvénient de le faire de la manière rapide et sale que vous avez mentionnée est le suivant: si le répertoire est déjà dans votre chemin d’amorçage, il se répète.

Exemple:

J'ai créé un plugin appelé todo. Mon répertoire est structuré comme suit:

/---vendeur
 | 
 | ---/plugins 
 | 
 | ---/todo 
 | 
 | ---/lib 
 | 
 | ---/app 
 | 
 | ---/models 
 | ---/contrôleurs 
 | 
 | ---/Rails 
 | 
 | --- init.rb 

Dans le fichier init.rb, j'ai entré le code suivant:

## 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 

Notez comment je dis au bloc de code d'effectuer les actions à l'intérieur du bloc sur les chaînes «modèles», «contrôleurs» et «modèles», où je répète «modèles». (Pour votre information, %w{ ... } est juste un autre moyen de dire à Ruby de tenir un tableau de chaînes). Lorsque je lance script/console, je tape ce qui suit:

>> puts $:

Et je tape ceci pour qu'il soit plus facile de lire le contenu de la chaîne. Le résultat obtenu est:

...
...
./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

Comme vous pouvez le constater, bien que ce soit un exemple aussi simple que je pourrais créer en utilisant un projet sur lequel je travaille actuellement, si vous ne faites pas attention, la méthode rapide et sale conduira à des chemins répétés. Le plus long chemin vérifiera les chemins répétés et s'assurera qu'ils ne se produisent pas.

Si vous êtes un programmeur Rails expérimenté, vous avez probablement une très bonne idée de ce que vous faites et ne commettez probablement pas l'erreur de répéter des chemins. Si vous êtes un débutant, je choisirais le chemin le plus long jusqu'à ce que vous compreniez vraiment ce que vous faites.

8
Dyba

Le meilleur que j'ai rencontré pour ajouter un répertoire via un chemin relatif lors de l'utilisation de Rspec. Je le trouve assez prolixe mais c'est quand même un beau paquebot.

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

Il existe une gemme qui vous permettra de configurer votre chemin de chargement avec un code plus net et plus propre. Découvrez ceci: https://github.com/nayyara-samuel/load-path .

Il a aussi une bonne documentation

1
Rubyist

Je sais que cette question a été posée pour la première fois depuis longtemps, mais j'ai une réponse supplémentaire à partager.

J'ai plusieurs applications Ruby qui ont été développées par un autre programmeur au cours de plusieurs années et qui réutilisent les mêmes classes dans les différentes applications bien qu'elles puissent accéder à la même base de données. Dans la mesure où cela enfreint la règle DRY, j'ai décidé de créer une bibliothèque de classes à partager avec toutes les applications Ruby. J'aurais pu le mettre dans la bibliothèque principale Ruby, mais cela masquerait un code personnalisé dans la base de code commune, ce que je ne voulais pas faire.

J'ai eu un problème où j'ai eu un conflit de nom entre un nom déjà défini "profile.rb" et une classe que j'utilisais. Ce conflit n'était pas un problème jusqu'à ce que j'essaye de créer la bibliothèque de code commune. Normalement, Ruby commence par rechercher les emplacements des applications, puis les emplacements $ LOAD_PATH.

Le fichier application_controller.rb n'a pas pu trouver la classe que j'ai créée et a jeté une erreur sur la définition d'origine car il ne s'agit pas d'une classe. Depuis que j'ai supprimé la définition de classe de la section app/models de l'application, Ruby n'a pas pu la trouver et a cherché dans les chemins Ruby.

J'ai donc modifié la variable $ LOAD_PATH pour inclure un chemin d'accès au répertoire de la bibliothèque que j'utilisais. Cela peut être fait dans le fichier environment.rb au moment de l'initialisation.

Même avec le nouveau répertoire ajouté au chemin de recherche, Ruby renvoyait une erreur car il utilisait préférentiellement le fichier défini par le système en premier. Le chemin de recherche dans la variable $ LOAD_PATH recherche préférentiellement les chemins Ruby en premier.

Je devais donc modifier l'ordre de recherche afin que Ruby trouve la classe dans ma bibliothèque commune avant de rechercher les bibliothèques intégrées.

Ce code l'a fait dans le fichier environment.rb:

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

Je ne pense pas que vous puissiez utiliser les constructions de codage avancées données précédemment à ce niveau, mais cela fonctionne parfaitement si vous souhaitez configurer quelque chose au moment de l'initialisation dans votre application. Vous devez conserver l'ordre d'origine de la variable originale $ LOAD_PATH lors de l'ajout de cette variable à la nouvelle variable, faute de quoi certaines des principales classes Ruby seront perdues.

Dans le fichier application_controller.rb, j’utilise simplement un

require 'profile'
require 'etc' #etc

et cela charge les fichiers de bibliothèque personnalisés pour l’ensemble de l’application, c’est-à-dire qu’il n’est pas nécessaire d’utiliser des commandes require dans chaque contrôleur.

Pour moi, c’était la solution que je cherchais et je pensais l’ajouter à cette réponse pour transmettre l’information.

0
Timothy Dooling