¿Cuál es la mejor práctica si quiero require
un archivo relativo en Ruby y quiero que funcione tanto en 1.8.xy> = 1.9.2?
Veo algunas opciones:
- solo hazlo
$LOAD_PATH << '.'
y olvídalo todo - hacer
$LOAD_PATH << File.dirname(__FILE__)
require './path/to/file'
- verifique si
RUBY_VERSION
<1.9.2, luego definarequire_relative
comorequire
, use enrequire_relative
todas partes donde sea necesario después - compruebe si
require_relative
ya existe, si es así, intente continuar como en el caso anterior - use construcciones extrañas como , por desgracia, no parecen funcionar completamente en Ruby 1.9 porque, por ejemplo:
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>'
- Construcción aún más extraña: parece funcionar, pero es raro y no del todo bien parecido.
require File.join(File.expand_path(File.dirname(__FILE__)), 'path/to/file')
- Use gemas de backports : es un poco pesado, requiere infraestructura de rubygems e incluye toneladas de otras soluciones, mientras que solo quiero
require
trabajar con archivos relativos.
Hay una pregunta estrechamente relacionada en StackOverflow que da algunos ejemplos más, pero no da una respuesta clara, que es una práctica recomendada.
¿Existe alguna solución universal aceptable y aceptada por todos para hacer que mi aplicación se ejecute en Ruby <1.9.2 y> = 1.9.2?
ACTUALIZAR
Aclaración: no quiero solo respuestas como "puedes hacer X"; de hecho, ya he mencionado la mayoría de las opciones en cuestión. Quiero justificación , es decir, por qué es una mejor práctica, cuáles son sus pros y sus contras y por qué debería elegirse entre los demás.
require
yrequire_relative
?a.rb
y deseaba que el intérprete leyera y analizara el contenido del archivob.rb
en el directorio actual (generalmente el mismo directorio que cona.rb
), simplemente escribiríarequire 'b'
y estaría bien, ya que la ruta de búsqueda predeterminada incluía el directorio actual. En Ruby 1.9 más moderno, tendrá que escribirrequire_relative 'b'
en este caso, yarequire 'b'
que solo buscaría en rutas de biblioteca estándar. Eso es lo que rompe la compatibilidad hacia adelante y hacia atrás para secuencias de comandos más simples que no se instalarán correctamente (por ejemplo, instalen las secuencias de comandos ellos mismos).backports
solo pararequire_relative
, vea mi respuesta ...Respuestas:
Se acaba de agregar una solución alternativa a la gema 'aws', así que pensé en compartirla, ya que se inspiró en esta publicación.
https://github.com/appoxy/aws/blob/master/lib/awsbase/require_relative.rb
Esto le permite usar
require_relative
como lo haría en ruby 1.9.2 en ruby 1.8 y 1.9.1.fuente
require_relative
función se incluye en un proyecto de extensión de las bibliotecas principales de Ruby, que se encuentra aquí: rubyforge.org/projects/extensions . Debería poder instalarlas congem install extensions
. Luego, en su código, agregue la siguiente línea antes derequire_relative
: require 'extensiones / all' (procedente de la publicación de Aurril aquí )Antes de dar el salto a 1.9.2 usé lo siguiente para los requisitos relativos:
Es un poco extraño la primera vez que lo ves, porque parece que hay un '...' extra al comienzo. La razón es que
expand_path
expandirá una ruta relativa al segundo argumento, y el segundo argumento se interpretará como si fuera un directorio.__FILE__
obviamente no es un directorio, pero eso no importa yaexpand_path
que no importa si los archivos existen o no, solo aplicará algunas reglas para expandir cosas como..
,.
y~
. Si puede superar el "valor de espera inicial, ¿no hay un extra..
allí?" Creo que la línea de arriba funciona bastante bien.Suponiendo que
__FILE__
es así/absolute/path/to/file.rb
, lo que sucede es queexpand_path
construirá la cadena/absolute/path/to/file.rb/../relative/path
y luego aplicará una regla que dice que..
debería eliminar el componente de ruta antes (file.rb
en este caso), regresando/absolute/path/to/relative/path
.¿Es esta la mejor práctica? Depende de lo que quieras decir con eso, pero parece que está en toda la base de código de Rails, por lo que diría que es al menos un idioma bastante común.
fuente
El pico tiene un fragmento para esto para 1.8. Aquí está:
Básicamente solo usa lo que Theo respondió, pero aún así puedes usarlo
require_relative
.fuente
$RUBY_VERSION
o comprobando sirequire_relative
existe directamente?require_relative
está definido.No es un buen hábito de seguridad: ¿por qué debería exponer todo su directorio?
Esto no funciona si RUBY_VERSION <1.9.2
Ya ha respondido por qué estas no son las mejores opciones.
Esto puede funcionar, pero hay una forma más segura y rápida: lidiar con la excepción LoadError:
fuente
Soy fanático de usar la gema ( fuente ) rbx-require-relative . Originalmente fue escrito para Rubinius, pero también es compatible con MRI 1.8.7 y no hace nada en 1.9.2. Requerir una gema es simple, y no tengo que tirar fragmentos de código en mi proyecto.
Agréguelo a su Gemfile:
Entonces
require 'require_relative'
ante tirequire_relative
.Por ejemplo, uno de mis archivos de prueba se ve así:
Esta es la solución más limpia de cualquiera de estos IMO, y la gema no es tan pesada como los backports.
fuente
La
backports
gema ahora permite la carga individual de backports.Entonces podrías simplemente:
Esto
require
no afectará a las versiones más nuevas, ni actualizará ningún otro método incorporado.fuente
Otra opción es decirle al intérprete qué rutas buscar
fuente
Un problema que no he visto señalado con las soluciones basadas en __FILE__ es que se rompen con respecto a los enlaces simbólicos. Por ejemplo, decir que tengo:
El script principal, el punto de entrada, la aplicación es foo.rb. Este archivo está vinculado a ~ / Scripts / foo que está en mi $ PATH. Esta declaración de requerimiento se rompe cuando ejecuto 'foo':
Debido a que __FILE__ es ~ / Scripts / foo, la declaración require anterior busca ~ / Scripts / foo / lib / someinclude.rb que obviamente no existe. La solución es simple. Si __FILE__ es un enlace simbólico, debe ser desreferenciado. Pathname # realpath nos ayudará con esta situación:
fuente
Si estuviera construyendo una gema, no querría contaminar la ruta de carga.
Pero, en el caso de una aplicación independiente, es muy conveniente simplemente agregar el directorio actual a la ruta de carga como lo hace en los primeros 2 ejemplos.
Mi voto va a la primera opción en la lista.
Me encantaría ver un poco de literatura sólida sobre las mejores prácticas de Ruby.
fuente
Definiría el mío
relative_require
si no existe (es decir, bajo 1.8) y luego usaría la misma sintaxis en todas partes.fuente
Ruby on Rails:
fuente