Qual é a diferença entre require_relative e require no Ruby?

302

Qual é a diferença entre require_relativee requireno Ruby?

agentbanks217
fonte
9
Antes 1.9.2 não havia necessidade de require_relative, porque diretório atual do roteiro estava em $:. Veja stackoverflow.com/questions/2900370
Nakilon
1
require_relative requer um arquivo apontado especificamente para o arquivo que o chama. exigir requer um arquivo incluído no $ LOAD_PATH.
Donato
artigo útil sobre as diferenças => medium.com/@ellishim/...
Ahmed Hamdy

Respostas:

298

Basta olhar para os documentos :

require_relativecomplementa o método interno require, permitindo carregar um arquivo relativo ao arquivo que contém a require_relativeinstrução

Por exemplo, se você tiver classes de teste de unidade no diretório "test" e dados para elas no diretório "test / data" de teste, poderá usar uma linha como esta em um caso de teste:

require_relative "data/customer_data_1"
miku
fonte
28
Existe uma diferença entre require './file.rb'e require_relative 'file.rb'?
Ciro Santilli # 25/14
69
@CiroSantilli Yes. require_relativepermite "carregar um arquivo que seja relativo ao arquivo que contém a require_relativeinstrução ". Com require, ./indica um caminho que é relativo ao seu diretório de trabalho atual.
Ajedi32
17
Eu acho que é mais importante notar que require strsempre procurará nos diretórios em $ LOAD_PATH. Você deve usar require_relativequando o arquivo que você precisa carregar existir em algum lugar relativo ao arquivo que solicita o carregamento. Reserve requirepara dependências "externas".
Rthbound
97

require_relative é um subconjunto conveniente de require

require_relative('path')

é igual a:

require(File.expand_path('path', File.dirname(__FILE__)))

se __FILE__for definido ou suscitar o LoadErrorcontrário.

Isso implica que:

  • require_relative 'a'e require_relative './a'exigir em relação ao arquivo atual ( __FILE__).

    É isso que você deseja usar ao solicitar dentro da sua biblioteca, pois não deseja que o resultado dependa do diretório atual do chamador.

  • eval('require_relative("a.rb")')aumenta LoadErrorporque __FILE__não está definido por dentro eval.

    É por isso que você não pode usar require_relativenos testes do RSpec, que são evaleditados.

As seguintes operações são possíveis apenas com require:

  • require './a.rb'requer em relação ao diretório atual

  • require 'a.rb'usa o caminho de pesquisa ( $LOAD_PATH) para exigir. Ele não encontra arquivos relativos ao diretório ou caminho atual.

    Isso não é possível require_relativeporque os documentos dizem que a pesquisa de caminho ocorre apenas quando "o nome do arquivo não é resolvido para um caminho absoluto" (ou seja, começa com /ou ./ou ../), o que é sempre o caso File.expand_path.

A operação a seguir é possível com os dois, mas você deseja usá- requirelo, pois é mais curto e mais eficiente:

  • require '/a.rb'e require_relative '/a.rb'ambos exigem o caminho absoluto.

Lendo a fonte

Quando os documentos não estiverem claros, recomendo que você dê uma olhada nas fontes (alterne a fonte nos documentos). Em alguns casos, ajuda a entender o que está acontecendo.

exigir:

VALUE rb_f_require(VALUE obj, VALUE fname) {
  return rb_require_safe(fname, rb_safe_level());
}

require_relative:

VALUE rb_f_require_relative(VALUE obj, VALUE fname) {
    VALUE base = rb_current_realfilepath();
    if (NIL_P(base)) {
        rb_loaderror("cannot infer basepath");
    }
    base = rb_file_dirname(base);
    return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
}

Isso nos permite concluir que

require_relative('path')

é o mesmo que:

require(File.expand_path('path', File.dirname(__FILE__)))

Porque:

rb_file_absolute_path   =~ File.expand_path
rb_file_dirname1        =~ File.dirname
rb_current_realfilepath =~ __FILE__
Ciro Santilli adicionou uma nova foto
fonte
74

Da API Ruby :

require_relative complementa o método incorporado requer, permitindo que você carregue um arquivo que seja relativo ao arquivo que contém a instrução require_relative.

Ao usar o exigir para carregar um arquivo, você geralmente acessa a funcionalidade que foi instalada e tornada acessível adequadamente em seu sistema. require não oferece uma boa solução para carregar arquivos dentro do código do projeto. Isso pode ser útil durante uma fase de desenvolvimento, para acessar dados de teste ou mesmo para acessar arquivos "bloqueados" dentro de um projeto, não destinados a uso externo.

Por exemplo, se você tiver classes de teste de unidade no diretório "test" e dados para elas no diretório "test / data" de teste, poderá usar uma linha como esta em um caso de teste:

require_relative "data/customer_data_1" 

Como nem "teste" nem "teste / dados" provavelmente estão no caminho da biblioteca do Ruby (e por boas razões), um requisito normal não os encontrará. require_relative é uma boa solução para esse problema em particular.

Você pode incluir ou omitir a extensão (.rb ou .so) do arquivo que está sendo carregado.

O caminho deve responder a to_str.

Você pode encontrar a documentação em http://extensions.rubyforge.org/rdoc/classes/Kernel.html

svilenv
fonte
50

Resumo

Use requirepara gemas instaladas

Use require_relativepara arquivos locais

requireusa o seu $LOAD_PATHpara encontrar os arquivos.
require_relativeusa o local atual do arquivo usando a instrução


exigir

Exigir depende de você ter instalado (por exemplo gem install [package]) um pacote em algum lugar do seu sistema para essa funcionalidade.

Ao usar, requirevocê pode usar o ./formato " " para um arquivo no diretório atual, por exemplo, require "./my_file"mas isso não é uma prática comum ou recomendada, e você deve usá-lo require_relative.

require_relative

Isso significa simplesmente incluir o arquivo 'relativo ao local do arquivo com a instrução require_relative'. Eu geralmente recomendo que os arquivos devem estar "dentro" da árvore de diretórios atual em oposição ao "up", por exemplo, não fazer uso

require_relative '../../../filename'

(até três níveis de diretório) no sistema de arquivos, porque isso tende a criar dependências desnecessárias e quebradiças. No entanto, em alguns casos, se você já está "dentro" de uma árvore de diretórios, "para cima e para baixo" pode ser necessário outro ramo da árvore de diretórios. Mais simplesmente, talvez, não use require_relative para arquivos fora deste repositório (supondo que você esteja usando o git, que é amplamente um padrão de fato neste momento, no final de 2018).

Observe que require_relativeusa o diretório atual do arquivo com a instrução require_relative (portanto, não necessariamente o diretório atual do qual você está usando o comando). Isso mantém o require_relativecaminho "estável", pois sempre é relativo ao arquivo que o exige da mesma maneira.

Michael Durrant
fonte
27

As respostas principais estão corretas, mas profundamente técnicas. Para quem é mais novo no Ruby:

  • require_relative provavelmente será usado para trazer o código de outro arquivo que você escreveu.

por exemplo, e se você tiver dados ~/my-project/data.rbe quiser incluí-los ~/my-project/solution.rb? em solution.rbvocê adicionariarequire_relative 'data' .

é importante observar que esses arquivos não precisam estar no mesmo diretório. require_relative '../../folder1/folder2/data'também é válido.

  • require provavelmente será usado para trazer código de uma biblioteca que outra pessoa escreveu.

por exemplo, e se você quiser usar uma das funções auxiliares fornecidas na active_supportbiblioteca? você precisará instalar a gema com gem install activesupporte depois no arquivo require 'active_support'.

require 'active_support/all'
"FooBar".underscore

Disse diferentemente--

  • require_relative requer um arquivo especificamente apontado para o arquivo que o chama.

  • requirerequer um arquivo incluído no arquivo $LOAD_PATH.

gavião-da-noite
fonte
3
Como posso votar nesta resposta e levá-la ao topo, para que todos os visitantes desta página de perguntas obtenham uma resposta clara e compreensível imediatamente, sem quebrar o cérebro?
TiredOfProgramming
16

Acabei de ver que o código do RSpec tem algum comentário sobre require_relativeser O (1) constante e requireser O (N) linear. Então, provavelmente, a diferença é que require_relativeé a preferida require.

mech
fonte
1
Interessante. Cheguei aqui procurando informações sobre uma comparação de velocidade. Meu pensamento era que require_relativeera mais rápido, porque o carregador não precisa percorrer o caminho de carregamento em busca do arquivo. Essencialmente, require_relativefornece um link direto.
Clint Pachl
Discussão inicial sobre a velocidade relativa à exigência e o log de alterações do RSpec .
Clint Pachl
1

Quero acrescentar que, ao usar o Windows, você pode usar require './1.rb'se o script é executado local ou a partir de uma unidade de rede mapeada, mas quando executado a partir de um \\servername\sharename\foldercaminho UNC, é necessário usarrequire_relative './1.rb' .

Não me misturo na discussão que usar por outras razões.

Peter
fonte
Eu queria saber como você carrega o require_relativearquivo. Você poderia, por favor, ter uma idéia neste stackoverflow.com/questions/43487784/…
Emjey 19/17