Wie unterscheidet sich die Last von der Anforderung in Ruby?

Antworten:

98

requireSucht in allen definierten Suchpfaden nach der Bibliothek und hängt auch .rb oder .so an den von Ihnen eingegebenen Dateinamen an. Außerdem wird sichergestellt, dass eine Bibliothek nur einmal enthalten ist. Wenn Ihre Anwendung also Bibliothek A und B benötigt und Bibliothek B auch Bibliothek A benötigt, wird A nur einmal geladen.

Mit loadmüssen Sie den vollständigen Namen der Bibliothek hinzufügen und sie wird bei jedem Aufruf geladen load- auch wenn sie sich bereits im Speicher befindet.

Nikolaus Gradwohl
quelle
Vielen Dank, Sir, damit wir sagen können, dass .rb beim Laden nicht erforderlich ist. Und "erfordern" ruft nicht immer auf, wenn es im Speicher ist?
Arpit Vaishnav
4
requireVerfolgt, was bereits über das globale Array $LOADED_FEATURES( $") geladen wurde , das loadignoriert wird.
Ciro Santilli 法轮功 冠状 病 六四 事件 26
39

Ein weiterer Unterschied zwischen Kernel#requireund Kernel#loadbesteht darin, dass Kernel#loadein optionales zweites Argument verwendet wird, mit dem Sie den geladenen Code in ein anonymes leeres Modul einschließen können.

Leider ist es nicht sehr nützlich. Erstens ist es für den loaded-Code einfach , aus dem Modul auszubrechen, indem er einfach auf den globalen Namespace zugreift, dh er kann immer noch so etwas wie Monkeypatch ausführen class ::String; def foo; end end. Und zweitens wird loaddas Modul, in das der Code eingeschlossen ist , nicht zurückgegeben, sodass Sie ihn grundsätzlich ObjectSpace::each_object(Module)von Hand herausfischen müssen .

Jörg W Mittag
quelle
Sehr gut zu wissen! Hatte keine Ahnung, Kernel#loadhatte ein anderes Argument
Josh Bodah
Leider ist es nicht sehr nützlich. Erstens ist es für den loaded-Code einfach , aus dem Modul auszubrechen, indem er einfach auf den globalen Namespace zugreift, dh er kann immer noch so etwas wie Monkeypatch ausführen class ::String; def foo; end end. Und zweitens wird loaddas Modul, in das der Code eingeschlossen ist , nicht zurückgegeben, sodass Sie ihn grundsätzlich ObjectSpace::each_object(Module)von Hand herausfischen müssen .
Jörg W Mittag
4

Ich habe eine Rails-Anwendung ausgeführt und in Gemfile einen bestimmten benutzerdefinierten Edelstein mit der Option "require: false" erstellt. Als ich nun den Rails-Server oder die Rails-Konsole geladen habe, konnte ich den Gem im Initialisierer anfordern und der Gem wurde geladen. Als ich jedoch einen Spezifikationstest mit rspec und capybara durchführte, wurde ein Ladefehler angezeigt. Und ich war völlig verwirrt, warum der Edelstein beim Ausführen eines Tests nicht in $ LOAD_PATH gefunden wurde.

Also habe ich all die verschiedenen Arten der Interaktion von Laden, Erfordernis, Rubygems und Bundler überprüft. Und dies ist eine Zusammenfassung meiner Ergebnisse, die mir geholfen haben, die Lösung für mein spezielles Problem zu finden:

Belastung

1) Sie können einen absoluten Pfad zu einer Ruby-Datei übergeben und der Code in dieser Datei wird ausgeführt.

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

2) Sie können einen relativen Pfad zum Laden übergeben. Wenn Sie sich im selben Verzeichnis wie die Datei befinden, wird sie gefunden:

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

Wenn Sie jedoch versuchen, eine Datei mit load () aus einem anderen Verzeichnis zu laden, wird sie nicht mit einem relativen Pfad gefunden, der auf dem aktuellen Arbeitsverzeichnis basiert (z. B. ./):

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

3) Wie oben gezeigt, gibt load immer true zurück (wenn die Datei nicht geladen werden konnte, wird a ausgelöst LoadError).

4) Globale Variablen, Klassen, Konstanten und Methoden werden importiert, jedoch keine lokalen Variablen.

5) Wenn Sie zweimal die gleiche Datei laden, wird der Code in dieser Datei zweimal ausgeführt. Wenn die angegebene Datei eine Konstante definiert, wird diese Konstante zweimal definiert, wodurch eine Warnung ausgegeben wird.

6) $ LOAD_PATH ist ein Array von absoluten Pfaden. Wenn Sie nur einen Dateinamen laden, durchläuft er $ LOAD_PATH und sucht in jedem Verzeichnis nach der Datei.

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

benötigen

1) Wenn Sie dieselbe Datei zweimal aufrufen müssen, wird sie nur einmal ausgeführt. Es ist auch klug genug, dieselbe Datei nicht zweimal zu laden, wenn Sie einmal mit einem relativen Pfad und einmal mit einem absoluten Pfad darauf verweisen.

2) Rückgabe true erforderlich, wenn die Datei ausgeführt wurde, und false, wenn dies nicht der Fall war.

3) require verfolgt, welche Dateien bereits in die globale Variable $ LOADED_FEATURES geladen wurden.

4) Sie müssen die Dateierweiterung nicht angeben:

require 'foo'

5) require sucht nach foo.rb, aber auch nach dynamischen Bibliotheksdateien wie foo.so, foo.o oder foo.dll. So können Sie C-Code von Ruby aus aufrufen.

6) require überprüft das aktuelle Verzeichnis nicht, da sich das aktuelle Verzeichnis standardmäßig nicht in $ LOAD_PATH befindet.

7) require_relative nimmt einen Pfad relativ zur aktuellen Datei, nicht zum Arbeitsverzeichnis des Prozesses.

Rubygems

1) Rubygems ist ein Paketmanager, mit dem die Installation von Ruby-Bibliotheken namens Gems einfach verwaltet werden kann.

2) Der Inhalt wird als Zip-Datei verpackt, die eine Reihe von Ruby-Dateien und / oder dynamischen Bibliotheksdateien enthält, die von Ihrem Code zusammen mit einigen Metadaten importiert werden können.

3) Rubygems ersetzt die Standardmethode require durch eine eigene Version. Diese Version durchsucht zusätzlich zu den Verzeichnissen in $ LOAD_PATH Ihre installierten Edelsteine. Wenn Rubygems die Datei in Ihren Edelsteinen findet, wird dieser Edelstein Ihrem $ LOAD_PATH hinzugefügt.

4) Der Befehl gem install ermittelt alle Abhängigkeiten eines Gems und installiert sie. Tatsächlich werden alle Abhängigkeiten eines Edelsteins installiert, bevor der Edelstein selbst installiert wird.

Bundler

1) Mit Bundler können Sie alle Edelsteine ​​angeben, die Ihr Projekt benötigt, und optional welche Versionen dieser Edelsteine. Dann installiert der Befehl bundle alle diese Edelsteine ​​und ihre Abhängigkeiten.

2) Sie geben in einer Datei namens Gemfile an, welche Edelsteine ​​Sie benötigen.

3) Der Befehl bundle installiert auch alle in Gemfile.lock aufgelisteten Edelsteine ​​in den angegebenen spezifischen Versionen.

4) Wenn Sie bundle exec vor einen Befehl stellen, z. B. bundle exec rspec, wird sichergestellt, dass require die in Ihrer Gemfile.lock angegebene Version eines Gems lädt.

Schienen und Bundler

1) In config / boot.rb muss 'bundler / setup' ausgeführt werden. Bundler stellt sicher, dass Ruby alle Edelsteine ​​in der Gemfile (und alle ihre Abhängigkeiten) finden kann. require 'bundler / setup' erkennt automatisch Ihre Gemfile und stellt Ruby alle Gems in Ihrer Gemfile zur Verfügung (technisch gesehen werden die Gems "auf den Ladepfad" gesetzt). Sie können sich das als Hinzufügen einiger zusätzlicher Kräfte vorstellen, um 'Rubygems' zu benötigen.

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

2) Nachdem Ihr Code Ruby zur Verfügung steht, können Sie die Edelsteine ​​benötigen, die Sie benötigen. Zum Beispiel können Sie "Sinatra" benötigen. Wenn Sie viele Abhängigkeiten haben, möchten Sie vielleicht sagen, dass Sie alle Edelsteine ​​in meiner Gem-Datei benötigen. Geben Sie dazu den folgenden Code ein, der unmittelbar nach "bundler / setup" erforderlich ist:

Bundler.require(:default)

3) Für den Aufruf von Bundler.require ist standardmäßig jeder Edelstein in Ihrer Gemfile erforderlich. Wenn in der Zeile in der Gem-Datei gem 'foo' steht: require => false, wird sichergestellt, dass foo installiert ist, aber nicht require aufgerufen. Sie müssen require ('foo') anrufen, wenn Sie den Edelstein verwenden möchten.

Angesichts dieser Wissensbreite kehrte ich zum Thema meines Tests zurück und stellte fest, dass ich den Edelstein in rails_helper.rb explizit benötigen musste, da Bundler.setup ihn zu $ ​​LOAD_PATH hinzufügte, aber Folgendes erforderte: false schloss Bundler.require aus, ihn explizit zu benötigen . Und dann wurde das Problem behoben.

Donato
quelle