Qual è la differenza tra Cake e Leiningen?Qual è la differenza tra Cake e Leiningen?
risposta
Questa risposta continua ad ottenere interessi, presumibilmente come riferimento per Leiningen in StackOverflow quindi è ora notevolmente modificato per aggiornarlo per il 2014.
Leiningen e torta fusa nel 2011. Leiningen (versione 2) è ora lo strumento di automazione Clojure de facto.
Leiningen è uno strumento di creazione e gestore dipendenza per Clojure che include la capacità di impostare un REPL interattiva con il percorso di classe opportunamente configurata e con tutte le dipendenze java e Clojure acquisiti in modo automatico dai repository Maven e/o la comunità basate Clojars.
torta era molto simile a Leiningen (fino al utilizzando lo stesso formato di file project.clj al momento), ma ha tentato di evitare un sacco di spese generali di avvio mantenendo JVM persistenti intorno in background. Questa soluzione era più reattiva ma scambiata per i bug dovuti allo stato accumulato nei processi persistenti (vecchie definizioni di funzioni che gironzolavano, ecc.) Nel corso tipico dello sviluppo iterativo basato su REPL. Questo si è rivelato un pessimo affare.
L'esperienza con Leiningen e un continuo desiderio di tempi di avvio più veloci hanno portato ad una serie di raccomandazioni e approcci per le cose accelerare: https://github.com/technomancy/leiningen/wiki/Faster
La principale differenza è nel modo in cui le attività vengono attuate.
L'approccio di Cake è "è difficile estendere le funzioni dopo che sono state definite, quindi inventiamo un nuovo meccanismo per le attività anziché utilizzare le funzioni", che ha portato alla macro deftask.
L'approccio di Leiningen è "è difficile estendere le funzioni dopo che sono state definite, quindi dovremmo fare un modo per farlo facilmente, in questo modo possiamo usare le funzioni per le attività e anche estendere cose che non sono attività ", che consente di applicare tutti i vantaggi di componibilità delle funzioni con le attività.
Ti piacerebbe fornire un esempio? Non ho molta familiarità con Leiningen o Cake, e sarei interessato a vedere un'illustrazione della differenziazione che stai descrivendo tra i due. –
Quando le attività sono solo funzioni, è possibile estenderle in modi molto più interessanti. Testimoniare questo plugin di Leiningen: http://github.com/technomancy/rodney-leonard-stubbs L'estensione di attività di Cake consente solo di aggiungere/attivare effetti secondari, mentre Leiningen consente di ribattere, alterando argomenti/valore di ritorno ed esecuzione condizionale. Le attività di torta – technomancy
possono contenere anche chiamate di funzione, supportando tutte queste funzioni – lancepantz
Come ha detto Alex, la differenza più evidente è la velocità dalla riga di comando. Cake utilizza una JVM persistente, quindi si verifica solo l'overhead di avvio di jvm quando si esegue un'attività all'interno del progetto per la prima volta. Se non si utilizza emacs + slime + clojure-test-mode, questo può essere un enorme risparmio di tempo. Ad esempio, una serie di test ragionevolmente ampia su uno dei miei progetti viene eseguita in 0,3 secondi in torta, rispetto a 11,2 secondi in lein.
Oltre alle prestazioni, l'idea alla base della torta è il modello di attività di dipendenza. Ogni attività viene eseguita una volta sola in una determinata build, tenendo conto di tutti i prerequisiti transitivi nel grafico delle dipendenze. Ecco un esempio da Martin Fowler's article on rake nella sintassi della torta, che va direttamente nel tuo project.clj.
(deftask code-gen
"This task generates code. It has no dependencies."
(println "generating code...")
...)
(deftask compile #{code-gen}
"This task does the compilation. It depends on code-gen."
(println "compiling...")
...)
(deftask data-load #{code-gen}
"This task loads the test data. It depends on code-gen."
(println "loading test data...")
...)
(deftask test #{compile data-load}
"This task runs the tests. It depends on compile and data-load."
(println "running tests...")
...)
a fare lo stesso in Leiningen, si dovrebbe per prima cosa creare una directory Leiningen nel progetto con 4 file: code_gen.clj, compile.clj, data_load.clj e my_test.clj.
src/Leiningen/code_gen.clj
(ns leiningen.code-gen
"This task generates code. It has no dependencies.")
(defn code-gen []
(println "generating code..."))
src/Leiningen/my_compile.clj
(ns leiningen.my-compile
"This task does the compilation. It depends on code-gen."
(:use [leiningen.code-gen]))
(defn my-compile []
(code-gen)
(println "compiling..."))
src/Leiningen/data_load.CLJ
(ns leiningen.data-load
"This task loads the test data. It depends on code-gen."
(:use [leiningen.code-gen]))
(defn data-load []
(code-gen)
(println "loading test data..."))
src/Leiningen/my_test.clj
(ns leiningen.my-test
"This task runs the tests. It depends on compile and data-load."
(:use [leiningen.my-compile]
[leiningen.data-load]))
(defn my-test []
(my-compile)
(data-load)
(println "running tests..."))
Ci si aspetterebbe ...
generating code...
compiling...
loading test data...
running tests...
Ma sia data-load e il mio-compilazione dipendono da codice-gen, quindi la tua uscita attuale è ...
generating code...
compiling...
generating code...
loading test data...
running tests...
Yo u avrebbe dovuto Memoize code-gen per evitare che venga eseguito più volte:
(ns leiningen.code-gen
"This task generates code. It has no dependencies.")
(def code-gen (memoize (fn []
(println "generating code..."))))
uscita:
generating code...
compiling...
loading test data...
running tests...
che è quello che vogliamo.
Le build sono più semplici e più efficienti se un'attività viene eseguita una sola volta per build, quindi abbiamo reso il comportamento predefinito nei build di torta. La filosofia è vecchia di decenni e condivisa da un lignaggio di strumenti di costruzione. Puoi ancora usare le funzioni, puoi ancora chiamarle ripetutamente e hai sempre a disposizione tutta la potenza del clojure.
Lein fornisce semplicemente una funzione semplice come attività, ma con il vincolo aggiunto che deve avere il proprio spazio dei nomi in src. Se un'attività dipende da esso, sarà in uno spazio dei nomi separato e deve utilizzare/richiedere l'altro nella macro ns
. Le creazioni di torte sembrano molto più ordinate e concise in confronto.
Un'altra differenza fondamentale è come vengono aggiunti i compiti. Supponiamo di voler aggiungere my-test
come prerequisito per l'attività jar
integrata da Lein. Nella torta, è possibile utilizzare la macro deftask
da aggiungere alle forme e alle dipendenze di un'attività.
(deftask jar #{my-test})
Lein usa Robert Hooke per aggiungere compiti. È una libreria davvero fantastica, dal nome della filosfera naturale preferita di tutti, ma richiederebbe una macro per la concisione di deftask
.
(add-hook #'leiningen.jar/jar (fn [f & args]
(my-test)
(apply f args)))
Cake ha anche la nozione di un progetto globale. Puoi aggiungere dipendenze specifiche degli utenti, come swank, a ~/.cake/project.clj
e averlo su tutti i tuoi progetti. Il progetto globale viene anche utilizzato per avviare una sostituzione all'esterno di un progetto per la sperimentazione. Lein implementa funzionalità simili supportando la configurazione per utente in ~/.lein/init.clj
e i plugin globali in ~/.lein/plugins
. In generale, Lein ha attualmente un ecosistema di plug-in molto più ricco rispetto alla torta, ma la torta include più attività fuori dalla scatola (guerra, distribuzione, compilazione java, dipendenze native, clojars e swank). Potrebbe anche valere la pena di controllare Cljr, in sostanza è solo un progetto globale con un gestore di pacchetti, ma senza funzionalità di build (non ho esperienza con esso comunque).
La vera differenza inconciliabile sono le definizioni dei compiti, come ha sottolineato la tecnologia. Nella mia opinione (parziale), la torta gestisce i compiti molto meglio. La necessità di un modello di dipendenza delle attività è diventato evidente quando abbiamo iniziato a utilizzare i buffer di protocollo nel nostro progetto con lein. I protobuf erano prerequisiti per tutti i nostri compiti, tuttavia la loro compilazione è molto lenta. Abbiamo anche un sacco di attività interdipendenti, quindi qualsiasi build è stata dolorosa. Inoltre, non mi piace il requisito di uno spazio dei nomi separato, e quindi un file src aggiuntivo, per ogni attività che creo.Gli sviluppatori dovrebbero creare molti compiti, l'approccio di lein scoraggia questo creando troppo attrito. Con la torta, puoi semplicemente usare la macro deftask all'interno di project.clj.
Cake è ancora giovane, e un work in progress, ma è un progetto molto attivo.
Bene, esiste anche "lein interactive" che consente di eseguire lein persistenti senza sovraccarico del tempo di avvio di Java per ciascun comando lein. – Marko
L'esempio di quattro task è abbastanza elaborato. È fatto in quel modo nel rendere perché make non ha funzioni, quindi tutto deve essere un compito. Ma non avresti mai spezzato i tuoi compiti in quel modo con Leiningen; semplicemente non ha senso Non vedi mai compiti così brevi; ci sono sempre almeno 2 o 3 funzioni di supporto nello spazio dei nomi di quella attività in pratica. – technomancy
Anche l'obiezione di concisione a Robert Hooke è molto sciocca; Ho implementato una macro anteposta in quattro righe per fare ciò che fanno le dipendenze di Cake. La parte più difficile è stata scegliere un nome per la macro. – technomancy
Come 2011-11-15, l'annuncio di cake and lein merge
Il gruppo clojure-cake è stato apparentemente cancellato. Un altro link dell'annuncio ancora in vita: https://groups.google.com/forum/#!topic/leiningen/WnnQIZipG5E – Joanis
torta è nel processo di fusione con Leiningen. Link: https://groups.google.com/forum/#!topic/leiningen/WnnQIZipG5E – Joanis