2010-09-11 11 views
12

Ho un progetto con leiningen chiamato techne. Ho creato un modulo chiamato scrub con un tipo chiamato Scrub e una funzione chiamata foo.Come si usa un tipo al di fuori del proprio spazio dei nomi in 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)))) 

Quando eseguo il test, ottengo l'errore:

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) 

Se io rimuovere test-scrub tutto funziona bene. Perché: usare techne.scrub 'importa' le definizioni di funzione ma non le definizioni di tipo? Come faccio a fare riferimento alle definizioni del tipo?

risposta

15

Poiché deftype genera una classe, sarà probabilmente necessario importare la classe Java in techne.scrub-test con (: import [techne.scrub Scrub]) nella definizione di ns.

realtà ho scritto questa stessa cosa per quanto riguarda defrecord qui:

Un'altra cosa che si potrebbe fare sarebbe quella di definire una funzione di costruzione di macchia:

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

e quindi non è necessario importare Scrub in test-scrub.

+1

Uso sempre le funzioni di costruzione per questo motivo e per la convalida. –

+1

Sì, abbiamo trovato utile estendere defrecord per aggiungere automaticamente funzioni di costruzione con convalida dei campi, supporto pprint a un form evalable, ecc. –

+4

Si noti che questa risposta è precedente a Clojure 1.4. Dalla versione 1.4, un costruttore posizionale (-> Scrub) e mappa (map-> Scrub) verrà automaticamente creato da defrecord. Questo è il metodo di costruzione preferito e richiede solo che tu faccia riferimento a tali funzioni nel tuo spazio dei nomi - non è necessario importare la classe. –

0

Aggiungo l'importazione, ma ho lo stesso problema. Sto testando il pacchetto Expectations 2.0.9, cercando di importare il nodo deftype e l'interfaccia INode.

In 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) _)) 

In 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])) 

e l'uscita da 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 

Il suggerimento di utilizzare un metodo di fabbrica, tuttavia, è una soluzione valida.

Problemi correlati