¿En qué se diferencia la carga de la requerida en Ruby?

Respuestas:

98

requirebusca la biblioteca en todas las rutas de búsqueda definidas y también agrega .rb o .so al nombre de archivo que ingrese. También se asegura de que una biblioteca solo se incluya una vez. Entonces, si su aplicación requiere la biblioteca A y B y la biblioteca B, la biblioteca A también se cargará una sola vez.

Con loaddebe agregar el nombre completo de la biblioteca y se carga cada vez que llama load, incluso si ya está en la memoria.

Nikolaus Gradwohl
fuente
Gracias señor, podemos decir que .rb no es obligatorio para cargar. ¿Y "require" no llama a todos los tiempos, si está en la memoria?
Arpit Vaishnav
4
requirerealiza un seguimiento de lo que ya se ha cargado a través de la matriz global $LOADED_FEATURES( $"), que loadignora.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
39

Otra diferencia entre Kernel#requirey Kernel#loades que Kernel#loadtoma un segundo argumento opcional que le permite envolver el código cargado en un módulo vacío anónimo.

Desafortunadamente, no es muy útil. Primero, es fácil que el loadcódigo ed salga del módulo, simplemente accediendo al espacio de nombres global, es decir, todavía pueden parchear algo como class ::String; def foo; end end. Y en segundo lugar, loadno devuelve el módulo en el que envuelve el código, por lo que básicamente tienes que pescarlo a ObjectSpace::each_object(Module)mano.

Jörg W Mittag
fuente
¡Es bueno saberlo! No Kernel#loadtenía idea, tenía otra discusión
Josh Bodah
Desafortunadamente, no es muy útil. Primero, es fácil que el loadcódigo ed salga del módulo, simplemente accediendo al espacio de nombres global, es decir, todavía pueden parchear algo como class ::String; def foo; end end. Y en segundo lugar, loadno devuelve el módulo en el que envuelve el código, por lo que básicamente tienes que pescarlo a ObjectSpace::each_object(Module)mano.
Jörg W Mittag
4

Estaba ejecutando una aplicación Rails y en Gemfile, tenía una gema personalizada específica que creé con la opción "require: false". Ahora, cuando cargué el servidor de rails o la consola de rails, pude requerir la gema en el inicializador y la gema se cargó. Sin embargo, cuando ejecuté una prueba de características de especificaciones con rspec y capibara, obtuve un error de carga. Y estaba completamente desconcertado por qué no se encontró la gema en $ LOAD_PATH al ejecutar una prueba.

Así que revisé todas las diferentes formas en que se cargan, requieren, los rubygems y el paquete interactúan. Y estos son un resumen de mis hallazgos que me ayudaron a descubrir la solución a mi problema particular:

carga

1) Puede pasarle una ruta absoluta a un archivo ruby ​​y ejecutará el código en ese archivo.

load('/Users/myuser/foo.rb')

2) Puede pasar una ruta relativa para cargar. Si está en el mismo directorio que el archivo, lo encontrará:

> load('./foo.rb')
foo.rb loaded!
=> true

Pero si intenta cargar un archivo desde un directorio diferente con load (), no lo encontrará con una ruta relativa basada en el directorio de trabajo actual (por ejemplo, ./):

> load('./foo.rb')
LoadError: cannot load such file -- foo.rb

3) Como se muestra arriba, load siempre devuelve verdadero (si el archivo no se pudo cargar, genera a LoadError).

4) Las variables, clases, constantes y métodos globales se importan, pero no las variables locales.

5) Llamar a load dos veces en el mismo archivo ejecutará el código en ese archivo dos veces. Si el archivo especificado define una constante, definirá esa constante dos veces, lo que produce una advertencia.

6) $ LOAD_PATH es una matriz de rutas absolutas. Si pasa load solo un nombre de archivo, recorrerá $ LOAD_PATH y buscará el archivo en cada directorio.

> $LOAD_PATH.push("/Users/myuser")
> load('foo.rb')
foo.rb loaded!
 => true

exigir

1) Llamar a require en el mismo archivo dos veces solo lo ejecutará una vez. También es lo suficientemente inteligente como para no cargar el mismo archivo dos veces si se refiere a él una vez con una ruta relativa y una vez con una ruta absoluta.

2) require devuelve verdadero si el archivo se ejecutó y falso si no lo fue.

3) require realiza un seguimiento de los archivos que ya se han cargado en la variable global $ LOADED_FEATURES.

4) No es necesario que incluya la extensión del archivo:

require 'foo'

5) require buscará foo.rb, pero también archivos de biblioteca dinámica, como foo.so, foo.o o foo.dll. Así es como puede llamar al código C desde ruby.

6) require no comprueba el directorio actual, ya que el directorio actual no está por defecto en $ LOAD_PATH.

7) require_relative toma una ruta relativa al archivo actual, no al directorio de trabajo del proceso.

Rubygems

1) Rubygems es un administrador de paquetes diseñado para administrar fácilmente la instalación de bibliotecas de Ruby llamadas gems.

2) Empaqueta su contenido como un archivo zip que contiene un montón de archivos ruby ​​y / o archivos de biblioteca dinámica que pueden ser importados por su código, junto con algunos metadatos.

3) Rubygems reemplaza el método require predeterminado con su propia versión. Esa versión revisará sus gemas instaladas además de los directorios en $ LOAD_PATH. Si Rubygems encuentra el archivo en tus gemas, agregará esa gema a tu $ LOAD_PATH.

4) El comando de instalación de gemas determina todas las dependencias de una gema y las instala. De hecho, instala todas las dependencias de una gema antes de instalar la gema en sí.

Bundler

1) Bundler le permite especificar todas las gemas que necesita su proyecto y, opcionalmente, qué versiones de esas gemas. Luego, el comando bundle instala todas esas gemas y sus dependencias.

2) Especifica qué gemas necesita en un archivo llamado Gemfile.

3) El comando bundle también instala todas las gemas enumeradas en Gemfile.lock en las versiones específicas enumeradas.

4) Poner bundle exec antes de un comando, por ejemplo, bundle exec rspec, asegura que require cargará la versión de una gema especificada en tu Gemfile.lock.

Rieles y empaquetador

1) En config / boot.rb, se ejecuta require 'bundler / setup'. Bundler se asegura de que Ruby pueda encontrar todas las gemas en Gemfile (y todas sus dependencias). require 'bundler / setup' automáticamente descubrirá tu Gemfile y hará que todas las gemas en tu Gemfile estén disponibles para Ruby (en términos técnicos, coloca las gemas “en la ruta de carga”). Puedes pensar en ello como agregar algunos poderes adicionales para requerir 'rubygems'.

ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])

2) Ahora que su código está disponible para Ruby, puede solicitar las gemas que necesita. Por ejemplo, puede requerir 'sinatra'. Si tiene muchas dependencias, es posible que desee decir "requerir todas las gemas en mi Gemfile". Para hacer esto, coloque el siguiente código inmediatamente después de require 'bundler / setup':

Bundler.require(:default)

3) De forma predeterminada, llamar a Bundler.require requerirá cada gema en su Gemfile. Si la línea en el Gemfile dice gem 'foo',: require => false entonces se asegurará de que foo esté instalado, pero no llamará a require. Tendrá que llamar a require ('foo') si desea usar la gema.

Entonces, dada esta amplitud de conocimiento, volví al problema de mi prueba y me di cuenta de que tenía que requerir explícitamente la gema en rails_helper.rb, ya que Bundler.setup la agregó a $ LOAD_PATH pero require: false impidió que Bundler.require lo requiriera explícitamente . Y luego se resolvió el problema.

Donato
fuente