Qual é a maneira preferida de recarregar funções definidas em um arquivo Clojure sem ter que reiniciar o REPL. Agora, para usar o arquivo atualizado, tenho que:
- editar
src/foo/bar.clj
- feche o REPL
- abra o REPL
(load-file "src/foo/bar.clj")
(use 'foo.bar)
Além disso, (use 'foo.bar :reload-all)
não resulta no efeito requerido, que é avaliar os corpos modificados das funções e retornar novos valores, em vez de se comportar como a fonte não mudou.
Documentação:
clojure
reload
read-eval-print-loop
leiningen
pkaleta
fonte
fonte
(use 'foo.bar :reload-all)
sempre funcionou bem para mim. Além disso,(load-file)
nunca deve ser necessário se você tiver o caminho de classe configurado corretamente. Qual é o "efeito necessário" que você não está obtendo?bar.clj
detalhando o "efeito necessário".(defn f [] 1)
e alterasse sua definição para(defn f [] 2)
, parecia-me que, depois de emitir(use 'foo.bar :reload-all)
e chamar af
função, ela retornaria 2, não 1. Infelizmente, não funciona dessa maneira para mim e para todos os envolvidos. Quando mudo o corpo da função, tenho que reiniciar o REPL.:reload
ou:reload-all
ambos devem funcionar.Respostas:
Ou
(use 'your.namespace :reload)
fonte
:reload-all
também deve funcionar. O OP diz especificamente que não, mas acho que havia algo mais errado no ambiente de desenvolvimento do OP, porque, para um único arquivo, os dois (:reload
e:reload-all
) deveriam ter o mesmo efeito. Aqui está o comando completo para:reload-all
:(use 'your.namespace :reload-all)
Isso recarrega todas as dependências também.Há também uma alternativa, como usar tools.namespace , é bastante eficiente:
fonte
(refresh)
parece também fazer com que o REPL esqueça que você solicitouclojure.tools.namespace.repl
. As chamadas subsequentes para(refresh)
fornecerão uma RuntimeException, "Não é possível resolver o símbolo: atualização neste contexto". Provavelmente, a melhor coisa a fazer é(require 'your.namespace :reload-all)
, ou, se você sabe que deseja atualizar muito o seu REPL para um determinado projeto, faça um:dev
perfil e adicione[clojure.tools.namespace.repl :refer (refresh refresh-all)]
-odev/user.clj
.Recarregar o código Clojure usando
(require … :reload)
e:reload-all
é muito problemático :A biblioteca clojure.tools.namespace melhora significativamente a situação. Ele fornece uma função de atualização fácil que faz o recarregamento inteligente com base em um gráfico de dependência dos namespaces.
Infelizmente, recarregar uma segunda vez falhará se o espaço de nomes no qual você referenciou a
refresh
função foi alterado. Isso ocorre porque o tools.namespace destrói a versão atual do namespace antes de carregar o novo código.Você pode usar o nome completo do var como solução alternativa para esse problema, mas pessoalmente prefiro não precisar digitar isso a cada atualização. Outro problema com o exposto acima é que, após recarregar o namespace principal, as funções auxiliares do REPL padrão (como
doc
esource
) não são mais referenciadas lá.Para resolver esses problemas, prefiro criar um arquivo de origem real para o espaço de nome do usuário, para que ele possa ser recarregado com segurança. Coloquei o arquivo de origem,
~/.lein/src/user.clj
mas você pode colocá-lo em qualquer lugar. O arquivo deve exigir a função de atualização na declaração ns superior como esta:Você pode configurar um perfil de usuário leiningen
~/.lein/profiles.clj
para que o local em que você colocou o arquivo seja adicionado ao caminho da classe. O perfil deve ser algo como isto:Observe que eu defino o espaço para nome do usuário como ponto de entrada ao iniciar o REPL. Isso garante que as funções auxiliares do REPL sejam referenciadas no espaço para nome do usuário em vez do espaço para nome principal do seu aplicativo. Dessa forma, eles não se perderão, a menos que você altere o arquivo de origem que acabamos de criar.
Espero que isto ajude!
fonte
:source-paths
eu recebo#<FileNotFoundException java.io.FileNotFoundException: Could not locate user__init.class or user.clj on classpath: >
, enquanto:resource-paths
tudo está bem.:resource-paths
, eu estou no meu espaço para nome de usuário dentro de repl.reload
problema. Depois, tudo o que pensei que estava funcionando não estava mais. Talvez alguém deva resolver esta situação?A melhor resposta é:
Isso não apenas recarregará seu espaço de nomes especificado, mas também todos os espaços de nomes de dependência.
Documentação:
exigir
fonte
lein repl
Coljure 1.7.0 e o nREPL 0.3.5. Se você é novo no clojure: O espaço para nome ('my.namespace
) é definido com(ns ...)
emsrc/
.../core.clj
, por exemplo.proj.stuff.core
reflete a estrutura do arquivo no discosrc/proj/stuff/core.clj
, o REPL pode localizar o arquivo correto e você não precisaload-file
.Um forro baseado na resposta do papachan:
fonte
Eu uso isso no Lighttable (e no impressionante instarepl), mas deve ser usado em outras ferramentas de desenvolvimento. Eu estava tendo o mesmo problema com definições antigas de funções e métodos múltiplos, depois de recarregadas, agora durante o desenvolvimento, em vez de declarar namespaces com:
Declaro meus namespaces assim:
Muito feio, mas sempre que reavaliamos todo o espaço para nome (Cmd-Shift-Enter no Lighttable para obter os novos resultados instarepl de cada expressão), ele afasta todas as definições antigas e cria um ambiente limpo. Fui enganado todos os dias por definições antigas antes de começar a fazer isso e isso salvou minha sanidade. :)
fonte
Tente carregar o arquivo novamente?
Se você estiver usando um IDE, geralmente há um atalho de teclado para enviar um bloco de código ao REPL, redefinindo efetivamente as funções associadas.
fonte
Assim que
(use 'foo.bar)
funciona para você, significa que você tem foo / bar.clj ou foo / bar_init.class no seu CLASSPATH. A barra_init.class seria uma versão compilada pela AOT do bar.clj. Se o fizer(use 'foo.bar)
, não sei exatamente se Clojure prefere a classe ao invés de clj ou o contrário. Se preferir arquivos de classe e você tiver os dois, fica claro que editar o arquivo clj e recarregar o espaço para nome não tem efeito.BTW: Você não precisa
load-file
antes douse
se o seu CLASSPATH estiver definido corretamente.BTW2: Se você precisar usá-lo
load-file
por algum motivo, poderá fazê-lo novamente se tiver editado o arquivo.fonte