¿Por qué Ruby 1.9.2 elimina "." de LOAD_PATH, y ¿cuál es la alternativa?

154

Los últimos conjuntos de cambios a Ruby 1.9.2 ya no hacen que el directorio actual sea .parte de su LOAD_PATH. Tengo un número no trivial de Rakefiles que asumen que .es parte del LOAD_PATH, por lo que esto los rompió (informaron que "no se debe cargar ese archivo" para todas las declaraciones de requerimiento basadas en la ruta del proyecto). ¿Hubo una justificación particular para hacer esto?

En cuanto a una solución, agregar en $: << "."todas partes funciona, pero parece increíblemente hacky y no quiero hacer eso. ¿Cuál es la forma preferida de hacer que mis Rakefiles 1.9.2+ sean compatibles?

John Feminella
fuente

Respuestas:

141

Se consideró un riesgo de "seguridad".

Puedes evitarlo usando rutas absolutas

File.expand_path(__FILE__) et al

o haciendo

require './filename' (ironically).

o usando

require_relative 'filename'

o agregar un directorio "incluir"

ruby -I . ...

o lo mismo, usando irb;

$irb -I .
rogerdpack
fuente
27
Terminé usando require_relative. Gracias.
John Feminella
11
¿Es similar a la mayoría de los Unixes sin incluir el directorio actual en la ruta para ejecutar ejecutables?
Andrew Grimm
55
require './filename'solo funciona si su script se ejecuta con el directorio de trabajo establecido en el mismo directorio en el que reside el script. Este no suele ser el caso en proyectos de directorios múltiples.
mxcl
34

Hay dos razones:

  • robustez y
  • seguridad

Ambos se basan en el mismo principio subyacente: en general, simplemente no puede saber cuál es el directorio actual, cuando se ejecuta su código. Lo que significa que, cuando necesita un archivo y depende de que esté en el directorio actual, no tiene forma de controlar si ese archivo estará allí, o si es el archivo que realmente espera que esté allí.

Jörg W Mittag
fuente
55
No creo que exigir que dos archivos estén en la misma ubicación uno con respecto al otro es necesariamente un mal requisito. Si eso fuera cierto, entonces no tendríamos uso para directorios.
John Feminella
44
@John Feminella: ¿qué tiene esto que ver con poner los archivos en rutas relacionadas entre sí? La pregunta es sobre ponerlos en relación con ., es decir, el directorio de trabajo actual. Si el usuario cdestá en un directorio diferente, el directorio de trabajo actual cambia, y ahora los archivos son require completamente diferentes dependiendo de en qué directorio se encontraba el usuario cuando llamó a su script. No creo que sea una buena idea.
Jörg W Mittag
Entonces, para mantener una interfaz decente, ¿debería hacer esto? $: << File.dirname(__FILE__)
Joshua Cheek
44
@ Joshua Cheek: Personalmente, no me gusta eso. (Pero no mires mi código anterior, porque está lleno de ese tipo de cosas :-)). Simplemente pretendo que el libdirectorio está en $LOAD_PATHy luego requiretodos los archivos relativos a lib. En otras palabras: le dejo al administrador que descubra cómo configurarlo $LOAD_PATHcorrectamente. Si usa RubyGems, eso es trivial, porque RubyGems lo hace automáticamente por usted, y si usa paquetes Debian, entonces es el trabajo del mantenedor de paquetes. En general, parece funcionar bastante bien.
Jörg W Mittag
8
@Joshua Cheek: También, como una especie de contrapeso a la eliminación .de $LOAD_PATH, Ruby 1.9.2 introduce require_relativela que ... sorpresa ... requiresa archivo relativa a la ubicación del archivo que se está ejecutando (es decir, en relación con File.dirname(__FILE__)).
Jörg W Mittag
16

Como otras respuestas señalan, es un riesgo de seguridad porque .en su ruta de carga se refiere al directorio de trabajo actual Dir.pwd, no al directorio del archivo actual que se está cargando. Entonces, quien ejecute su script puede cambiar esto simplemente cdyendo a otro directorio. ¡No está bien!

He estado usando caminos completos construidos __FILE__como una alternativa.

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

A diferencia require_relative, esto es retrocompatible con Ruby 1.8.7.

Jonathan Tran
fuente
44
También existe esta variación (que personalmente encuentro más legible): require Pathname.new(__FILE__).dirname + 'filename'
Tyler Rick
8

Utilizar require_relative 'file_to_require'

Agregue esto en su código para hacer que require_relative funcione en 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
fuente
3

Encontré que esto era un cambio confuso hasta que me di cuenta de un par de cosas.

Puede configurar RUBYLIB en su .profile (Unix) y continuar con la vida como lo hizo antes:

export RUBYLIB="."

Pero como se mencionó anteriormente, durante mucho tiempo se ha considerado inseguro hacerlo.

Para la gran mayoría de los casos, puede evitar problemas simplemente llamando a sus scripts de Ruby con un '.' por ejemplo ./scripts/server.

Dylan
fuente
3

Como Jörg W Mittag señaló, creo que lo que quiere usar es require_relativeque el archivo que necesita es relativo al archivo fuente de la requiredeclaración y no al directorio de trabajo actual.

Sus dependencias deben ser relativas a su archivo de compilación de rastrillo.

Martín
fuente