Bonjour, et Welcome to Clojure :-D
J'avais préparé une réponse plus complète, mais Bertrand et Christophe ont déjà dit beaucoup, je vais donc juste compléter :
- Si tu fais plus qu'un petit essai dans un coin, alors créer un vrai projet sous GitHub avec un fichier Leiningen project.clj permet de faciliter la vie aux personnes que tu sollicites : très facile alors de regarder un peu ton code, jouer avec en lançant le projet via Lein repl, etc.
- ce genre de librairie est presque un cas d'école pour l'utilisation de tests unitaires automatisés
- parce que c'est très facile à écrire (dès lors que tu isoles comme tu l'as fait la fonction principale d'analyse d'une ligne de la manière dont la ligne est récupérée, cette fonction est facilement testable)
- parce qu'une librairie csv, avec ses innombrables cas particuliers, appelle vraiment des tests unitaires automatisés
Je pense donc que ton projet gagnerait énormément à avoir de vrais tests automatisés (juste utiliser clojure.test est largement suffisant pour une librairie csv je pense, car il s'agit plus d'avoir une suite de non-régression).
Enfin, comme le disait Bertrand, il existe déjà plusieurs librairies csv en Clojure, soit "wrappant" des librairies java existantes comme open-csv, soit réécrites de zéro (une recherche dans la ml clojure devrait te retourner les versions les plus récentes).
Bien sûr, je comprends l'intérêt de l'exercice, mais si ton objectif (comme ton email le suggérait à demi mot) est de parser du csv pour un projet "de prod", alors à la fin de l'exercice à ta place j'utiliserai une des librairies déjà existantes.
Quelques remarques moins importantes sur le code :
Trop décomposer en variables peut autant nuire à la lisibilité que pas assez décomposer. Ainsi, tu pourrais enlever une ligne sur 2 ici :
(let [quoted-field-pattern-str (str field-delimiter ".*" field-delimiter)
quoted-field-pattern (re-pattern quoted-field-pattern-str)
...] ...)
(let [quoted-field-pattern (re-pattern (str field-delimiter ".*" field-delimiter))
...] ...)
Mais ailleurs, j'ai trouvé difficile de suivre le code car les lignes sont vraiment longues (plus de 140 chars contenant de multiples expressions:
(loop [parts (s/split csv-record (re-pattern field-separator)) , fields [] , incomplete-field [] ]
(cond
(nil? parts) fields
(and (empty? incomplete-field) (re-matches quoted-field-pattern (first parts))) (recur (next parts) (conj fields (clean-field (first parts))) [])
(and (empty? incomplete-field) (or (empty? (first parts)) (simple-field-pattern? (first parts)))) (recur (next parts) (conj fields (first parts)) [])
(re-matches quoted-end-field-pattern (first parts)) (recur (next parts) (conj fields (clean-field (s/join field-separator (conj incomplete-field (first parts))))) [])
:else (recur (next parts) fields (conj incomplete-field (first parts)))
)
))
Quand les expressions dans un (and) sont longues, les mettre chacune sur une ligne aide bien à la relecture
Dans un cond, si la partie conditionnelle est longue, ce que je fais souvent c'est mettre alors l'expression associée sur la ligne suivante, réindentée de 2 espaces
Propreté du code : à partir du moment où tu sollicites une relecture, il est agréable pour les relecteurs de lire un code "propre", par ex. avec les parenthèses fermantes rassemblées (il m'arrive aussi de laisser pendant le dev des parenthèses fermantes sur leur propre ligne pour plus facilement faire du copier/coller par ligne, ajouter une nouvelle ligne dans un doseq, un cond, etc., mais à la fin je trouve que tout rassembler fait vraiment plus propre)
Par ex., la fonction complete-record est vraiment difficile à la lire uniquement à cause d'une mauvaise indentation et de trop de retours à la ligne :
(defn complete-record?
"Returns if a line is a complete record or finalizes a complete record."
([line] (let [c (seq line) initial-status (if (= (first c) \") false true) ]
(complete-record? initial-status line))
)
([initial-status line] (let [c (seq line) ]
(if (reduce new-open-status initial-status (partition 2 1 c)) (= (last c) \") true))
)
)
Il suffirait de peu de choses pour que ça pique moins les yeux:
https://gist.github.com/3181088Bonne chance, et surtout ne te décourage pas, on est tous passés par là au début.
--
Laurent