2010-09-11 14 views
12

Mam projekt skonfigurowany z leiningen o nazwie techne. Stworzyłem moduł o nazwie scrub z typem zwanym Scrub i funkcją o nazwie foo.Jak używać typu spoza własnej przestrzeni nazw w clojure?

Techne/scrub.clj:

(ns techne.scrub) 
    (deftype Scrub [state] 
    Object 
    (toString [this] 
    (str "SCRUB: " state))) 

(defn foo 
    [item] 
    (Scrub. "foo") 
    "bar") 

Techne/scrub_test.clj:

(ns techne.scrub-test                                    
    (:use [techne.scrub] :reload-all)                                
    (:use [clojure.test]))                                   


(deftest test-foo                                     
    (is (= "bar" (foo "foo"))))                                       

(deftest test-scrub                                    
    (is (= (Scrub. :a) (Scrub. :a)))) 

Kiedy wykonać test, pojawia się błąd:

Exception in thread "main" java.lang.IllegalArgumentException: Unable to resolve classname: Scrub (scrub_test.clj:11) 
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:5376) 
    at clojure.lang.Compiler.analyze(Compiler.java:5190) 
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:5357) 

gdybym usuń test-scrub wszystko działa dobrze. Dlaczego: use techne.scrub "importuje" definicje funkcji, ale nie definicje typów? Jak odwołać się do definicji typów?

Odpowiedz

15

Ponieważ deftype generuje klasę, prawdopodobnie będziesz musiał zaimportować tę klasę Java w teście techne.scrub z (: import [techne.scrub Scrub]) w swojej definicji ns.

I rzeczywiście napisał tę samą rzecz w odniesieniu do defrecord tutaj:

Inną rzeczą, jaką można zrobić byłoby zdefiniować funkcję konstruktora w zarośla:

(defn new-scrub [state] 
    (Scrub. state)) 

, a następnie nie trzeba importować Scrub w szufladzie testowej.

+1

Zawsze używam funkcji konstruktora z tego powodu i do sprawdzania poprawności. –

+1

Tak, uznaliśmy za pomocne przedłużenie defrecordu, aby automatycznie dodawać funkcje konstruktora z walidacją pól, obsługę pprint do formularza eval-able itd. –

+4

Należy pamiętać, że ta odpowiedź poprzedza Clojure 1.4. Od wersji 1.4 konstruktor pozycyjny (-> Scrub) i map (map-> Scrub) zostanie automatycznie utworzony przez defrecord. Jest to preferowana metoda konstrukcji i wymaga tylko odesłania tych funkcji do przestrzeni nazw - nie ma potrzeby importowania klasy. –

0

Dodaję import, ale mam ten sam problem. Testuję z pakietem Expectations 2.0.9, próbując zaimportować węzeł typu deftype i interfejs INode.

W core.clj:

(ns linked-list.core) 

(definterface INode 
    (getCar []) 
    (getCdr []) 
    (setCar [x]) 
    (setCdr [x])) 

(deftype Node [^:volatile-mutable car ^:volatile-mutable cdr] 
    INode 
    (getCar[_] car) 
    (getCdr[_] cdr) 
    (setCar[_ x] (set! car x) _) 
    (setCdr[_ x] (set! cdr x) _)) 

W core_test.clj:

(ns linked-list.core-test 
    (:require [expectations :refer :all] 
      [linked-list.core :refer :all]) 
    (:import [linked-list.core INode] 
      [linked-list.core Node])) 

a wyjście z LEIN autoexpect:

*************** Running tests *************** 
Error refreshing environment: java.lang.ClassNotFoundException: linked-list.core.INode, compiling:(linked_list/core_test.clj:1:1) 
Tests completed at 07:29:36.252 

Propozycja stosować metodę fabrycznego jednakże jest to opłacalna praca.

Powiązane problemy