Inleiding tot Leiningen voor Clojure

1. Inleiding

Leiningen is een modern bouwsysteem voor onze Clojure-projecten. Het is ook volledig in Clojure geschreven en geconfigureerd.

Het werkt op dezelfde manier als Maven en geeft ons een declaratieve configuratie die ons project beschrijft, zonder dat we de exacte uit te voeren stappen hoeven te configureren.

Laten we erin springen en kijken hoe we aan de slag kunnen gaan met Leiningen voor het bouwen van onze Clojure-projecten.

2. Leiningen installeren

Leiningen is beschikbaar als een zelfstandige download, evenals van een groot aantal pakketbeheerders voor verschillende systemen.

Standalone downloads zijn beschikbaar voor zowel Windows als voor Linux en Mac. Download in alle gevallen het bestand, maak het indien nodig uitvoerbaar en dan is het klaar voor gebruik.

De eerste keer dat het script wordt uitgevoerd, wordt de rest van de Leiningen-applicatie gedownload en wordt dit vanaf dit punt in de cache opgeslagen:

$ ./lein Leiningen downloaden naar /Users/user/.lein/self-installs/leiningen-2.8.3-standalone.jar nu ... ..... Leiningen is een tool voor het werken met Clojure-projecten. Er zijn verschillende taken beschikbaar: ..... Start `lein help $ TASK` voor details. .....

3. Een nieuw project aanmaken

Zodra Leiningen is geïnstalleerd, kunnen we het gebruiken om een ​​nieuw project te maken door aan te roepen lein nieuw.

Hiermee wordt een project gemaakt met een bepaalde sjabloon uit een reeks opties:

  • app - Wordt gebruikt om een ​​applicatie te maken
  • standaard - Wordt gebruikt om een ​​algemene projectstructuur te creëren, typisch voor bibliotheken
  • inpluggen - Wordt gebruikt om een ​​Leiningen-plug-in te maken
  • sjabloon - Wordt gebruikt om nieuwe Leiningen-sjablonen voor toekomstige projecten te maken

Om bijvoorbeeld een nieuwe applicatie met de naam "mijn-project" te maken, voeren we het volgende uit:

$ ./lein nieuwe app mijn-project Het genereren van een project met de naam mijn-project op basis van de 'app'-sjabloon.

Dit geeft ons een project met daarin:

  • Een build-definitie - project.clj
  • Een brondirectory - src - inclusief een eerste bronbestand - src / mijn_project / core.clj
  • Een testdirectory - test - inclusief een eerste testdossier - test / mijn_project / core_test.clj
  • Enkele aanvullende documentatiebestanden - README.md, LICENTIE, CHANGELOG.md en doc / intro.md

Als we in onze build-definitie kijken, zullen we zien dat het ons vertelt wat we moeten bouwen, maar niet hoe we het moeten bouwen:

(defproject mijn-project "0.1.0-SNAPSHOT": beschrijving "FIXME: schrijf beschrijving": url "//example.com/FIXME": licentie {: naam "EPL-2.0 OF GPL-2.0-of-later MET Klassepad -exception-2.0 ": url" //www.eclipse.org/legal/epl-2.0/ "}: afhankelijkheden [[org.clojure / clojure" 1.9.0 "]]: main ^: skip-aot my-project .core: target-path "target /% s": profielen {: uberjar {: aot: all}})

Dit vertelt ons:

  • De details van het project bestaande uit de projectnaam, versie, beschrijving, homepage en licentiegegevens.
  • De belangrijkste naamruimte die moet worden gebruikt bij het uitvoeren van de toepassing
  • De lijst met afhankelijkheden
  • Het doelpad om de uitvoer in te bouwen
  • Een profiel voor het bouwen van een uberjar

Merk op dat de belangrijkste bronnaamruimte mijn-project.core, en is te vinden in het bestand mijn_project / core.clj. Het wordt in Clojure afgeraden om naamruimten met één segment te gebruiken - het equivalent van klassen op het hoogste niveau in een Java-project.

Bovendien worden de bestandsnamen gegenereerd met onderstrepingstekens in plaats van met koppeltekens, omdat de JVM problemen heeft met koppeltekens in bestandsnamen.

De gegenereerde code is vrij eenvoudig:

(ns my-project.core (: gen-class)) (defn -main "Ik doe nog niet heel veel ..." [& args] (println "Hello, World!"))

Merk ook op dat Clojure hier slechts een afhankelijkheid is. Dit maakt het triviaal om projecten te schrijven met elke gewenste versie van de Clojure-bibliotheken, en vooral om meerdere verschillende versies op hetzelfde systeem te laten draaien.

Als we deze afhankelijkheid wijzigen, krijgen we in plaats daarvan de alternatieve versie.

4. Bouwen en rennen

Ons project is niet veel waard als we het niet kunnen bouwen, uitvoeren en verpakken voor distributie, dus laten we daar nu naar kijken.

4.1. Een REPL starten

Zodra we een project hebben, kunnen we een REPL erin lanceren met lein repl. Dit geeft ons een REPL waarin alles in het project al beschikbaar is op het klassenpad - inclusief alle projectbestanden en alle afhankelijkheden.

Het start ons ook in de gedefinieerde hoofdnaamruimte voor ons project:

$ lein repl nREPL-server gestart op poort 62856 op host 127.0.0.1 - nrepl: //127.0.0.1: 62856 [] REPL-y 0.4.3, nREPL 0.5.3 Clojure 1.9.0 Java HotSpot (TM) 64-bits server VM 1.8.0_77-b03 Documenten: (doc functie-naam-hier) (zoek-doc "deel-van-naam-hier") Bron: (bron functie-naam-hier) Javadoc: (javadoc java-object-of- class-here) Exit: Control + D of (exit) of (quit) Resultaten: opgeslagen in vars * 1, * 2, * 3, een uitzondering in * e my-project.core => (-main) Hallo, Wereld ! nihil

Dit voert de functie uit -hoofd in de huidige naamruimte, die we hierboven hebben gezien.

4.2. De applicatie uitvoeren

Als we werken aan een applicatieproject - gemaakt met lein nieuwe app - dan we kunnen de applicatie eenvoudig vanaf de opdrachtregel uitvoeren. Dit gebeurt met lein rennen:

$ lein run Hallo, wereld!

Dit zal de functie uitvoeren die wordt aangeroepen -hoofd in de naamruimte gedefinieerd als :hoofd in onze project.clj het dossier.

4.3. Een bibliotheek bouwen

Als we werken aan een bibliotheekproject - gemaakt met lein nieuwe standaard - dan we kunnen de bibliotheek in een JAR-bestand bouwen voor opname in andere projecten.

We hebben twee manieren waarop we dit kunnen bereiken - door te gebruiken lein pot of lein installeren. Het verschil zit hem simpelweg in waar het output JAR-bestand is geplaatst.

Als we lein pot dan plaatst het het in de local doelwit directory:

$ lein jar Gemaakt /Users/user/source/me/my-library/target/my-library-0.1.0-SNAPSHOT.jar

Als we lein installeren, dan zal het het JAR-bestand bouwen, een pom.xml bestand en plaats de twee vervolgens in de lokale Maven-repository (meestal onder .m2 / repository in de homedirectory van de gebruiker)

$ lein install Gemaakt /Users/user/source/me/my-library/target/my-library-0.1.0-SNAPSHOT.jar Schreef /Users/user/source/me/my-library/pom.xml Geïnstalleerde jar en pom naar de lokale opslagplaats.

4.4. Een Uberjar bouwen

Als we aan een aanvraagproject werken, Leiningen geeft ons de mogelijkheid om een ​​zogenaamde uberjar te bouwen. Dit is een JAR-bestand dat het project zelf en alle afhankelijkheden bevat en zo is ingesteld dat het kan worden uitgevoerd zoals het is.

$ lein uberjar Mijn-project.core compileren Gemaakt /Users/user/source/me/my-project/target/uberjar/my-project-0.1.0-SNAPSHOT.jar Gemaakt / Users / user / source / me / my- project / target / uberjar / mijn-project-0.1.0-SNAPSHOT-standalone.jar

Het bestand mijn-project-0.1.0-SNAPSHOT.jar is een JAR-bestand dat precies het lokale project en het bestand bevat mijn-project-0.1.0-SNAPSHOT-standalone.jar bevat alles wat nodig is om de applicatie uit te voeren.

$ java -jar target / uberjar / my-project-0.1.0-SNAPSHOT-standalone.jar Hallo, wereld!

5. Afhankelijkheden

Hoewel we alles wat nodig is voor ons project zelf kunnen schrijven, is het over het algemeen aanzienlijk beter om het werk dat anderen al voor ons hebben gedaan, opnieuw te gebruiken. We kunnen dit doen door ons project te laten afhangen van deze andere bibliotheken.

5.1. Afhankelijkheden toevoegen aan ons project

Om afhankelijkheden aan ons project toe te voegen, moeten we ze correct toevoegen aan ons project.clj het dossier.

Afhankelijkheden worden weergegeven als een vector die bestaat uit de naam en versie van de afhankelijkheid in kwestie. We hebben al gezien dat Clojure zelf wordt toegevoegd als een afhankelijkheid, geschreven in het formulier [org.clojure / clojure "1.9.0"].

Als we andere afhankelijkheden willen toevoegen, kunnen we dit doen door ze toe te voegen aan de vector naast de : afhankelijkheden trefwoord. Als we bijvoorbeeld afhankelijk willen zijn van clj-json we zouden het bestand bijwerken:

 : afhankelijkheden [[org.clojure / clojure "1.9.0"] [clj-json "0.5.3"]]

Als we eenmaal klaar zijn, als we onze REPL starten - of een andere manier om ons project te bouwen of uit te voeren - dan zal Leiningen ervoor zorgen dat de afhankelijkheden worden gedownload en beschikbaar zijn op het klassenpad:

$ lein repl Clj-json / clj-json / 0.5.3 / clj-json-0.5.3.pom ophalen van clojars Clj-json / clj-json / 0.5.3 / clj-json-0.5.3.jar ophalen van clojars nREPL-server gestart op poort 62146 op host 127.0.0.1 - nrepl: //127.0.0.1: 62146 REPL-y 0.4.3, nREPL 0.5.3 Clojure 1.9.0 Java HotSpot (TM) 64-bits server VM 1.8.0_77 -b03 Docs: (doc functie-naam-hier) (zoek-doc "deel-van-naam-hier") Bron: (bron functie-naam-hier) Javadoc: (javadoc java-object-of-klasse-hier) Exit: Control + D of (exit) of (quit) Resultaten: opgeslagen in vars * 1, * 2, * 3, een uitzondering in * e my-project.core => (vereisen '(clj-json [core: as json])) nihil my-project.core => (json / genereren-string {"foo" "bar"}) "{\" foo \ ": \" bar \ "}" my-project.core =>

We kunnen ze ook vanuit ons project gebruiken. We kunnen bijvoorbeeld het gegenereerde src / mijn_project / core.clj bestand als volgt:

(ns my-project.core (: gen-class)) (vereis '(clj-json [core: as json])) (defn -main "Ik doe nog niet veel ..." [& args] (println (json / genereren-string {"foo" "bar"})))

En dan werkt het precies zoals verwacht:

$ lein rennen {"foo": "bar"}

5.2. Afhankelijkheden zoeken

Vaak kan het moeilijk zijn om de afhankelijkheden te vinden die we in ons project willen gebruiken. Leiningen wordt geleverd met een ingebouwde zoekfunctionaliteit om dit gemakkelijker te maken. Dit gebeurt met lein zoeken.

We kunnen bijvoorbeeld onze JSON-bibliotheken vinden:

$ lein search json Zoeken centraal ... [com.jwebmp / ​​json "0.63.0.60"] [com.ufoscout.coreutils / json "3.7.4"] [com.github.iarellano / json "20190129"] ... .. Zoeken naar clojars ... [cheshire "5.8.1"] JSON en JSON SMILE codering, snel. [json-html "0.4.4"] Geef JSON en verkrijg een DOM-knooppunt met een menselijke weergave van die JSON [ring / ring-json "0.5.0-beta1"] Ring-middleware voor het afhandelen van JSON [clj-json "0.5. 3 "] Snelle JSON-codering en decodering voor Clojure via de Jackson-bibliotheek. .....

Dit doorzoekt alle repositories waarmee ons project werkt - in dit geval Maven Central en Clojars. Het retourneert vervolgens de exacte tekenreeks die in ons moet worden geplaatst project.clj bestand en, indien beschikbaar, de beschrijving van de bibliotheek.

6. Ons project testen

Clojure heeft ingebouwde ondersteuning voor het testen van onze applicatie, en Leiningen kan dit voor onze projecten gebruiken.

Ons gegenereerde project bevat testcode in de test directory, naast de broncode in het src directory. Het bevat ook standaard een enkele, falende test - te vinden in test / mijn_project / core-test.clj:

(ns my-project.core-test (: vereist [clojure.test: refer: all] [my-project.core: refer: all])) (deftest a-test (test "FIXME, ik faal." (is (= 0 1))))

Dit importeert het mijn-project.core naamruimte van ons project, en de clojure.test naamruimte van de Clojure-kerntaal. We definiëren dan een test met de behendigste en testen oproepen.

We kunnen onmiddellijk de namen van de test zien, en het feit dat het opzettelijk is geschreven om te falen - het beweert dat 0 == 1.

Laten we dit uitvoeren met behulp van de lein-test opdracht, en zie onmiddellijk de tests lopen en mislukken:

$ lein test lein test mijn-project.core-test lein-test: alleen mijn-project.core-test / a-test FAIL in (a-test) (core_test.clj: 7) FIXME, ik faal. verwacht: (= 0 1) actueel: (niet (= 0 1)) Ran 1 tests met 1 beweringen. 1 fouten, 0 fouten. Tests zijn mislukt.

Als we in plaats daarvan de test repareren, verander deze dan om dat te bevestigen 1 == 1 in plaats daarvan krijgen we in plaats daarvan een passerend bericht:

$ lein test lein test my-project.core-test Ran 1 tests met 1 beweringen. 0 fouten, 0 fouten.

Dit is een veel beknoptere output, die alleen laat zien wat we moeten weten. Dit betekent dat als er storingen zijn, vallen ze meteen op.

Als we willen, kunnen we ook een specifieke subset van de tests uitvoeren. Op de opdrachtregel kan een naamruimte worden opgegeven, en alleen tests in die naamruimte worden uitgevoerd:

$ lein test my-project.core-test lein test my-project.core-test Ran 1 tests met 1 beweringen. 0 fouten, 0 fouten. $ lein test my-project.unknown lein test my-project.unknown Ran 0 tests met 0 beweringen. 0 fouten, 0 fouten.

7. Samenvatting

Dit artikel heeft laten zien hoe u aan de slag kunt met de Leiningen-buildtool en hoe u deze kunt gebruiken om onze op Clojure gebaseerde projecten te beheren - zowel uitvoerbare applicaties als gedeelde bibliotheken.

Waarom probeer je het niet uit bij het volgende project en kijk je hoe goed het kan werken.