REPL에서 clojure 파일을 다시로드하는 방법


170

REPL을 다시 시작하지 않고 Clojure 파일에 정의 된 기능을 다시로드하는 기본 방법은 무엇입니까? 지금 업데이트 된 파일을 사용하려면 다음을 수행해야합니다.

  • 편집하다 src/foo/bar.clj
  • REPL을 닫으십시오
  • REPL을여십시오
  • (load-file "src/foo/bar.clj")
  • (use 'foo.bar)

또한 (use 'foo.bar :reload-all)소스가 전혀 변경되지 않은 것처럼 동작하는 대신 수정 된 함수 본문을 평가하고 새 값을 반환하는 필수 효과가 없습니다.

선적 서류 비치:


20
(use 'foo.bar :reload-all)항상 나를 위해 잘 작동했습니다. 또한 (load-file)클래스 경로를 올바르게 설정 한 경우 필요하지 않아야합니다. 얻지 못한 "필수 효과"는 무엇입니까?
Dave Ray

예, "필수 효과"는 무엇입니까? bar.clj"필요한 효과"에 대한 샘플을 게시하십시오 .
Sridhar Ratnakumar

1
필요한 효과로 함수가 (defn f [] 1)있고 정의를으로 변경 하면 함수를 (defn f [] 2)발행 (use 'foo.bar :reload-all)하고 호출 한 후 1이 f아닌 2를 반환해야한다고 생각했습니다. 기능 본문을 변경할 때 REPL을 다시 시작해야합니다.
pkaleta

설정에 다른 문제가 :reload있거나 :reload-all둘 다 작동해야합니다.
Jason

답변:


196

또는 (use 'your.namespace :reload)


3
:reload-all작동해야합니다. OP는 구체적으로 그렇지 않다고 말하지만 OP의 개발 환경에는 다른 파일이 있다고 생각합니다. 단일 파일의 경우 두 ( :reload:reload-all)가 동일한 효과를 가져야하기 때문입니다. 여기에 대한 전체 명령이 있습니다 :reload-all: (use 'your.namespace :reload-all) 이것은 모든 종속성을 다시로드합니다.
Jason

77

tools.namespace를 사용하는 것과 같은 대안도 있지만 매우 효율적입니다.

user=> (use '[clojure.tools.namespace.repl :only (refresh)])

user=> (refresh)

:reloading (namespace.app)

:ok

3
이 답변이 더 적절하다
Bahadir Cambel

12
주의 사항 : 달리는 (refresh)것은 REPL이 당신이 필요하다는 것을 잊게하는 것처럼 보입니다 clojure.tools.namespace.repl. 이후에 호출 (refresh)하면 RuntimeException, "심볼을 확인할 수 없습니다 :이 컨텍스트에서 새로 고침"이 발생합니다. 아마도 가장 좋은 방법은 (require 'your.namespace :reload-all), 또는 주어진 프로젝트에 대해 REPL을 많이 새로 고치려 는 경우 :dev프로파일을 만들고에 추가 [clojure.tools.namespace.repl :refer (refresh refresh-all)]하는 것dev/user.clj 입니다.
Dave Yarwood

1
tools.namespace의 저자가 Clojure 워크 플로우에 대한 블로그 포스트 : thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded
David Tonhofer

61

사용 Clojure의 코드를 다시로드 (require … :reload)하고 :reload-all있습니다 매우 문제 :

  • 서로 의존하는 두 개의 네임 스페이스를 수정하는 경우 컴파일 오류가 발생하지 않도록 올바른 순서로 다시로드해야합니다.

  • 소스 파일에서 정의를 제거한 후 다시로드하면 해당 정의를 여전히 메모리에서 사용할 수 있습니다. 다른 코드가 해당 정의에 의존하는 경우 코드는 계속 작동하지만 다음에 JVM을 다시 시작할 때 중단됩니다.

  • 다시로드 된 네임 스페이스에가 포함되어 있으면 defmulti관련된 모든 defmethod표현식 도 다시로드해야합니다 .

  • 다시로드 된 네임 스페이스에가 포함 된 경우 defprotocol해당 프로토콜을 구현하는 모든 레코드 또는 유형을 다시로드하고 해당 레코드 / 유형의 기존 인스턴스를 새 인스턴스로 바꿔야합니다.

  • 다시로드 된 네임 스페이스에 매크로가 포함 된 경우 해당 매크로를 사용하는 네임 스페이스도 다시로드해야합니다.

  • 실행중인 프로그램에 다시로드 된 네임 스페이스의 값을 닫는 함수가 포함 된 경우 해당 닫은 값은 업데이트되지 않습니다. 이것은 "핸들러 스택"을 함수 구성으로 구성하는 웹 애플리케이션에서 일반적입니다.

clojure.tools.namespace 라이브러리는 상황을 크게 개선합니다. 네임 스페이스의 종속성 그래프를 기반으로 스마트 다시로드를 수행하는 간편한 새로 고침 기능을 제공합니다.

myapp.web=> (require '[clojure.tools.namespace.repl :refer [refresh]])
nil
myapp.web=> (refresh)
:reloading (myapp.web)
:ok

불행하게도 refresh함수 를 참조한 네임 스페이스가 변경된 경우 두 번째로 다시로드하지 못할 수 있습니다. 이는 tools.namespace가 새 코드를로드하기 전에 현재 버전의 네임 스페이스를 삭제하기 때문입니다.

myapp.web=> (refresh)

CompilerException java.lang.RuntimeException: Unable to resolve symbol: refresh in this context, compiling:(/private/var/folders/ks/d6qbfg2s6l1bcg6ws_6bq4600000gn/T/form-init819543191440017519.clj:1:1)

이 문제에 대한 해결 방법으로 정규화 된 var 이름을 사용할 수 있지만 개인적으로 각 새로 고칠 때마다 입력하지 않아도됩니다. 위의 또 다른 문제는 (같은 주요 네임 스페이스를 표준 REPL 도우미 기능을 다시로드 후이다 docsource) 더 이상이 참조되지 않습니다.

이러한 문제를 해결하기 위해 사용자 네임 스페이스에 대한 실제 소스 파일을 작성하여 안정적으로 다시로드 할 수 있습니다. 소스 파일을 넣었 ~/.lein/src/user.clj지만 어디에나 배치 할 수 있습니다. 파일은 다음과 같이 최상위 ns 선언에 refresh 함수가 필요합니다.

(ns user
  (:require [clojure.tools.namespace.repl :refer [refresh]]))

파일을 넣은 위치가 클래스 경로에 추가되도록 leiningen 사용자 프로파일 을 설정할 수 있습니다 ~/.lein/profiles.clj. 프로필은 다음과 같아야합니다.

{:user {:dependencies [[org.clojure/tools.namespace "0.2.7"]]
        :repl-options { :init-ns user }
        :source-paths ["/Users/me/.lein/src"]}}

REPL을 시작할 때 사용자 네임 스페이스를 진입 점으로 설정했습니다. 이렇게하면 REPL 헬퍼 함수가 애플리케이션의 기본 네임 스페이스 대신 사용자 네임 스페이스에서 참조됩니다. 그렇게하면 방금 만든 소스 파일을 변경하지 않으면 손실되지 않습니다.

도움이 되었기를 바랍니다!


좋은 제안입니다. 한 가지 질문 : 왜 ": source-paths"항목이 위에 있습니까?
Alan Thompson 1

2
@DirkGeurs, :source-paths내가 얻는 #<FileNotFoundException java.io.FileNotFoundException: Could not locate user__init.class or user.clj on classpath: >동안 :resource-paths모든 것이 정상 입니다.
fl00r

1
@ fl00r 그리고 여전히 그 오류가 발생합니까? REPL을 시작하는 폴더에 유효한 project.clj가 있습니까? 문제가 해결 될 수 있습니다.
Dirk Geurs

1
예, 그것은 꽤 표준이며 모두 잘 작동합니다 :resource-paths. 내 사용자 네임 스페이스에 있습니다.
fl00r

1
reload문제로 인해 거짓말을 한 REPL과 함께 일하면서 즐거운 시간을 보냈습니다 . 그런 다음 내가 생각하는 모든 것이 더 이상 아니라는 것이 밝혀졌습니다. 누군가이 상황을 해결해야합니까?
Alper

41

가장 좋은 대답은 다음과 같습니다.

(require 'my.namespace :reload-all)

지정된 네임 스페이스를 다시로드 할뿐만 아니라 모든 종속 네임 스페이스도 다시로드합니다.

선적 서류 비치:

요구하다


2
lein replColjure 1.7.0 및 nREPL 0.3.5와 함께 작동하는 유일한 대답입니다 . 당신이 Clojure의 새로운면 : 네임 스페이스를 ( 'my.namespace)로 정의 (ns ...)에서 src/... /core.clj예를 들어.
Aaron Digulla

1
이 답변의 문제점은 원래 질문이 (로드 파일 ...)을 사용하고 있다는 것입니다. 로드 파일 다음에 네임 스페이스에 : reload-all을 어떻게 추가 할 수 있습니까?
jgomo3

와 같은 네임 스페이스 구조 proj.stuff.core는 디스크와 같은 파일 구조를 미러링하므로 src/proj/stuff/core.cljREPL은 올바른 파일을 찾을 수 있으며 필요하지 않습니다 load-file.
Alan Thompson

6

papachan의 답변을 기반으로 한 라이너 :

(clojure.tools.namespace.repl/refresh)

5

나는 이것을 Lighttable (그리고 멋진 instarepl)에서 사용하지만 다른 개발 도구에서 사용해야합니다. 나는 다시로드 한 후에 함수와 멀티 메쏘드의 오래된 정의에 대해 같은 문제를 겪고 있었으므로 개발 중에 네임 스페이스를 선언하는 대신 개발 중에 지금 :

(ns my.namespace)

다음과 같이 네임 스페이스를 선언합니다.

(clojure.core/let [s 'my.namespace]
                  (clojure.core/remove-ns s)
                  (clojure.core/in-ns s)
                  (clojure.core/require '[clojure.core])
                  (clojure.core/refer 'clojure.core))

꽤 추악하지만 전체 네임 스페이스 (Cmd-Shift-Enter를 Lighttable에서 각 표현식의 새로운 별표 결과를 얻음)를 다시 평가할 때마다 오래된 정의가 모두 사라지고 깨끗한 환경이됩니다. 나는 이것을하기 전에 오래된 정의에 의해 며칠마다 걸려 넘어졌고 그것은 내 정신을 구했습니다. :)


3

파일로드를 다시 시도 하시겠습니까?

IDE를 사용하는 경우 일반적으로 코드 블록을 REPL에 전송하는 키보드 단축키가 있으므로 관련 기능을 효과적으로 재정의 할 수 있습니다.


1

(use 'foo.bar)당신을 위해 일 하자마자 , 그것은 당신이 당신의 CLASSPATH에 foo / bar.clj 또는 foo / bar_init.class를 가지고 있다는 것을 의미합니다. bar_init.class는 AOT 컴파일 버전의 bar.clj입니다. 그렇게 (use 'foo.bar)하면 Clojure가 clj 또는 다른 방식으로 클래스를 선호하는지 확실하지 않습니다. 클래스 파일을 선호하고 두 파일이 모두있는 경우 clj 파일을 편집 한 다음 네임 스페이스를 다시로드해도 아무런 영향이 없습니다.

BTW : 당신은 할 필요가 없습니다 load-file전에 use당신의 CLASSPATH가 올바르게 설정되어있는 경우.

BTW2 : 어떤 load-file이유로 사용해야 하는 경우 파일을 편집 한 경우 다시 수행 할 수 있습니다.


14
왜 이것이 정답으로 표시되는지 잘 모르겠습니다. 질문에 명확하게 대답하지 않습니다.
AnnanFay

5
누군가이 질문에 올 때 나는이 대답을 매우 명확하게 찾지 못합니다.
ctford
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.