Obsah
1. Leiningen: nástroj pro správu projektů napsaných v Clojure
2. Základní vlastnosti nástroje Leiningen
3. Instalace Leiningenu z balíčku distribuce
4. Instalace v případě, že balíček není k dispozici
5. Otestování základní funkčnosti instalace Leiningenu
7. Automatické stažení závislých balíčků a spuštění projektu
9. Přidání nové knihovny, na níž projekt závisí
10. Automatické stažení závislé knihovny
11. Otestování upraveného projektu
1. Leiningen: nástroj pro správu projektů napsaných v Clojure
V dnešním článku si popíšeme vybrané základní vlastnosti nástroje Leiningen, který je v současnosti používán poměrně velkým množstvím projektů vyvinutých s využitím programovacího jazyka Clojure. Leiningen se typicky používá pro vytváření nových projektů na základě předem připravené šablony, automatické stahování všech potřebných knihoven (i jejich závislostí), spouštění projektů, spouštění testů a v neposlední řadě taktéž pro spuštění interaktivní smyčky REPL, která vývojářům nabízí více možnosti, než standardní implementace REPLu dostupná přímo v Clojure (mezi přidané vlastnosti patří zejména automatické nastavení cest ke knihovnám apod.). Leiningen je multiplatformním produktem, což znamená, že i ty vývojové týmy, jejichž členové pracují s různými operačními systémy, mohou možnosti nabízené Leiningenem využít. K Leiningenu lze v případě potřeby připojovat i další přídavné moduly (plugins), takže například existuje podpora pro spuštění webové aplikace takovým způsobem, že se změny provedené ve zdrojových kódech ihned promítnou do běžící aplikace bez nutnosti jejího restartu, což samozřejmě umožňuje rychlejší vývoj i testování.
2. Základní vlastnosti nástroje Leiningen
O některých vlastnostech nabízených nástrojem Leiningen jsme se zmínili již v předchozí kapitole, zkusme si ovšem jeho základní vlastnosti postupně uvést v jednotlivých bodech:
- Vytvoření nového projektu na základě vybrané a předem připravené šablony. K dispozici jsou šablony běžné aplikace (doplněné o jednotkové testy), přídavného modulu pro samotný Leiningen atd. Základním příkazem je lein new.
- Automatické stažení všech knihoven a jejich závislostí na základě konfigurace zapsané do souboru project.clj. Tuto funkci zajistí příkaz lein deps.
- Spuštění projektu s možností předání parametrů příkazového řádku (viz ukázkový příklad). Příkaz je jednoduchý: lein run.
- Spuštění jednotkových testů, které mohou být vytvořeny společně s projektem (kostra jednoho testu je připravena automaticky). Snadno uhádnutelný příkaz, který testy spustí, se jmenuje lein test.
- Relativně rychlá kontrola syntaxe zdrojových kódů i kontrola existence volaných metod (lein check).
- Lokální instalace projektu do specifikovaného adresáře (lein install).
- Příprava Java archivu (souboru s koncovkou .jar) takovým způsobem, aby bylo možné aplikaci nasadit i na jiném počítači. V rámci přípravy archivu se provádí překlad vybraných modulů do javovského bajtkódu (lein jar).
- Příprava Java archivu obsahujícího i všechny závislé knihovny včetně samotného Clojure. Takto vytvořený „uberjar“ je posléze možné nasadit na jakémkoli počítači vybaveném pouze JRE (běhovým prostředím jazyka Java). Zajistí příkaz lein uberjar.
- Spuštění smyčky REPL s nastavením cest ke všem potřebným knihovnám a modulům (lein repl).
- Každý příkaz Leiningenu je v rozumné míře popsán v nápovědě (lein help příkaz).
3. Instalace Leiningenu z balíčku distribuce
Pojďme si nyní říci, jakým způsobem lze Leiningen nainstalovat. Nejjednodušší je to v případě, že se balíček s tímto nástrojem již nachází v repositářích distribuce. Postup je nasnadě – Leiningen se nainstaluje (i se svými závislostmi) stejným způsobem, jako prakticky jakýkoli jiný balíček. Podívejme se například na způsob instalace Leiningenu na počítači s (primárně) desktopovou distribucí Linux Mint. Předpokládejme, že aktuálně přihlášený uživatel může získat práva roota, tedy:
$ su - Password:
Instalace je v tomto případě až triviálně snadná:
apt-get install leiningen
Po chvilce získáme seznam všech balíčků, které se nainstalují společně s Leiningenem:
Reading package lists... Done Building dependency tree Reading state information... Done The following extra packages will be installed: ant bsh clojure-contrib clojure1.2 clojure1.4 java-wrappers junit junit4 libapache-pom-java libasm3-java libatinject-jsr330-api-java libavalon-framework-java libbatik-java libbsf-java libbsh-java ... ... ... ... ... ... libxalan2-java libxbean-java libxerces2-java libxml-commons-external-java libxml-commons-resolver1.1-java libxmlgraphics-commons-java rlwrap 0 upgraded, 76 newly installed, 0 to remove and 85 not upgraded. Need to get 56,1 MB of archives. After this operation, 75,2 MB of additional disk space will be used. Do you want to continue? [Y/n]
Zajímavé je, kolik závislých balíčků se k Leiningenu doinstaluje. Ve skutečnosti nejsou některé tyto balíčky potřebné, o čemž se ostatně můžete sami přesvědčit při manuální instalaci popsané v následující kapitole (tímto chováním trpí i další javovské balíčky, třeba Eclipse apod.).
Na počítačích s operačním systémem Microsoft Windows lze buď použít Cygwin a manuální postup popsaný dále, popř. lze sáhnout po aplikaci leiningen-win-installer dostupné na adrese http://leiningen-win-installer.djpowell.net/ (osobně ji však nemám kde odzkoušet :-), takže prosím znalejší čtenáře, aby se o svoji pozitivní či negativní zkušenost podělili v diskuzi pod článkem).
4. Instalace v případě, že balíček není k dispozici
Zajímavější a vlastně i poučnější je manuální instalace Leiningenu v případě, že příslušný balíček není k dispozici popř. uživatel preferuje mít větší kontrolu nad celým procesem. Dále uvedený postup je možné po mírné úpravě využít i v případě, že uživatel nemá práva roota. Postup byl otestován na Debianu, Fedoře 19, Fedoře 20 a Linux Mintu, měl by však fungovat ve všech distribucích s nainstalovaným Bashem (i v Cygwinu). Nejprve je nutné stáhnout skript lein, který představuje samotné jádro Leiningenu:
wget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein
Chvíli počkáme na (doufejme) zdárný výsledek:
--2015-02-09 20:31:45-- https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 23.235.43.133 Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|23.235.43.133|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 12015 (12K) [text/plain] Saving to: 'lein' 100%[=========================================================>] 12 015 --.-K/s in 0,002s 2015-02-09 20:31:46 (5,85 MB/s) - 'lein' saved [12015/12015]
Nyní máme na výběr dvě možnosti. Buď je možné skript lein uložit do libovolného lokálního adresáře, který je součástí proměnné PATH (lze snadno zjistit přes echo $PATH), popř. lze tento skript „nainstalovat“ takovým způsobem, aby byl dostupný i pro všechny ostatní uživatele. První možnost je jednoduchá, předpokládejme instalaci do ~/bin a udělejme skript spustitelný:
chmod u+x lein mv lein ~/bin
Druhá možnost – instalace tak, aby byl lein dostupný i pro další uživatele – samozřejmě vyžaduje příslušná práva roota:
sudo cp lein /usr/local/bin sudo chmod a+x /usr/local/bin/lein
Pro jistotu lze samozřejmě zkontrolovat, co se v tomto skriptu provádí :-)
5. Otestování základní funkčnosti instalace Leiningenu
I po úspěšné instalaci skriptu lein ještě není vše připraveno k okamžitému použití. Ve skutečnosti totiž skript lein ke své činnosti potřebuje i další soubor, jímž je (minimálně v současnosti) javovský archiv nazvaný leiningen-2.x.x-standalone.jar (x.x se postupně mění). Tento archiv je však stažen a uložen zcela automaticky při prvním spuštění Leiningenu. Můžeme si to ostatně snadno otestovat:
lein
Zahájí se stahování a posléze se vypíšou všechny možnosti, které Leiningen v základní instalaci svým uživatelům nabízí:
Downloading Leiningen to /home/tester/.lein/self-installs/leiningen-2.5.1-standalone.jar now... % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 406 0 406 0 0 749 0 --:--:-- --:--:-- --:--:-- 749 100 14.5M 100 14.5M 0 0 1618k 0 0:00:09 0:00:09 --:--:-- 1510k Leiningen is a tool for working with Clojure projects. Several tasks are available: change Rewrite project.clj by applying a function. check Check syntax and warn on reflection. classpath Print the classpath of the current project. clean Remove all files from project's target-path. compile Compile Clojure source into .class files. deploy Build and deploy jar to remote repository. deps Download all dependencies. do Higher-order task to perform other tasks in succession. help Display a list of tasks or help for a given task. install Install the current project to the local repository. jar Package up all the project's files into a jar file. javac Compile Java source files. new Generate project scaffolding based on a template. plugin DEPRECATED. Please use the :user profile instead. pom Write a pom.xml file to disk for Maven interoperability. release Perform :release-tasks. repl Start a repl session either with the current project or standalone. retest Run only the test namespaces which failed last time around. run Run a -main function with optional command-line arguments. search Search remote maven repositories for matching jars. show-profiles List all available profiles or display one if given an argument. test Run the project's tests. trampoline Run a task without nesting the project's JVM inside Leiningen's. uberjar Package up the project files and dependencies into a jar file. update-in Perform arbitrary transformations on your project map. upgrade Upgrade Leiningen to specified version or latest stable. vcs Interact with the version control system. version Print version for Leiningen and the current JVM. with-profile Apply the given task with the profile(s) specified. Run `lein help $TASK` for details. Global Options: -o Run a task offline. -U Run a task after forcing update of snapshots. -h, --help Print this help or help for a specific task. -v, --version Print Leiningen's version. See also: readme, faq, tutorial, news, sample, profiles, deploying, gpg, mixed-source, templates, and copying.
Výše zmíněný soubor leiningen-2.x.x-standalone.jar naleznete v adresáři ~/.lein:
$ tree ~/.lein /home/ptisnovsk/.lein ├── repl-history └── self-installs └── leiningen-2.5.0-standalone.jar 1 directory, 2 files
6. Vytvoření nového projektu
Nyní si již konečně můžeme popsat způsob práce s projekty s využitím nástroje Leiningen. Základním příkazem je vytvoření nového projektu v aktuálním adresáři. Tuto činnost zajišťuje příkaz lein new, kterému se navíc musí předat typ projektu:
lein new
V základní instalaci Leiningenu (tj. ve chvíli, kdy prozatím nejsou nainstalovány žádné další přídavné moduly) by měly být k dispozici minimálně následující čtyři typy projektů:
Subtasks available: template A meta-template for 'lein new' templates. default A general project template for libraries. app An application project template. plugin A leiningen plugin project template.
Zkusme si nyní vytvořit běžný projekt představující aplikaci naprogramovanou v Clojure. Pro vytvoření projektu použijeme následující příkaz:
lein new app clojure_test_1 Generating a project called clojure_test_1 based on the 'app' template.
V případě úspěchu by se měl v aktuálním adresáři vytvořit podadresář s názvem clojure_test1, který má tuto strukturu:
. ├── doc │ └── intro.md ├── LICENSE ├── project.clj ├── README.md ├── resources ├── src │ └── clojure_test_1 │ └── core.clj └── test └── clojure_test_1 └── core_test.clj 6 directories, 6 files
Soubory doc/intro.md, LICENCE a README.md jsou základem dokumentace, ovšem z hlediska vývojáře existuje v projektu dvojice mnohem důležitějších souborů. Prvním z nich je project.clj. Tento soubor je zpracováván Leiningenem při mnoha činnostech, zejména při spouštění aplikace, instalaci závislostí apod. Podívejme se nyní na obsah tohoto souboru:
(defproject clojure_test_1 "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.6.0"]] :main ^:skip-aot clojure-test-1.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Vidíme, že se jedná o běžný zdrojový soubor programovacího jazyka Clojure obsahující mapu, v níž jednotlivé klíče mají předem daný význam. Důležitý je především klíč :main, kterým se specifikuje soubor s funkcí pojmenovanou main-. Tato funkce je zavolána po spuštění aplikace a navíc jsou této funkci předány parametry z příkazové řádky (takže jejich zpracování je velmi jednoduché, není totiž nutné používat *command-line-args* atd.). Dále zde můžeme vidět další důležitý klíč :dependencies, o jehož významu se přesvědčíme v navazujících kapitolách.
Soubor src/clojure_test1/core.clj obsahuje základní kostru aplikace. Především zde nalezneme specifikaci jmenného prostoru (což je pochopitelné) a taktéž výše zmíněnou funkci main- tvořící vstupní bod do právě vytvořené aplikace:
(ns clojure-test-1.core (:gen-class)) (defn -main "I don't do a whole lot ... yet." [& args] (println "Hello, World!"))
Poznámka: povšimněte si, že ve jménech adresářů a souborů se používají podtržítka, kdežto ve specifikacích jmenných prostorů pomlčky. Na tuto konvenci je nutné si zvyknout, při jejím nedodržení totiž Clojure nenajde všechny skripty a budou vypisována mnohdy kryptická chybová hlášení.
7. Automatické stažení závislých balíčků a spuštění projektu
Právě vytvořený projekt lze spustit příkazem lein run zavolaného v adresáři s projektem, tedy:
cd clojure_test_1 lein run
Před prvním spuštěním se automaticky vyhodnotí všechny závislé balíčky, ty se stáhnou a použijí (vidíme, že se mj. stahuje i samotné Clojure):
Retrieving org/clojure/clojure/1.6.0/clojure-1.6.0.pom from central Retrieving org/sonatype/oss/oss-parent/7/oss-parent-7.pom from central Retrieving org/clojure/tools.nrepl/0.2.6/tools.nrepl-0.2.6.pom from central Retrieving org/clojure/pom.contrib/0.1.2/pom.contrib-0.1.2.pom from central Retrieving clojure-complete/clojure-complete/0.2.3/clojure-complete-0.2.3.pom from clojars Retrieving org/clojure/tools.nrepl/0.2.6/tools.nrepl-0.2.6.jar from central Retrieving org/clojure/clojure/1.6.0/clojure-1.6.0.jar from central Retrieving clojure-complete/clojure-complete/0.2.3/clojure-complete-0.2.3.jar from clojars Hello, World!
Po druhém spuštění stejné aplikace příkazem:
lein run
Se již žádné další balíčky nestahují, ale dojde skutečně přímo ke spuštění:
Hello, World!
8. Struktura adresáře ~/.m2
Zajímavé bude zjistit, kam se vlastně uložily všechny balíčky, na nichž běh aplikace závisí. Projekt Leiningen ve skutečnosti používá stejnou strukturu jako Maven (resp. přesněji řečeno je přímo využívána funkcionalita Mavenu), takže balíčky nalezneme v adresáři ~/.m2 (který vám bude časem utěšeně bobtnat :-). Obsah adresáře těsně po spuštění demonstračního příkladu vypadá takto:
tree ~/.m2
. └── repository ├── clojure-complete │ └── clojure-complete │ └── 0.2.3 │ ├── clojure-complete-0.2.3.jar │ ├── clojure-complete-0.2.3.jar.sha1 │ ├── clojure-complete-0.2.3.pom │ ├── clojure-complete-0.2.3.pom.sha1 │ └── _maven.repositories └── org ├── clojure │ ├── clojure │ │ └── 1.6.0 │ │ ├── clojure-1.6.0.jar │ │ ├── clojure-1.6.0.jar.sha1 │ │ ├── clojure-1.6.0.pom │ │ ├── clojure-1.6.0.pom.sha1 │ │ └── _maven.repositories │ ├── pom.contrib │ │ └── 0.1.2 │ │ ├── _maven.repositories │ │ ├── pom.contrib-0.1.2.pom │ │ └── pom.contrib-0.1.2.pom.sha1 │ └── tools.nrepl │ └── 0.2.6 │ ├── _maven.repositories │ ├── tools.nrepl-0.2.6.jar │ ├── tools.nrepl-0.2.6.jar.sha1 │ ├── tools.nrepl-0.2.6.pom │ └── tools.nrepl-0.2.6.pom.sha1 └── sonatype └── oss └── oss-parent └── 7 ├── _maven.repositories ├── oss-parent-7.pom └── oss-parent-7.pom.sha1 16 directories, 21 files
Po několika týdnech práce na různých projektech se však můžete dopracovat i k následujícímu stavu:
/home/ptisnovsk/.m2 └── repository ├── args4j │ ├── args4j │ │ └── 2.0.16 │ │ ├── args4j-2.0.16.jar │ │ ├── args4j-2.0.16.jar.sha1 │ │ ├── args4j-2.0.16.pom │ │ ├── args4j-2.0.16.pom.sha1 │ │ └── _maven.repositories │ └── args4j-site │ └── 2.0.16 │ ├── args4j-site-2.0.16.pom │ ├── args4j-site-2.0.16.pom.sha1 │ └── _maven.repositories ├── cljsbuild │ └── cljsbuild │ └── 1.0.3 │ ├── cljsbuild-1.0.3.jar │ ├── cljsbuild-1.0.3.jar.sha1 │ ├── cljsbuild-1.0.3.pom │ ├── cljsbuild-1.0.3.pom.sha1 │ └── _maven.repositories ├── clj-stacktrace │ └── clj-stacktrace │ └── 0.2.5 │ ├── clj-stacktrace-0.2.5.jar │ ├── clj-stacktrace-0.2.5.jar.sha1 │ ├── clj-stacktrace-0.2.5.pom │ ├── clj-stacktrace-0.2.5.pom.sha1 │ └── _maven.repositories ├── clojure-complete │ └── clojure-complete │ └── 0.2.3 │ ├── clojure-complete-0.2.3.jar │ ├── clojure-complete-0.2.3.jar.sha1 │ ├── clojure-complete-0.2.3.pom │ ├── clojure-complete-0.2.3.pom.sha1 │ └── _maven.repositories ├── com │ └── google │ ├── code │ │ └── findbugs │ │ └── jsr305 │ │ └── 1.3.9 │ │ ├── jsr305-1.3.9.jar │ │ ├── jsr305-1.3.9.jar.sha1 │ │ ├── jsr305-1.3.9.pom │ │ ├── jsr305-1.3.9.pom.sha1 │ │ └── _maven.repositories │ ├── google │ │ └── 1 │ │ ├── google-1.pom │ │ ├── google-1.pom.sha1 │ │ └── _maven.repositories │ ├── guava │ │ ├── guava │ │ │ └── 15.0 │ │ │ ├── guava-15.0.jar │ │ │ ├── guava-15.0.jar.sha1 │ │ │ ├── guava-15.0.pom │ │ │ ├── guava-15.0.pom.sha1 │ │ │ └── _maven.repositories │ │ └── guava-parent │ │ └── 15.0 │ │ ├── guava-parent-15.0.pom │ │ ├── guava-parent-15.0.pom.sha1 │ │ └── _maven.repositories │ ├── javascript │ │ └── closure-compiler │ │ └── v20131014 │ │ ├── closure-compiler-v20131014.jar │ │ ├── closure-compiler-v20131014.jar.sha1 │ │ ├── closure-compiler-v20131014.pom │ │ ├── closure-compiler-v20131014.pom.sha1 │ │ └── _maven.repositories │ └── protobuf │ └── protobuf-java │ └── 2.4.1 │ ├── _maven.repositories │ ├── protobuf-java-2.4.1.jar │ ├── protobuf-java-2.4.1.jar.sha1 │ ├── protobuf-java-2.4.1.pom │ └── protobuf-java-2.4.1.pom.sha1 ├── fs │ └── fs │ └── 1.1.2 │ ├── fs-1.1.2.jar │ ├── fs-1.1.2.jar.sha1 │ ├── fs-1.1.2.pom │ ├── fs-1.1.2.pom.sha1 │ └── _maven.repositories ├── javassist │ └── javassist │ └── 3.12.1.GA │ ├── javassist-3.12.1.GA.jar │ ├── javassist-3.12.1.GA.jar.sha1 │ ├── javassist-3.12.1.GA.pom │ ├── javassist-3.12.1.GA.pom.sha1 │ └── _maven.repositories ├── lein-cljsbuild │ ├── cljs-compat │ │ └── 1.0.0-SNAPSHOT │ │ ├── cljs-compat-1.0.0-20140402.162347-24.jar │ │ ├── cljs-compat-1.0.0-20140402.162347-24.jar.sha1 │ │ ├── cljs-compat-1.0.0-20140402.162347-24.pom │ │ ├── cljs-compat-1.0.0-20140402.162347-24.pom.sha1 │ │ ├── cljs-compat-1.0.0-SNAPSHOT.jar │ │ ├── cljs-compat-1.0.0-SNAPSHOT.pom │ │ ├── maven-metadata-clojars.xml │ │ ├── maven-metadata-clojars.xml.sha1 │ │ ├── _maven.repositories │ │ └── resolver-status.properties │ └── lein-cljsbuild │ └── 1.0.3 │ ├── lein-cljsbuild-1.0.3.jar │ ├── lein-cljsbuild-1.0.3.jar.sha1 │ ├── lein-cljsbuild-1.0.3.pom │ ├── lein-cljsbuild-1.0.3.pom.sha1 │ └── _maven.repositories └── org ├── apache │ ├── apache │ │ └── 9 │ │ ├── apache-9.pom │ │ ├── apache-9.pom.sha1 │ │ └── _maven.repositories │ └── commons │ ├── commons-compress │ │ └── 1.3 │ │ ├── commons-compress-1.3.jar │ │ ├── commons-compress-1.3.jar.sha1 │ │ ├── commons-compress-1.3.pom │ │ ├── commons-compress-1.3.pom.sha1 │ │ └── _maven.repositories │ └── commons-parent │ └── 22 │ ├── commons-parent-22.pom │ ├── commons-parent-22.pom.sha1 │ └── _maven.repositories ├── clojure │ ├── clojure │ │ ├── 1.3.0 │ │ │ ├── clojure-1.3.0.jar │ │ │ ├── clojure-1.3.0.jar.sha1 │ │ │ ├── clojure-1.3.0.pom │ │ │ ├── clojure-1.3.0.pom.sha1 │ │ │ └── _maven.repositories │ │ ├── 1.4.0 │ │ │ ├── clojure-1.4.0.pom │ │ │ ├── clojure-1.4.0.pom.sha1 │ │ │ └── _maven.repositories │ │ ├── 1.5.1 │ │ │ ├── clojure-1.5.1.pom │ │ │ ├── clojure-1.5.1.pom.sha1 │ │ │ └── _maven.repositories │ │ └── 1.6.0 │ │ ├── clojure-1.6.0.jar │ │ ├── clojure-1.6.0.jar.sha1 │ │ ├── clojure-1.6.0.pom │ │ ├── clojure-1.6.0.pom.sha1 │ │ └── _maven.repositories │ ├── clojurescript │ │ └── 0.0-2197 │ │ ├── clojurescript-0.0-2197.jar │ │ ├── clojurescript-0.0-2197.jar.sha1 │ │ ├── clojurescript-0.0-2197.pom │ │ ├── clojurescript-0.0-2197.pom.sha1 │ │ └── _maven.repositories │ ├── data.json │ │ └── 0.2.3 │ │ ├── data.json-0.2.3.jar │ │ ├── data.json-0.2.3.jar.sha1 │ │ ├── data.json-0.2.3.pom │ │ ├── data.json-0.2.3.pom.sha1 │ │ └── _maven.repositories │ ├── google-closure-library │ │ └── 0.0-20140226-71326067 │ │ ├── google-closure-library-0.0-20140226-71326067.jar │ │ ├── google-closure-library-0.0-20140226-71326067.jar.sha1 │ │ ├── google-closure-library-0.0-20140226-71326067.pom │ │ ├── google-closure-library-0.0-20140226-71326067.pom.sha1 │ │ └── _maven.repositories │ ├── google-closure-library-third-party │ │ └── 0.0-20140226-71326067 │ │ ├── google-closure-library-third-party-0.0-20140226-71326067.jar │ │ ├── google-closure-library-third-party-0.0-20140226-71326067.jar.sha1 │ │ ├── google-closure-library-third-party-0.0-20140226-71326067.pom │ │ ├── google-closure-library-third-party-0.0-20140226-71326067.pom.sha1 │ │ └── _maven.repositories │ ├── pom.contrib │ │ └── 0.1.2 │ │ ├── _maven.repositories │ │ ├── pom.contrib-0.1.2.pom │ │ └── pom.contrib-0.1.2.pom.sha1 │ ├── tools.nrepl │ │ └── 0.2.6 │ │ ├── _maven.repositories │ │ ├── tools.nrepl-0.2.6.jar │ │ ├── tools.nrepl-0.2.6.jar.sha1 │ │ ├── tools.nrepl-0.2.6.pom │ │ └── tools.nrepl-0.2.6.pom.sha1 │ └── tools.reader │ └── 0.8.3 │ ├── _maven.repositories │ ├── tools.reader-0.8.3.jar │ ├── tools.reader-0.8.3.jar.sha1 │ ├── tools.reader-0.8.3.pom │ └── tools.reader-0.8.3.pom.sha1 ├── javassist │ └── javassist │ ├── 3.12.1.GA │ └── 3.18.0 ├── json │ └── json │ └── 20090211 │ ├── json-20090211.jar │ ├── json-20090211.jar.sha1 │ ├── json-20090211.pom │ ├── json-20090211.pom.sha1 │ └── _maven.repositories ├── mozilla │ └── rhino │ └── 1.7R4 │ ├── _maven.repositories │ ├── rhino-1.7R4.jar │ ├── rhino-1.7R4.jar.sha1 │ ├── rhino-1.7R4.pom │ └── rhino-1.7R4.pom.sha1 └── sonatype └── oss └── oss-parent ├── 5 │ ├── _maven.repositories │ ├── oss-parent-5.pom │ └── oss-parent-5.pom.sha1 └── 7 ├── _maven.repositories ├── oss-parent-7.pom └── oss-parent-7.pom.sha1 89 directories, 150 files
uff…
Adresář ~/.m2 je samozřejmě možné pročistit a znovu u všech projektů spustit lein deps (popř. i Maven v případě, že programátor současně vyvíjí i projekty v Javě).
Stručné shrnutí: při práci s Leiningenem se typicky používají čtyři adresáře:
- Adresář zmíněný na PATH, kde je uložen spustitelný skript lein.
- Adresář ~/.lein obsahující soubory potřebné pro běh Leiningenu.
- Adresář ~/.m2 s knihovnami vyžadovanými jednotlivými projekty.
- Adresář s projektem, který musí obsahovat především soubor project.clj.
9. Přidání nové knihovny, na níž projekt závisí
Podívejme se nyní na způsob řešení závislostí. Pokusíme se do našeho demonstračního příkladu přidat knihovnu org.clojure/data.json, kterou lze použít při zpracování dat uložených či přenášených v populárním formátu JSON. Nová knihovna se přidá do vektoru navázaného na klíč :dependencies, přičemž se nesmí zapomenout na to, že i samotná deklarace knihovny je vektor obsahující jméno a verzi – pozor tedy na správné uzávorkování (viz zvýrazněný řádek):
(defproject clojure_test_1 "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [ [org.clojure/clojure "1.6.0"] [org.clojure/data.json "0.2.5"]] :main ^:skip-aot clojure-test-1.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Upravíme i zdrojový kód projektu takovým způsobem, aby tuto knihovnu využíval. Knihovnu je nutné uvést v atributu :require (opět viz zvýrazněný řádek) s případným uvedením symbolu sloužícího jako alias k plnému názvu jmenného prostoru knihovny. To znamená, že namísto clojure.data.json/pprint se ve zdrojovém kódu může psát pouze json/pprint atd.:
(ns clojure-test-1.core (:gen-class) (:require [clojure.data.json :as json])) (defn -main "I don't do a whole lot ... yet." [& args] (let [article {:title "What's Good About Clojure?" :url "http://www.catalysoft.com/articles/goodAboutClojure.html" :last-checked (.toString (new java.util.Date))}] (json/pprint article)))
10. Automatické stažení závislé knihovny
Pokud se nyní (opět v adresáři s projektem) zadá následující příkaz…
lein deps
… je podle zpráv vypisovaných na terminál patrné, že Leiningen otevře a zpracuje soubor project.clj, načte všechny knihovny specifikované v tomto souboru, vyhodnotí, které knihovny ještě nejsou lokálně dostupné a následně tyto knihovny stáhne a uloží do správného podadresáře v ~/.m2:
Retrieving org/clojure/data.json/0.2.5/data.json-0.2.5.pom from central Retrieving org/clojure/clojure/1.4.0/clojure-1.4.0.pom from central Retrieving org/sonatype/oss/oss-parent/5/oss-parent-5.pom from central Retrieving org/clojure/data.json/0.2.5/data.json-0.2.5.jar from central
11. Otestování upraveného projektu
Nyní již máme všechny potřebné knihovny nainstalované lokálně a můžeme přistoupit ke spuštění naší demonstrační aplikace:
lein run
Z výpisu provedeného na standardní výstup je patrné, že se funkce json/pprint skutečně správně zavolala (vyhodnotila):
{"title":"What's Good About Clojure?", "url":"http:\/\/www.catalysoft.com\/articles\/goodAboutClojure.html", "last-checked":"Mon Feb 09 21:12:08 CET 2015"}
Ve druhé části článku si ukážeme další možnosti, které projekt Leiningen programátorům nabízí.
12. Odkazy na Internetu
- Leiningen: úvodní stránka
http://leiningen.org/ - Leiningen: Git repository
https://github.com/technomancy/leiningen - leiningen-win-installer
http://leiningen-win-installer.djpowell.net/ - Clojure 1: Úvod
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/ - Clojure 2: Symboly, kolekce atd.
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/ - Clojure 3: Funkcionální programování
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-3-cast-funkcionalni-programovani/ - Clojure 4: Kolekce, sekvence a lazy sekvence
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-4-cast-kolekce-sekvence-a-lazy-sekvence/ - Clojure 5: Sekvence, lazy sekvence a paralelní programy
http://www.root.cz/clanky/clojure-a-bezpecne-aplikace-pro-jvm-sekvence-lazy-sekvence-a-paralelni-programy/ - Clojure 6: Podpora pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/ - Clojure 7: Další funkce pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/ - Clojure 8: Identity, stavy, neměnné hodnoty a reference
http://www.root.cz/clanky/programovaci-jazyk-clojure-8-identity-stavy-nemenne-hodnoty-a-referencni-typy/ - Clojure 9: Validátory, pozorovatelé a kooperace s Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-9-validatory-pozorovatele-a-kooperace-mezi-clojure-a-javou/ - Clojure 10: Kooperace mezi Clojure a Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/ - Clojure 11: Generátorová notace seznamu/list comprehension
http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/ - Clojure 12: Překlad programů z Clojure do bajtkódu JVM I
http://www.root.cz/clanky/programovaci-jazyk-clojure-12-preklad-programu-z-clojure-do-bajtkodu-jvm/ - Clojure 13: Překlad programů z Clojure do bajtkódu JVM II
2) http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/ - Clojure 14: Základy práce se systémem maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/ - Clojure 15: Tvorba uživatelských maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/ - Clojure 16: Složitější uživatelská makra
http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/ - Clojure 17: Využití standardních maker v praxi
http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/ - Clojure 18: Základní techniky optimalizace aplikací
http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Clojure 19: Vývojová prostředí pro Clojure
http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/ - Clojure 20: Vývojová prostředí pro Clojure (Vimu s REPL)
http://www.root.cz/clanky/programovaci-jazyk-clojure-20-vyvojova-prostredi-pro-clojure-integrace-vimu-s-repl/ - Clojure 21: ClojureScript aneb překlad Clojure do JS
http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/