Qual é a melhor prática se eu quiser require
um arquivo relativo no Ruby e trabalhar com o 1.8.xe> = 1.9.2?
Vejo algumas opções:
- basta fazer
$LOAD_PATH << '.'
e esquecer tudo - Faz
$LOAD_PATH << File.dirname(__FILE__)
require './path/to/file'
- verifique se
RUBY_VERSION
<1.9.2 e definarequire_relative
comorequire
, use emrequire_relative
qualquer lugar onde for necessário posteriormente - verifique se
require_relative
já existe, se existir, tente continuar como no caso anterior - use construções estranhas como - infelizmente elas não parecem funcionar completamente no Ruby 1.9, porque, por exemplo:
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>'
- Construção ainda mais estranha: parece funcionar, mas é estranha e não é muito bonita.
require File.join(File.expand_path(File.dirname(__FILE__)), 'path/to/file')
- Use a gem de backports - é meio pesada, requer infraestrutura de rubygems e inclui várias outras soluções alternativas, enquanto eu só quero
require
trabalhar com arquivos relativos.
Há uma pergunta intimamente relacionada no StackOverflow que fornece mais alguns exemplos, mas não fornece uma resposta clara - o que é uma prática recomendada.
Existe alguma solução universal decente e aceita por todos para fazer meu aplicativo rodar em Ruby <1.9.2 e> = 1.9.2?
ATUALIZAR
Esclarecimento: não quero apenas respostas como "você pode fazer X" - na verdade, eu já mencionei a maioria das opções em questão. Quero justificativa , ou seja, por que é uma prática recomendada, quais são seus prós e contras e por que deve ser escolhida entre as outras.
require
erequire_relative
?a.rb
e desejava fazer o interpretador ler e analisar o conteúdo do arquivob.rb
no diretório atual (geralmente o mesmo diretório que o anteriora.rb
), basta escreverrequire 'b'
e seria bom, pois o caminho de pesquisa padrão incluía o diretório atual. No Ruby 1.9 mais moderno, você terá que escreverrequire_relative 'b'
neste caso, poisrequire 'b'
somente pesquisaria nos caminhos padrão da biblioteca. É isso que interrompe a compatibilidade com versões anteriores e posteriores de scripts mais simples que não serão instalados corretamente (por exemplo, eles próprios instalam scripts).backports
apenas pararequire_relative
, veja a minha resposta ...Respostas:
Uma solução alternativa para isso foi adicionada à gema 'aws', então pensei em compartilhar, porque foi inspirada neste post.
https://github.com/appoxy/aws/blob/master/lib/awsbase/require_relative.rb
Isso permite que você use o
require_relative
Ruby 1.9.2 no Ruby 1.8 e 1.9.1.fonte
require_relative
função está incluída em um projeto de extensão para as bibliotecas principais do Ruby, encontradas aqui: rubyforge.org/projects/extensions Você deve poder instalá-lasgem install extensions
. Então no seu código adicione a seguinte linha antes darequire_relative
: require 'extensões / all' (proveniente de post de Aurril aqui )Antes de pular para a versão 1.9.2, usei o seguinte para requerimentos relativos:
É um pouco estranho a primeira vez que você o vê, porque parece que há um '..' extra no início. O motivo é que
expand_path
irá expandir um caminho relativo ao segundo argumento, e o segundo argumento será interpretado como se fosse um diretório.__FILE__
obviamente não é um diretório, mas isso não importa, jáexpand_path
que não se importa se os arquivos existem ou não, apenas aplicarão algumas regras para expandir coisas como..
,.
e~
. Se você conseguir superar o "waitaminute" inicial, não há um extra..
lá? Eu acho que a linha acima funciona muito bem.Supondo que
__FILE__
seja/absolute/path/to/file.rb
, o que acontece é queexpand_path
construirá a sequência/absolute/path/to/file.rb/../relative/path
e aplicará uma regra que diz que..
deve remover o componente do caminho antes (file.rb
neste caso), retornando/absolute/path/to/relative/path
.Essa é a melhor prática? Depende do que você quer dizer com isso, mas parece que está em toda a base de código do Rails, então eu diria que é pelo menos um idioma bastante comum.
fonte
A picareta tem um trecho para isso para 1,8. Aqui está:
Basicamente, apenas usa o que Theo respondeu, mas você ainda pode usá-lo
require_relative
.fonte
$RUBY_VERSION
ou verificando serequire_relative
existe diretamente?require_relative
está definido.Não é um bom hábito de segurança: por que você deve expor todo o diretório?
Isso não funciona se RUBY_VERSION <1.9.2
Você já respondeu por que essas não são as melhores opções.
Isso pode funcionar, mas há uma maneira mais rápida e segura: lidar com a exceção LoadError:
fonte
Sou fã do uso da gema rbx-require-related ( fonte ). Foi originalmente escrito para Rubinius, mas também suporta MRI 1.8.7 e não faz nada no 1.9.2. Exigir uma gema é simples, e não preciso adicionar trechos de código ao meu projeto.
Adicione-o ao seu Gemfile:
Então
require 'require_relative'
antes de vocêrequire_relative
.Por exemplo, um dos meus arquivos de teste fica assim:
Essa é a solução mais limpa de qualquer uma dessas IMO, e a gema não é tão pesada quanto os backports.
fonte
A
backports
gema agora permite o carregamento individual de backports.Você poderia então simplesmente:
Isso
require
não afetará as versões mais recentes, nem atualizará outros métodos internos.fonte
Outra opção é informar ao intérprete quais caminhos procurar
fonte
Um problema que eu não vi apontado nas soluções baseadas em __FILE__ é que elas quebram com relação aos links simbólicos. Por exemplo, diga que tenho:
O script principal, o ponto de entrada, o aplicativo é foo.rb. Este arquivo está vinculado a ~ / Scripts / foo, que está no meu $ PATH. Esta declaração de exigência é interrompida quando executo 'foo':
Como __FILE__ é ~ / Scripts / foo, a instrução require acima procura por ~ / Scripts / foo / lib / someinclude.rb que obviamente não existe. A solução é simples. Se __FILE__ for um link simbólico, ele precisará ser desreferenciado. Nome do caminho # realpath nos ajudará com esta situação:
fonte
Se você estivesse construindo uma gema, não gostaria de poluir o caminho de carregamento.
Porém, no caso de um aplicativo independente, é muito conveniente adicionar o diretório atual ao caminho de carregamento, como nos dois primeiros exemplos.
Meu voto vai para a primeira opção na lista.
Gostaria muito de ver uma sólida literatura sobre boas práticas em Ruby.
fonte
Eu definiria o meu próprio
relative_require
se ele não existir (ou seja, sob 1,8) e depois usaria a mesma sintaxe em todos os lugares.fonte
Ruby on Rails:
fonte