2010-08-13 10 views
11

Clojure ma dużą liczbę funkcji/makr do pracy z przestrzeniami nazw i importowaniem pakietów java. Zgodnie z moim (ograniczonym) zrozumieniem, ustawienie przestrzeni nazw można uznać za stan w procesie clojure (repl).Zarządzanie obszarem nazw Clojure - czy istnieje sposób na zapisanie i przywrócenie stanu przestrzeni nazw replikacji, importu itd.?

Podczas pracy iteracyjnie w sesji REPL, szczególnie gdy pliki źródłowe są (ponownie) ładowane, mogę łatwo wpadać w zakłopotanie - często gdy popełniam błąd lub błąd składni w konfiguracji przestrzeni nazw. Innym razem chcę wypróbować refaktoryzujące przestrzenie nazw/aliasy/filtry referencyjne, ale nie mogę łatwo wyjść z istniejącego stanu przestrzeni nazw bez restartowania REPL.

Na przykład chciałbym mieć możliwość konfiguracji przestrzeni nazw punktów kontrolnych - na przykład po załadowaniu głównej części kodu do repa - a następnie wrócić do tego "czystego arkusza" po przetestowaniu biblioteki zaimportowanej w REPL tak, że mogę natychmiast przetestować plik źródłowy, który importuje przefiltrowany podzestaw metod w tej bibliotece jako część makra ns.

Czy użytkownicy mogą polecać sposoby zapisywania i przywracania konfiguracji przestrzeni nazw?

+1

To brzmi jak funkcja _save-world_, którą nosi wiele implementacji Common Lisp. – Greg

+0

To powinno być możliwe, używając (clojure.lang.Namespace/all) i .getMappings, ale nie mogę znaleźć żadnego wskazania, że ​​ktoś to zrobił. – dreish

Odpowiedz

10

Jestem pewien, że coś jest nie tak z tym , ponieważ napisałem to w odpowiedzi na to pytanie, ale widzę, że sam to wykorzystuję w moich projektach. Po prostu: zaimportuj (umieść to w swoim własnym pliku w projekcie) i używaj go swobodnie.

(ns world) 


(defn save-world 
    [] 
    (let [syms (filter identity (distinct (for [i (ns-map *ns*)] (first i))))] 
    (for [i syms] 
     (vector i 
       (ns-resolve *ns* i))))) 

(defn destroy-world-but 
    [saved] 
    (let [syms (filter identity (distinct (for [i (ns-map *ns*)] (first i))))] 
    (for [i syms] 
     (if-not (or (= (ns-resolve *ns* i) (ns-resolve *ns* saved)) 
        (= (ns-resolve *ns* i) (ns-resolve *ns* 'restore-world)) 
        (= (ns-resolve *ns* i) (ns-resolve *ns* '*ns*))) 
     (ns-unmap *ns* i))))) 

(defn restore-world 
    [saved] 
    (clojure.core/map 
    #(intern *ns* (clojure.core/first %) (clojure.core/second %)) 
    saved)) 

Pierwszy, zapisz stan swojego świata (ten, który chcesz wrócić do) tak:

(def *save* (save-world)) 

Następnie robić, co chcesz-eksperyment. Kiedy będziesz gotowy wrócić do poprzedniego stanu:

(destroy-world-but '*save*) 
(restore-world *save*) 

I powinieneś być dobry, aby iść!

(Mam nadzieję, że to działa! Pracował dla mnie - proszę dać mi znać, czy jest jakiś problem. Jestem pewien, że jest lepszy sposób, aby to zrobić, ale to działa i jest to, jak daleko mam dziś w nocy. Na pewno się zrewiduję.)

6

To nie zawsze działa. Możesz usunąć Vars z przestrzeni nazw za pomocą ns-unmap, ale inne fragmenty kodu mogą nadal zawierać odniesienia do tych definicji.

Clojure, ponieważ opiera się na JVM, nie ma pojęcia "obrazu pamięci", jak niektóre implementacje Common Lisp lub Scheme.

+0

Ostrożnie ostrzeżenie. Mógłbym mieć wiele kłopotów, gdybym na przykład próbował zapisać i przywrócić stan złożonej długiej aplikacji. Ale w przypadku prostego użycia wymaganych funkcji/aliasów podczas pojedynczej sesji repliki podejrzewam, że prawdopodobnie wykonuję coś w rodzaju tego, co Issac pokazuje poniżej. –

1

DMTCP może wykonać tę pracę w niezręczny sposób. Google w DMTCP: Distributed MultiThreaded CheckPointing. Używam go do interaktywnych programów OCaml.

Powiązane problemy