Por que o Ruby 1.9.2 remove "." de LOAD_PATH, e qual é a alternativa?

154

Os últimos conjuntos de alterações no Ruby 1.9.2 não fazem mais o diretório atual .parte do seu LOAD_PATH. Eu tenho um número não trivial de Rakefiles que assumem que .faz parte do LOAD_PATH, então isso os quebrou (eles relataram "nenhum arquivo para carregar", pois todos exigem instruções baseadas no caminho do projeto). Havia uma justificativa específica para fazer isso?

Quanto a uma correção, adicionar em $: << "."qualquer lugar funciona, mas parece incrivelmente hacky e eu não quero fazer isso. Qual é a maneira preferida de tornar meu Rakefiles 1.9.2+ compatível?

John Feminella
fonte

Respostas:

141

Foi considerado um risco de "segurança".

Você pode contornar isso usando caminhos absolutos

File.expand_path(__FILE__) et al

ou fazendo

require './filename' (ironically).

ou usando

require_relative 'filename'

ou adicionando um diretório "include"

ruby -I . ...

ou o mesmo, usando irb;

$irb -I .
rogerdpack
fonte
27
Acabei usando require_relative. Obrigado.
John Feminella
11
É semelhante à maioria dos unixes que não incluem o diretório atual no caminho para a execução de executáveis?
Andrew Grimm
5
require './filename'funciona apenas se o seu script for executado com o diretório de trabalho definido no mesmo diretório em que o script reside. Isso geralmente não é o caso em projetos com vários diretórios.
Mxcl
34

Há duas razões:

  • robustez e
  • segurança

Ambos são baseados no mesmo princípio subjacente: em geral, você simplesmente não pode saber qual é o diretório atual quando seu código é executado. O que significa que, quando você exige um arquivo e depende que ele esteja no diretório atual, você não tem como controlar se esse arquivo estará lá ou se é o arquivo que você realmente espera estar lá.

Jörg W Mittag
fonte
5
Não acho que impor que dois arquivos estejam no mesmo local em relação um ao outro é necessariamente um requisito ruim. Se isso fosse verdade, não teríamos utilidade para diretórios.
John Feminella
4
@ John Feminella: o que isso tem a ver com a colocação de arquivos em caminhos relativos entre si? A questão é colocá-los em relação a ., ou seja, o diretório de trabalho atual. Se o usuário estiver cdem um diretório diferente, o diretório de trabalho atual será alterado e agora você terá arquivos require completamente diferentes, dependendo do diretório em que o usuário estava quando chamou o script. Não acho que seja uma boa ideia.
Jörg W Mittag
Então, para manter uma interface decente, você deve fazer isso? $: << File.dirname(__FILE__)
Joshua Cheek
4
@ Joshua Cheek: Pessoalmente, eu não gosto disso. (Mas, por favor, não olhe para o meu código mais antigo, porque está cheio desse tipo de coisa :-)). Simplesmente finjo que o libdiretório está no $LOAD_PATHe então requiretodos os arquivos relativos a lib. Em outras palavras: deixo para o administrador descobrir como configurar $LOAD_PATHcorretamente. Se você usa RubyGems, isso é trivial, porque o RubyGems faz isso automaticamente para você, e se você usa pacotes Debian, esse é o trabalho do mantenedor de pacotes. Em suma, parece funcionar muito bem.
Jörg W Mittag
8
@Joshua Cheek: Além disso, como uma espécie de contrapeso para a remoção .de $LOAD_PATH, Ruby 1.9.2 introduz require_relativeque ... surpresa ... requirearquivo de sa em relação à localização do arquivo atualmente em execução (ou seja, em relação ao File.dirname(__FILE__)).
Jörg W Mittag
16

Como outras respostas apontam, é um risco de segurança, porque .no caminho de carregamento refere-se ao diretório de trabalho atual Dir.pwd, não ao diretório do arquivo atual que está sendo carregado. Portanto, quem estiver executando seu script pode mudar isso simplesmente cdinserindo outro diretório. Não é bom!

Eu tenho usado caminhos completos construídos __FILE__como uma alternativa.

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

Ao contrário require_relative, isso é compatível com o Ruby 1.8.7.

Jonathan Tran
fonte
4
Há também essa variação (que eu pessoalmente acho mais legível): require Pathname.new(__FILE__).dirname + 'filename'
Tyler Rick
8

Usar require_relative 'file_to_require'

Jogue isso no seu código para fazer o require_relative funcionar na 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
fonte
3

Achei isso uma mudança confusa, até que percebi algumas coisas.

Você pode definir o RUBYLIB no seu .profile (Unix) e continuar com a vida como fez antes:

export RUBYLIB="."

Mas, como mencionado acima, há muito tempo é considerado perigoso fazê-lo.

Na grande maioria dos casos, você pode evitar problemas simplesmente chamando seus scripts Ruby com um '.' por exemplo ./scripts/server.

Dylan
fonte
3

Como Jörg W Mittag apontou, acho que o que você deseja usar é require_relativeque o arquivo necessário seja relativo ao arquivo de origem da requiredeclaração e não ao diretório de trabalho atual.

Suas dependências devem ser relativas ao seu arquivo rake build.

Martin
fonte