¿La mejor manera de requerir todos los archivos de un directorio en ruby?


351

¿Cuál es la mejor manera de requerir todos los archivos de un directorio en ruby?


Puede crear un archivo con el mismo nombre del directorio y hacer que requiera todos los archivos. RSpec hace esto.
pedromanoel

Respuestas:


462

Qué tal si:

Dir["/path/to/directory/*.rb"].each {|file| require file }

18
Según Pickaxe, la extensión .rb es opcional. Técnicamente cambia el significado: "require 'foo.rb'" requiere foo.rb, mientras que "require 'foo'" podría requerir foo.rb, foo.so o foo.dll.
Sam Stokes

28
Hay un error sutil para no quitar la extensión. Si alguna otra parte de las llamadas de código requiere 'foo', ruby ​​volverá a cargar el mismo archivo, lo que puede provocar errores espurios. Agregué mi propia respuesta que explica eso y muestra cómo quitar la extensión.
Pete Hodgson

44
@Pete, ¿sigue siendo cierto? Ver el comentario de Rene a continuación.
Andres Riofrio

55
Esto puede ser obvio, pero vale la pena señalar que soltar el .rb también requerirá cualquier archivo que no sea .rb en el directorio, lo que podría no ser deseado.
user2398029

10
La sugerencia de @ PeteHodgson es inexacta. Ruby's requireno está confundido por la presencia o ausencia de la .rbextensión. Probado en MRI 1.8.7-p374, 2.1.5 y 2.2.0 probado. Esta leyenda urbana proviene de Rails, donde la carga automática "inteligente" exhibió el comportamiento que describe en versiones anteriores (y aún puede exhibirlo).
sheldonh

345

Si es un directorio relativo al archivo que requiere (por ejemplo, desea cargar todos los archivos en el directorio lib):

Dir[File.dirname(__FILE__) + '/lib/*.rb'].each {|file| require file }

Editar: según los comentarios a continuación, una versión actualizada:

Dir[File.join(__dir__, 'lib', '*.rb')].each { |file| require file }

14
También puede agregar todos los directorios secundarios como esteDir[File.dirname(__FILE__) + '/support/**/*.rb'].each {|file| require file }
jspooner

6262
Probablemente sea más seguro usar File.join en lugar de hacer suposiciones sobre barras diagonales / hacia atrás:Dir[File.join(File.dirname(__FILE__), 'lib', '*.rb')].each {|file| require file }
Chris

66
También hay require_relative
maasha

30
Si está usando> = ruby ​​2.0, puede usarlo en __dir__lugar de File.dirname(__FILE__).
Christian Bankester

3
@maasha ¿Cómo utiliza require_relativepara requerir todos los archivos en un directorio?
David Moles

101

Prueba la gema require_all:

  1. http://github.com/jarmo/require_all
  2. https://rubygems.org/gems/require_all

Te permite simplemente:

require_all 'path/to/directory'

Necesitaba incluir todos mis modelos de ActiveRecord, la gema require_all descubrió todas las dependencias y las requirió perfectamente. ¡Gracias!
panupan

2
@panupan Solo tenga en cuenta que require_allla resolución de dependencia cíclica funciona alrededor de un problema en su código fuente: tiene archivos fuente Ruby que no requieren sus dependencias. Esto cierra la puerta a la carga del bisturí, comprometiéndote a cargar todo o nada. Eso no es un problema en las bibliotecas pequeñas, pero es una decisión que debe tomar conscientemente.
sheldonh

No tiene sentido hinchar su aplicación con gemas que simplemente puede reemplazar con una línea de código. Esto aumenta el tiempo de carga de su aplicación e induce más errores a largo plazo.
Pere Joan Martorell

52
Dir[File.dirname(__FILE__) + '/../lib/*.rb'].each do |file| 
  require File.basename(file, File.extname(file))
end

Si no elimina la extensión, puede terminar requiriendo el mismo archivo dos veces (ruby no se dará cuenta de que "foo" y "foo.rb" son el mismo archivo). Requerir el mismo archivo dos veces puede generar advertencias falsas (por ejemplo, "advertencia: constante inicializada").


11
¿Es este realmente el caso? La documentación dice: una característica no se cargará si su nombre ya aparece en $ ". El nombre del archivo se convierte en una ruta absoluta, por lo que" requiere 'a'; require './a' "no cargará a.rb dos veces. ruby-doc.org/core/classes/Kernel.html#M001418
Derek

13
Mi prueba muestra lo mismo que Derek dijo: require "foo.rb"; require "foo";se cargará foo.rbsolo una vez.
Rene Saarsoo

@ PeteHodgson- ¿Puedes respaldar esto?
Yarin

44
No. Ruby's requireno está confundido por la presencia o ausencia de la .rbextensión. Probado en MRI 1.8.7-p374, 2.1.5 y 2.2.0. Esta leyenda urbana proviene de Rails, donde la carga automática "inteligente" exhibió el comportamiento descrito en versiones anteriores (y aún puede exhibirlo).
sheldonh

45
Dir.glob(File.join('path', '**', '*.rb'), &method(:require))

o, alternativamente, si desea abarcar los archivos para cargar en carpetas específicas:

Dir.glob(File.join('path', '{folder1,folder2}', '**', '*.rb'), &method(:require))

explicación:

Dir.glob toma un bloque como argumento.

method (: require) devolverá el método require.

& method (: require) convertirá el método en un bloque.


2
Este es un código hermoso. Me encanta cómo no hay bloques visibles.
Nate Symer

1
Dir.glob( File.join( File.dirname(__FILE__), '{lib,addons}', 'subfolder', '**', '*.rb' ), &method(:require) )elimina la dependencia de la plataforma (como '/' o '\'). Funciona bien. Gracias.
Ivan Black

30

La mejor manera es agregar el directorio a la ruta de carga y luego requireel nombre base de cada archivo. Esto se debe a que desea evitar accidentalmente requerir el mismo archivo dos veces, a menudo no el comportamiento previsto. Si un archivo se cargará o no depende de si requireha visto la ruta que se le ha pasado anteriormente. Por ejemplo, esta simple sesión irb muestra que puede requerir y cargar por error el mismo archivo dos veces.

$ irb
irb(main):001:0> require 'test'
=> true
irb(main):002:0> require './test'
=> true
irb(main):003:0> require './test.rb'
=> false
irb(main):004:0> require 'test'
=> false

Tenga en cuenta que las dos primeras líneas vuelven, lo que truesignifica que el mismo archivo se cargó las dos veces. Cuando se utilizan rutas, incluso si las rutas apuntan a la misma ubicación, requireno sabe que el archivo ya era necesario.

Aquí, en cambio, agregamos un directorio a la ruta de carga y luego requerimos el nombre base de cada archivo * .rb dentro.

dir = "/path/to/directory"
$LOAD_PATH.unshift(dir)
Dir[File.join(dir, "*.rb")].each {|file| require File.basename(file) }

Si no le importa que se requiera el archivo más de una vez, o si su intención es solo cargar el contenido del archivo, quizás loaddebería usarse en lugar de hacerlo require. Use carga en este caso, porque expresa mejor lo que está tratando de lograr. Por ejemplo:

Dir["/path/to/directory/*.rb"].each {|file| load file }

14

En lugar de concatenar rutas como en algunas respuestas, uso File.expand_path:

Dir[File.expand_path('importers/*.rb', File.dirname(__FILE__))].each do |file|
  require file
end

Actualizar:

En lugar de usar File.dirname, podría hacer lo siguiente:

Dir[File.expand_path('../importers/*.rb', __FILE__)].each do |file|
  require file
end

Donde ..elimina el nombre de archivo de __FILE__.


Este parece ser definitivamente el camino a seguir, y la respuesta más actualizada, después de intentar todo lo demás, +1 paraFile.expand_path
SuckerForMayhem

Definitivamente prefiero esta respuesta a la aceptada. Varias Rails.root.joinrespuestas también funcionan si estás en rieles.
nzifnab

14
Dir[File.join(__dir__, "/app/**/*.rb")].each do |file|
  require file
end

Esto funcionará de forma recursiva en su máquina local y en un control remoto (como Heroku) que no utiliza rutas relativas.


8

En Rails, puedes hacer:

Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }

Actualización: corregido con la sugerencia de @Jiggneshh Gohel para eliminar las barras.


Como Rails.rootes una Pathnameinstancia, puede hacer esto en cualquier entorno de Ruby, no solo en Rails (NB Rails.root.join('lib/ext/*.rb')lee un poco mejor)
DMKE

Gracias por la recomendación; Edité para incluir tu comentario.
Dan Kohn

El uso de una barra diagonal (/) para subdirectorios en Rails.root, por ejemplo Rails.root.join('/lib'), no genera la ruta correcta. Encontré que este funcionaba correctamente:Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }
Jignesh Gohel

@Jiggneshh Gohel Eliminé las barras como usted sugirió, gracias.
Dan Kohn el

3

Llegué unos años tarde a la fiesta, pero me gusta esta solución de una línea que solía tener rieles para incluir todo en aplicaciones / trabajadores / preocupaciones:

Dir[ Rails.root.join *%w(app workers concerns *) ].each{ |f| require f }


-2

¿Y qué hay de require_relative *Dir['relative path']:?


1
Requerir que el pariente no tome varios archivos: ruby-doc.org/core-2.1.2/Kernel.html#method-i-require_relative
fabriciofreitag

OK, pero en mi ejemplo no lo es. El '*' cambia la aridad a 1. Funciona como llamada múltiple a require_relative.
Aleksander

1
El '*' cambia arity a 1 - ¿Qué quieres decir con eso? require_relative *Dir['*.rb']trabajo, si solo hay un script ruby. Pero si se encuentran varias secuencias de comandos de rubí, se obtienerequire_relative': wrong number of arguments (4 for 1) (ArgumentError)
Knut
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.