Hlavní navigace

Programovací jazyk Clojure a práce s Gitem

Pavel Tišnovský

Další užitečnou knihovnou dostupnou pro vývojáře používající programovací jazyk Clojure je knihovna clj-jgit. Jedná se o rozhraní k poměrně známé javovské knihovně JGit umožňující provádění prakticky všech operací s Gitem, a to bez nutnosti zpracování textových výstupů Gitu spouštěného z příkazové řádky.

Obsah

1. Programovací jazyk Clojure a práce s Gitem

2. Instalace knihovny clj-jgit

3. První demonstrační příklad – naklonování Git repositáře a výpis seznamu větví

4. Druhý demonstrační příklad – použití funkce load-repo pro načtení informací o Git repositáři z lokálního adresáře

5. Třetí demonstrační příklad – využití makra with-repo

6. Čtvrtý demonstrační příklad – výpis logu ve zjednodušené podobě

7. Pátý demonstrační příklad – výpis vybraných informací z logu

8. Šestý demonstrační příklad – přidání a modifikace souborů v Git repositáři, provedení commitu

9. Repositář s demonstračními příklady

10. Odkazy na předchozí části seriálu

11. Odkazy na Internetu

1. Programovací jazyk Clojure a práce s GITem

Systém Git pravděpodobně není nutné programátorům podrobně představovat, protože se v současnosti jedná o jeden z nejrozšířenějších a nejpopulárnějších distribuovaných systémů pro správu revizí (distributed revision control system). Git je možné používat z příkazové řádky, k dispozici jsou však taktéž nástroje s grafickým uživatelským rozhraním, popř. je Git součástí i několika integrovaných vývojových prostředí. V některých případech je však nutné s Gitem, resp. přesněji řečeno s gitovskými repositáři, pracovat přímo z vyvíjené aplikace (v mém konkrétním případě se jedná o systém zajišťující publikaci dosti rozsáhlých strukturovaných dokumentů na zákaznickém portálu). V případě využití programovacího jazyka Clojure je pro tento účel nejvhodnější použít knihovnu nazvanou clj-jgit. Jak již název této knihovny naznačuje, jedná se o funkcionálně pojaté rozhraní k javovské knihovně JGit (http://www.jgit.org/). V následujících kapitolách si ukážeme naprosté základy práce s touto knihovnou, složitější příklady budou uvedeny příště.

2. Instalace knihovny clj-jgit

Instalace knihovny clj-jgit je velmi jednoduchá, protože můžeme použít systém Leiningen popsaný v úvodních částech tohoto seriálu (viz desátou kapitolu s odkazy). Postačuje pouze vytvořit nový projekt příkazem:

lein new app dummyproject

Dále je nutné upravit projektový soubor project.clj takovým způsobem, aby se v něm nacházelo jméno a verze knihovny clj-jgit:

(defproject dummyproject "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"]
                   [clj-jgit "0.8.0"]]
    :main ^:skip-aot dummyproject.core
    :target-path "target/%s"
    :profiles {:uberjar {:aot :all}})

Posledním krokem je spuštění příkazu:

lein deps

Systém Leiningen by měl zajistit stažení knihovny clj-jgit i všech závislých knihoven:

Retrieving clj-jgit/clj-jgit/0.8.0/clj-jgit-0.8.0.pom from clojars
Retrieving org/eclipse/jgit/org.eclipse.jgit.java7/3.5.0.201409260305-r/org.eclipse.jgit.java7-3.5.0.201409260305-r.pom from central
Retrieving org/eclipse/jgit/org.eclipse.jgit-parent/3.5.0.201409260305-r/org.eclipse.jgit-parent-3.5.0.201409260305-r.pom from central
Retrieving org/eclipse/jgit/org.eclipse.jgit/3.5.0.201409260305-r/org.eclipse.jgit-3.5.0.201409260305-r.pom from central
Retrieving com/jcraft/jsch/0.1.50/jsch-0.1.50.pom from central
Retrieving org/sonatype/oss/oss-parent/6/oss-parent-6.pom from central
Retrieving com/googlecode/javaewah/JavaEWAH/0.7.9/JavaEWAH-0.7.9.pom from central
Retrieving org/apache/httpcomponents/httpclient/4.1.3/httpclient-4.1.3.pom from central
Retrieving org/apache/httpcomponents/httpcomponents-client/4.1.3/httpcomponents-client-4.1.3.pom from central
Retrieving org/apache/httpcomponents/project/5/project-5.pom from central
Retrieving org/apache/httpcomponents/httpcore/4.1.4/httpcore-4.1.4.pom from central
Retrieving org/apache/httpcomponents/httpcomponents-core/4.1.4/httpcomponents-core-4.1.4.pom from central
Retrieving commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.pom from central
Retrieving org/apache/commons/commons-parent/5/commons-parent-5.pom from central
Retrieving org/apache/apache/4/apache-4.pom from central
Retrieving commons-codec/commons-codec/1.4/commons-codec-1.4.pom from central
Retrieving org/apache/commons/commons-parent/11/commons-parent-11.pom from central
Retrieving org/clojure/core.memoize/0.5.3/core.memoize-0.5.3.pom from central
Retrieving org/clojure/pom.contrib/0.0.26/pom.contrib-0.0.26.pom from central
Retrieving org/clojure/core.cache/0.6.3/core.cache-0.6.3.pom from central
Retrieving org/clojure/data.priority-map/0.0.2/data.priority-map-0.0.2.pom from central
Retrieving org/clojure/pom.contrib/0.0.25/pom.contrib-0.0.25.pom from central
Retrieving org/clojure/clojure/1.3.0/clojure-1.3.0.pom from central
Retrieving fs/fs/1.3.2/fs-1.3.2.pom from clojars
Retrieving org/apache/commons/commons-compress/1.3/commons-compress-1.3.pom from central
Retrieving org/apache/commons/commons-parent/22/commons-parent-22.pom from central
Retrieving org/apache/apache/9/apache-9.pom from central
Retrieving com/jcraft/jsch/0.1.50/jsch-0.1.50.jar from central
Retrieving org/eclipse/jgit/org.eclipse.jgit.java7/3.5.0.201409260305-r/org.eclipse.jgit.java7-3.5.0.201409260305-r.jar from central
Retrieving com/googlecode/javaewah/JavaEWAH/0.7.9/JavaEWAH-0.7.9.jar from central
Retrieving org/eclipse/jgit/org.eclipse.jgit/3.5.0.201409260305-r/org.eclipse.jgit-3.5.0.201409260305-r.jar from central
Retrieving org/apache/httpcomponents/httpcore/4.1.4/httpcore-4.1.4.jar from central
Retrieving org/apache/httpcomponents/httpclient/4.1.3/httpclient-4.1.3.jar from central
Retrieving commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar from central
Retrieving org/clojure/core.memoize/0.5.3/core.memoize-0.5.3.jar from central
Retrieving org/clojure/core.cache/0.6.3/core.cache-0.6.3.jar from central
Retrieving commons-codec/commons-codec/1.4/commons-codec-1.4.jar from central
Retrieving org/clojure/data.priority-map/0.0.2/data.priority-map-0.0.2.jar from central
Retrieving org/apache/commons/commons-compress/1.3/commons-compress-1.3.jar from central
Retrieving clj-jgit/clj-jgit/0.8.0/clj-jgit-0.8.0.jar from clojars
Retrieving fs/fs/1.3.2/fs-1.3.2.jar from clojars

3. První demonstrační příklad – naklonování Git repositáře a výpis seznamu větví

V dnešním prvním demonstračním příkladu s názvem git-test1 jsou ukázány základy práce s knihovnou clj-jgit. Nejprve je vytvořena kostra příkladu, a to s využitím nám již známého příkazu:

lein new app git-test1

Po spuštění výše uvedeného příkazu by se měla vytvořit následující adresářová struktura:

├── doc
│   └── intro.md
├── LICENSE
├── project.clj
├── README.md
├── resources
├── src
│   └── git_test1
│       └── core.clj
└── test
    └── git_test1
        └── core_test.clj

Dále je nutné provést úpravu projektového souboru project.clj, a to tak, že se do sekce :dependencies přidá knihovna clj-jgit ve verzi 0.8.0. Navíc se v tomto demonstračním příkladu používá další miniknihovna se jménem clj-rm-rf. Název této knihovny napovídá, jakou funkci zde nalezneme – jedná se o funkci použitou pro smazání vybraného adresáře:

(defproject git-test1 "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"]
                   [clj-jgit "0.8.0"]
                   [clj-rm-rf "1.0.0-SNAPSHOT"]]
    :main ^:skip-aot git-test1.core
    :target-path "target/%s"
    :profiles {:uberjar {:aot :all}})

Samotný zdrojový kód demonstračního příkladu, tj. konkrétně zdrojový soubor src/git_test1/core.clj, je poměrně jednoduchý. Nejprve musíme načíst modul clj-jgit.porcelain a taktéž hozumi.rm-rf, což zajistí dvojice řádků:

(require '[clj-jgit.porcelain :as jgit])
(require '[hozumi.rm-rf :as rm-rf])

Následuje deklarace dvojice konstant, kde první konstanta obsahuje adresu Git repositáře, který se bude klonovat. Druhá konstanta pak obsahuje jméno adresáře, do něhož se Git repositář naklonuje (tento adresář se na konci demonstračního příkladu smaže):

(def repository-url
    "Adresa Git repositare vcetne specifikace protokolu."
    "https://github.com/tisnik/testrepo.git")
 
(def directory-name
    "Jmeno adresare, do ktereho se Git repositar naklonuje."
    "repo")

Následuje trojice pomocných funkcí. První funkce naklonuje Git repositář do specifikovaného adresáře s využitím volání clj-jgit.porcelain/git-clone, druhá funkce (volaná na konci příkladu) smaže adresář s naklonovaným repositářem s využitím hozumi.rm-rf/rm-r a konečně třetí funkce načte seznam všech vzdálených větví, na což je použita funkce clj-jgit.porcelain/git-branch-list. Vrácená sekvence obsahuje objekty, nikoli přímo jména větví, takže je nutné použít metodu getName (volanou v programové smyčce):

(defn clone-repository
    "Naklonovani Git repositare do specifikovaneho adresare."
    [url directory]
    (jgit/git-clone url directory))
 
(defn delete-directory
    "Smazani adresare vcetne podadresaru a souboru."
    [directory]
    (rm-rf/rm-r (java.io.File. directory)))
 
(defn list-branches
    "Vypis vsech vzdalenych vetvi."
    [repository]
    (println "Remote branch list:")
    (doseq [branch (jgit/git-branch-list repository :remote)]
        (println (.getName branch))))

Další část demonstračního příkladu je již jednoduchá, protože následující funkce clone-and-list-branches naklonuje Git repositář, zobrazí stav repositáře (ten v tomto případě musí být čistý) a následně vypíše všechny vzdálené větve:

(defn clone-and-list-branches
    "Funkce naklonuje repositar a vypise vsechny vzdalene vetve."
    [repository-url directory-name]
    (let [repository (clone-repository repository-url directory-name)]
         ; navic jeste zjistime stav repositare
         (println "Repository status: " (jgit/git-status repository))
         (list-branches repository)))

Za povšimnutí stojí použití formy try-finally zajišťující, že pracovní adresář se vždy smaže, nezávisle na tom, zda při klonování či při dalších manipulacích s repositářem dojde k vyhození výjimky:

(defn git-test-1
    "Naklonovani repositare a vypis vzdalenych vetvi."
    [repository-url directory-name]
    (try (clone-and-list-branches repository-url directory-name)
         (finally
             ; vymazani adresare s naklonovanym repositarem
             (delete-directory directory-name))))

Podívejme se nyní na úplný výpis zdrojového kódu:

(ns git-test1.core
    (:gen-class))
 
(require '[clj-jgit.porcelain :as jgit])
(require '[hozumi.rm-rf :as rm-rf])
 
(def repository-url
    "Adresa Git repositare vcetne specifikace protokolu."
    "https://github.com/tisnik/testrepo.git")
 
(def directory-name
    "Jmeno adresare, do ktereho se Git repositar naklonuje."
    "repo")
 
(defn clone-repository
    "Naklonovani Git repositare do specifikovaneho adresare."
    [url directory]
    (jgit/git-clone url directory))
 
(defn delete-directory
    "Smazani adresare vcetne podadresaru a souboru."
    [directory]
    (rm-rf/rm-r (java.io.File. directory)))
 
(defn list-branches
    "Vypis vsech vzdalenych vetvi."
    [repository]
    (println "Remote branch list:")
    (doseq [branch (jgit/git-branch-list repository :remote)]
        (println (.getName branch))))
 
(defn clone-and-list-branches
    "Funkce naklonuje repositar a vypise vsechny vzdalene vetve."
    [repository-url directory-name]
    (let [repository (clone-repository repository-url directory-name)]
         ; navic jeste zjistime stav repositare
         (println "Repository status: " (jgit/git-status repository))
         (list-branches repository)))
 
(defn git-test-1
    "Naklonovani repositare a vypis vzdalenych vetvi."
    [repository-url directory-name]
    (try (clone-and-list-branches repository-url directory-name)
         (finally
             ; vymazani adresare s naklonovanym repositarem
             (delete-directory directory-name))))
 
(defn -main
    "Funkce zavolana po zadani prikazu 'lein run'."
    [& args]
    (git-test-1 repository-url directory-name))

Po spuštění příkladu by se na standardní výstup měly vypsat tyto řádky:

Repository status:  {:untracked #{}, :removed #{}, :modified #{}, :missing #{}, :changed #{}, :added #{}}
Remote branch list:
refs/remotes/origin/branch-1
refs/remotes/origin/branch-2
refs/remotes/origin/master

4. Druhý demonstrační příklad – použití funkce load-repo pro načtení informací o Git repositáři z lokálního adresáře

V dnešním druhém demonstračním příkladu si ukážeme použití funkce nazvané load-repo pro načtení informací o Git repositáři, který již byl naklonován dříve (nebo se může jednat o lokální repositář). Opět si nejprve vytvoříme kostru projektu:

lein new app git-test2

Úprava projektového souboru project.clj je naprosto stejná, jako tomu bylo v prvním demonstračním příkladu:

(defproject git-test2 "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"]
                   [clj-jgit "0.8.0"]
                   [clj-rm-rf "1.0.0-SNAPSHOT"]]
    :main ^:skip-aot git-test2.core
    :target-path "target/%s"
    :profiles {:uberjar {:aot :all}})

I ve druhém demonstračním příkladu dojde k naklonování repositáře a následně k výpisu informace o jeho stavu i seznamu vzdálených větví. Zatímco však v prvním příkladu jsme si pamatovali hodnotu vrácenou funkcí clj-jgit.porcelain/git-clone, ve druhém příkladu tuto hodnotu „zapomeneme“ (nikam se neuloží). Namísto toho je použita funkce clj-jgit.porcelain/load-repo, které se předá adresář, v němž je klon repositáře. Tuto funkci tedy použijeme vždy ve chvíli, kdy existuje jeho lokální kopie, nezávisle na tom, v jakém je tato kopie stavu:

(defn git-test-2
    "Naklonovani repositare, nacteni informaci
     z vytvoreneho adresare a vypis vzdalenych vetvi."
    [repository-url directory-name]
    ; naklonovani repositare do specifikovaneho adresare
    (clone-repository repository-url directory-name)
    ; nacteni informaci o repositari z lokalniho adresare
    (try (-> (jgit/load-repo directory-name)
             list-branches)
         (finally
             ; vymazani adresare s naklonovanym repositarem
             (delete-directory directory-name))))

Úplný zdrojový kód souboru src/git_test2/core.clj:

(ns git-test2.core
    (:gen-class))
 
(require '[clj-jgit.porcelain :as jgit])
(require '[hozumi.rm-rf :as rm-rf])
 
(def repository-url
    "Adresa Git repositare vcetne specifikace protokolu."
    "https://github.com/tisnik/testrepo.git")
 
(def directory-name
    "Jmeno adresare, do ktereho se Git repositar naklonuje."
    "repo")
 
(defn clone-repository
    "Naklonovani Git repositare do specifikovaneho adresare."
    [url directory]
    (jgit/git-clone url directory))
 
(defn delete-directory
    "Smazani adresare vcetne podadresaru a souboru."
    [directory]
    (rm-rf/rm-r (java.io.File. directory)))
 
(defn list-branches
    "Vypis vsech vzdalenych vetvi."
    [repository]
    (println "Remote branch list:")
    (doseq [branch (jgit/git-branch-list repository :remote)]
        (println (.getName branch))))
 
(defn git-test-2
    "Naklonovani repositare, nacteni informaci
     z vytvoreneho adresare a vypis vzdalenych vetvi."
    [repository-url directory-name]
    ; naklonovani repositare do specifikovaneho adresare
    (clone-repository repository-url directory-name)
    ; nacteni informaci o repositari z lokalniho adresare
    (try (-> (jgit/load-repo directory-name)
             list-branches)
         (finally
             ; vymazani adresare s naklonovanym repositarem
             (delete-directory directory-name))))
 
(defn -main
    "Funkce zavolana po zadani prikazu 'lein run'."
    [& args]
    (git-test-2 repository-url directory-name))

Po spuštění příkladu by se na standardní výstup měly vypsat tyto řádky:

Repository status:  {:untracked #{}, :removed #{}, :modified #{}, :missing #{}, :changed #{}, :added #{}}
Remote branch list:
refs/remotes/origin/branch-1
refs/remotes/origin/branch-2
refs/remotes/origin/master

5. Třetí demonstrační příklad – využití makra with-repo

Třetí demonstrační příklad, který si dnes ukážeme, vysvětluje použití makra with-repo. S makry začínajícími prefixem with- se můžeme v knihovnách programovacího jazyka Clojure setkat poměrně často, protože se používají ve chvíli, kdy je zapotřebí pracovat s nějakým zdrojem (soubor, síťové připojení, standardní výstup přesměrovaný do řetězce), jenž se musí po dokončení práce nějakým způsobem „uzavřít“ či „finalizovat“. Všechny funkce volané uvnitř těchto maker mohou pracovat se specifikovaným zdrojem a nemusí se starat o jeho uvolnění. Makro with-repo není žádnou výjimkou – používá se ve chvíli, kdy se načte informace o repositáři a uloží se do implicitně nazvané lokální proměnné repo. Práce s touto proměnnou je ve skutečnosti velmi snadná, o čemž se lze snadno přesvědčit:

(defn git-test-3
    "Naklonovani repositare, nacteni informaci
     z vytvoreneho adresare a vypis vzdalenych vetvi."
    [repository-url directory-name]
    ; naklonovani repositare do specifikovaneho adresare
    (clone-repository repository-url directory-name)
    ; nacteni informaci o repositari z lokalniho adresare
    ; povsimnete si pouziti "automagicky" vytvorene promenne,
    ; ktera se jmenuje 'repo'
    (try (jgit/with-repo directory-name
                         (list-branches repo)
                         ; libovolné množství funkcí používajících proměnnou repo
         )
         (finally
             ; vymazani adresare s naklonovanym repositarem
             (delete-directory directory-name))))

Opět si nejprve vytvoříme kostru projektu:

lein new app git-test3

Úprava projektového souboru project.clj je naprosto stejná, jako tomu bylo v prvním i ve druhém demonstračním příkladu:

(defproject git-test3 "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"]
                   [clj-jgit "0.8.0"]
                   [clj-rm-rf "1.0.0-SNAPSHOT"]]
    :main ^:skip-aot git-test3.core
    :target-path "target/%s"
    :profiles {:uberjar {:aot :all}})

Zdrojový kód souboru src/git_test3/core.clj:

(ns git-test3.core
    (:gen-class))
 
(require '[clj-jgit.porcelain :as jgit])
(require '[hozumi.rm-rf :as rm-rf])
 
(def repository-url
    "Adresa Git repositare vcetne specifikace protokolu."
    "https://github.com/tisnik/testrepo.git")
 
(def directory-name
    "Jmeno adresare, do ktereho se Git repositar naklonuje."
    "repo")
 
(defn clone-repository
    "Naklonovani Git repositare do specifikovaneho adresare."
    [url directory]
    (jgit/git-clone url directory))
 
(defn delete-directory
    "Smazani adresare vcetne podadresaru a souboru."
    [directory]
    (rm-rf/rm-r (java.io.File. directory)))
 
(defn list-branches
    "Vypis vsech vzdalenych vetvi."
    [repository]
    (println "Remote branch list:")
    (doseq [branch (jgit/git-branch-list repository :remote)]
        (println (.getName branch))))
 
(defn git-test-3
    "Naklonovani repositare, nacteni informaci
     z vytvoreneho adresare a vypis vzdalenych vetvi."
    [repository-url directory-name]
    ; naklonovani repositare do specifikovaneho adresare
    (clone-repository repository-url directory-name)
    ; nacteni informaci o repositari z lokalniho adresare
    ; povsimnete si pouziti "automagicky" vytvorene promenne,
    ; ktera se jmenuje 'repo'
    (try (jgit/with-repo directory-name
                         (list-branches repo))
         (finally
             ; vymazani adresare s naklonovanym repositarem
             (delete-directory directory-name))))
 
(defn -main
    "Funkce zavolana po zadani prikazu 'lein run'."
    [& args]
    (git-test-3 repository-url directory-name))

Po spuštění příkladu by se na standardní výstup měly opět vypsat stejné řádky:

Repository status:  {:untracked #{}, :removed #{}, :modified #{}, :missing #{}, :changed #{}, :added #{}}
Remote branch list:
refs/remotes/origin/branch-1
refs/remotes/origin/branch-2
refs/remotes/origin/master

6. Čtvrtý demonstrační příklad – výpis logu ve zjednodušené podobě

Dnešní čtvrtý demonstrační příklad se již odlišuje od předchozích třech příkladů, protože se v něm bude pracovat s logy (resp. zjednodušeně řečeno se zprávami o jednotlivých commitech). Vytvoření kostry příkladu je snadné:

lein new app git-test4

Úprava projektového souboru project.clj je stále stejná:

(defproject git-test4 "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"]
                   [clj-jgit "0.8.0"]
                   [clj-rm-rf "1.0.0-SNAPSHOT"]]
    :main ^:skip-aot git-test4.core
    :target-path "target/%s"
    :profiles {:uberjar {:aot :all}})

Základní kostra tohoto příkladu je prakticky shodná s příkladem předchozím, ovšem volá se odlišná funkce nazvaná print-simple-log, která je zde zvýrazněna tučným písmem:

(defn git-test-4
    "Naklonovani repositare, nacteni informaci
     z vytvoreneho adresare a vypis logu."
    [repository-url directory-name]
    ; naklonovani repositare do specifikovaneho adresare
    (clone-repository repository-url directory-name)
    ; nacteni informaci o repositari z lokalniho adresare
    ; povsimnete si pouziti "automagicky" vytvorene promenne,
    ; ktera se jmenuje 'repo'
    (try (jgit/with-repo directory-name
                         (print-simple-log repo))
         (finally
             ; vymazani adresare s naklonovanym repositarem
             (delete-directory directory-name))))

Ve funkci print-simple-log je volání clj-jgit.porcelain/git-log vracející informace z logu. Pro převod na čitelné informace o commitech je nutné (uvnitř smyčky) zavolat funkci clj-jgit.querying/commit-info vracející pro každý log speciální javovský objekt typu RevCommit a další informace uložené do mapy:

(defn print-simple-log
    "Vypis logu ve zjednodusenem formatu."
    [repository]
    (doseq [log-entry (jgit/git-log repository)]
        (println (jgit-query/commit-info repository log-entry))))

Po spuštění příkladu by se na standardní výstup měly vypsat tyto (poměrně nečitelné) řádky:

{:email ptisnovs@redhat.com, :raw #<RevCommit commit 394ce42cb3bcf44ff4e9a94949814bacddcdfe9b 1434726521 ----sp>, :time #inst "2015-06-19T15:08:41.000-00:00", :branches (refs/heads/master), :changed_files ([garbage :add]), :merge false, :author Pavel Tisnovsky, :id 394ce42cb3bcf44ff4e9a94949814bacddcdfe9b, :repo #<Git Git[Repository[repo/.git]]>, :message Added garbage}
{:email ptisnovs@redhat.com, :raw #<RevCommit commit 0fd398ab16e53ea0b783aef2413d75b75c6462cd 1434723899 ----sp>, :time #inst "2015-06-19T14:24:59.000-00:00", :branches (refs/heads/master), :changed_files ([README.md :edit]), :merge false, :author Pavel Tisnovsky, :id 0fd398ab16e53ea0b783aef2413d75b75c6462cd, :repo #<Git Git[Repository[repo/.git]]>, :message Updated README.md}
{:email ptisnovs@redhat.com, :raw #<RevCommit commit badf2b12f9281a8581009bfa068a5147c4cbc87a 1434722046 ----sp>, :time #inst "2015-06-19T13:54:06.000-00:00", :branches (refs/heads/master), :changed_files [[README.md :add]], :merge false, :author Pavel Tišnovský, :id badf2b12f9281a8581009bfa068a5147c4cbc87a, :repo #<Git Git[Repository[repo/.git]]>, :message Initial commit}

Zdrojový kód souboru src/git_test4/core.clj:

(ns git-test4.core
    (:gen-class))
 
(require '[clj-jgit.porcelain :as jgit])
(require '[clj-jgit.querying  :as jgit-query])
(require '[hozumi.rm-rf :as rm-rf])
 
(def repository-url
    "Adresa Git repositare vcetne specifikace protokolu."
    "https://github.com/tisnik/testrepo.git")
 
(def directory-name
    "Jmeno adresare, do ktereho se Git repositar naklonuje."
    "repo")
 
(defn clone-repository
    "Naklonovani Git repositare do specifikovaneho adresare."
    [url directory]
    (jgit/git-clone url directory))
 
(defn delete-directory
    "Smazani adresare vcetne podadresaru a souboru."
    [directory]
    (rm-rf/rm-r (java.io.File. directory)))
 
(defn print-simple-log
    "Vypis logu ve zjednodusenem formatu."
    [repository]
    (doseq [log-entry (jgit/git-log repository)]
        (println (jgit-query/commit-info repository log-entry))))
 
(defn git-test-4
    "Naklonovani repositare, nacteni informaci
     z vytvoreneho adresare a vypis logu."
    [repository-url directory-name]
    ; naklonovani repositare do specifikovaneho adresare
    (clone-repository repository-url directory-name)
    ; nacteni informaci o repositari z lokalniho adresare
    ; povsimnete si pouziti "automagicky" vytvorene promenne,
    ; ktera se jmenuje 'repo'
    (try (jgit/with-repo directory-name
                         (print-simple-log repo))
         (finally
             ; vymazani adresare s naklonovanym repositarem
             (delete-directory directory-name))))
 
(defn -main
    "Funkce zavolana po zadani prikazu 'lein run'."
    [& args]
    (git-test-4 repository-url directory-name))

7. Pátý demonstrační příklad – výpis vybraných informací z logu

Informace z logu, které byly vypsány v rámci předchozího příkladu byly poměrně nečitelné, ovšem ve skutečnosti je relativně snadné z vrácené sekvence objektů získat pouze potřebné informace. Jak se to dělá, si ukážeme v předposledním demonstračním příkladu. Vytvoření kostry příkladu je stále stejné:

lein new app git-test5

Úprava projektového souboru project.clj taktéž nepřináší žádné nové změny:

(defproject git-test5 "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"]
                   [clj-jgit "0.8.0"]
                   [clj-rm-rf "1.0.0-SNAPSHOT"]]
    :main ^:skip-aot git-test5.core
    :target-path "target/%s"
    :profiles {:uberjar {:aot :all}})

Funkce print-simple-log z předchozího příkladu pouze bez dalších úprav převáděla obsah (atributy) datových struktur vracených funkcí commit-info na řetězec, který byl ihned poté vypsán na standardní výstup:

(defn print-simple-log
    "Vypis logu ve zjednodusenem formatu."
    [repository]
    (doseq [log-entry (jgit/git-log repository)]
        (println (jgit-query/commit-info repository log-entry))))

Pro vylepšení vypisovaných výsledků o commitech však můžeme výsledek funkce commit-info uložit do lokální proměnné a následně získat a vypsat pouze vybrané atributy. Vzhledem k tomu, že je vrácena mapa, je získání atributů snadné, a to buď funkcí get nebo ještě jednodušeji zápisem (:klíč mapa):

(defn print-customized-log
    "Vypis logovacich informaci ve zvolenem formatu."
    [repository]
    (doseq [log-entry (jgit/git-log repository)]
        (let [info (jgit-query/commit-info repository log-entry)]
             (println (:author info) ":" (:message info)))))

Informace vypsané funkcí print-customized-log jsou již bez problémů čitelné:

Pavel Tisnovsky : Added garbage
Pavel Tisnovsky : Updated README.md
Pavel Tišnovský : Initial commit

Podívejme se nyní na úplný zdrojový kód souboru src/git_test5/core.clj:

(ns git-test5.core
    (:gen-class))
 
(require '[clj-jgit.porcelain :as jgit])
(require '[clj-jgit.querying  :as jgit-query])
(require '[hozumi.rm-rf :as rm-rf])
 
(def repository-url
    "Adresa Git repositare vcetne specifikace protokolu."
    "https://github.com/tisnik/testrepo.git")
 
(def directory-name
    "Jmeno adresare, do ktereho se Git repositar naklonuje."
    "repo")
 
(defn clone-repository
    "Naklonovani Git repositare do specifikovaneho adresare."
    [url directory]
    (jgit/git-clone url directory))
 
(defn delete-directory
    "Smazani adresare vcetne podadresaru a souboru."
    [directory]
    (rm-rf/rm-r (java.io.File. directory)))
 
(defn print-customized-log
    "Vypis logovacich informaci ve zvolenem formatu."
    [repository]
    (doseq [log-entry (jgit/git-log repository)]
        (let [info (jgit-query/commit-info repository log-entry)]
             (println (:author info) ":" (:message info)))))
 
(defn git-test-5
    "Naklonovani repositare, nacteni informaci
     z vytvoreneho adresare a vypis podrobnejsiho logu."
    [repository-url directory-name]
    ; naklonovani repositare do specifikovaneho adresare
    (clone-repository repository-url directory-name)
    ; nacteni informaci o repositari z lokalniho adresare
    ; povsimnete si pouziti "automagicky" vytvorene promenne,
    ; ktera se jmenuje 'repo'
    (try (jgit/with-repo directory-name
                         (print-customized-log repo))
         (finally
             ; vymazani adresare s naklonovanym repositarem
             (delete-directory directory-name))))
 
(defn -main
    "Funkce zavolana po zadani prikazu 'lein run'."
    [& args]
    (git-test-5 repository-url directory-name))

8. Šestý demonstrační příklad – přidání a modifikace souborů v GIT repositáři, provedení commitu

Dnešní šestý a současně i poslední demonstrační příklad nazvaný git-test6 bude již zajímavější, než příklady předchozí. Ukážeme si totiž přidávání a modifikaci souborů v repositáři, provádění commitů a taktéž vliv těchto operací na stav repositáře. Opět si tedy vytvořme kostru příkladu:

lein new app git-test6

Úprava projektového souboru project.clj je stále stejná a spočívá v přidání dvou nových knihoven:

(defproject git-test6 "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"]
                   [clj-jgit "0.8.0"]
                   [clj-rm-rf "1.0.0-SNAPSHOT"]]
    :main ^:skip-aot git-test6.core
    :target-path "target/%s"
    :profiles {:uberjar {:aot :all}})

V hlavní části programu se používají tyto funkce a makra:

Funkce či makro Význam
clj-jgit.porcelain/git-clone naklonování repositáře (již známe)
clj-jgit.porcelain/with-repo blok, v němž se pracuje se specifikovaným repositářem
clj-jgit.porcelain/git-add přidání souboru či změny do stage area
clj-jgit.porcelain/git-commit provedení commitu (ze stage area do lokálního repa)
clj-jgit.porcelain/git-status získání stavu repositáře

Stav repositáře má podobu mapy se šesticí prvků s klíči :untracked, :removed, :modified, :missing, :changed a :added. Hodnotami prvků jsou množiny (set) souborů.

Hlavní část demonstračního programu, kde se provádí změny v repositáři:

(defn git-test-6
    "Naklonovani repositare a pridani noveho souboru."
    [repository-url directory-name]
    ; naklonovani repositare do specifikovaneho adresare
    (clone-repository repository-url directory-name)
    ; budeme pracova s repositarem, ktery je v nasledujicim bloku
    ; predstavovan symbolem 'repo'
    (jgit/with-repo directory-name
         ; stav repa na zacatku
         (println "Repository status: " (jgit/git-status repo))
 
         ; vytvoreni noveho souboru
         (spit (str directory-name "/answer.txt") "*42*")
         ; modifikace stavajiciho souboru
         (spit (str directory-name "/README.md") "new text")
         ; novy stav repa
         (println "Repository status: " (jgit/git-status repo))
 
         ; pridani zmen do stage area
         (jgit/git-add repo "answer.txt")
         (jgit/git-add repo "README.md")
         ; novy stav repa
         (println "Repository status: " (jgit/git-status repo))
 
         ; provedeme commit vsech zmen
         (jgit/git-commit repo "The Answer to the Ultimate Question of Life, the Universe, and Everything")
         ; konecny stav repa
         (println "Repository status: " (jgit/git-status repo))
    )
    (delete-directory directory-name))

Po spuštění by se měla na standardní výstup vypsat pětice stavů repositáře:

Repository status:  {:untracked #{}, :removed #{}, :modified #{}, :missing #{}, :changed #{}, :added #{}}
Repository status:  {:untracked #{answer.txt}, :removed #{}, :modified #{README.md}, :missing #{}, :changed #{}, :added #{}}
Repository status:  {:untracked #{}, :removed #{}, :modified #{}, :missing #{}, :changed #{README.md}, :added #{answer.txt}}
Repository status:  {:untracked #{}, :removed #{}, :modified #{}, :missing #{}, :changed #{}, :added #{}}

Význam jednotlivých řádků:

  1. Na začátku (ihned po naklonování) je repositář ve stavu clean, což je logické
  2. Po vytvoření souboru answer.txt (ten v repu neexistoval) je tento soubor ve stavu untracked
  3. Po modifikaci souboru README.md (ten již v repu existoval) je tento soubor ve stavu modified
  4. (jgit/git-add repo „answer.txt“) zajistí změnu stavu z untracked na added
  5. (jgit/git-add repo „README.md“) zajistí změnu stavu z modified na changed
  6. Po (jgit/git-commit repo zpráva) se repositář opět ocitne ve stavu clean

Zdrojový kód souboru src/git_test6/core.clj:

(ns git-test6.core
    (:gen-class))
 
(require '[clj-jgit.porcelain :as jgit])
(require '[hozumi.rm-rf       :as rm-rf])
 
(def repository-url
    "Adresa Git repositare vcetne specifikace protokolu."
    "https://github.com/tisnik/testrepo.git")
 
(def directory-name
    "Jmeno adresare, do ktereho se Git repositar naklonuje."
    "repo")
 
(defn delete-directory
    "Smazani adresare vcetne podadresaru a souboru."
    [directory]
    (rm-rf/rm-r (java.io.File. directory)))
 
(defn clone-repository
    "Naklonovani Git repositare do specifikovaneho adresare."
    [url directory]
    (jgit/git-clone url directory))
 
(defn git-test-6
    "Naklonovani repositare a pridani noveho souboru."
    [repository-url directory-name]
    ; naklonovani repositare do specifikovaneho adresare
    (clone-repository repository-url directory-name)
    ; budeme pracova s repositarem, ktery je v nasledujicim bloku
    ; predstavovan symbolem 'repo'
    (jgit/with-repo directory-name
         ; stav repa na zacatku
         (println "Repository status: " (jgit/git-status repo))
 
         ; vytvoreni noveho souboru
         (spit (str directory-name "/answer.txt") "*42*")
         ; modifikace stavajiciho souboru
         (spit (str directory-name "/README.md") "new text")
         ; novy stav repa
         (println "Repository status: " (jgit/git-status repo))
 
         ; pridani zmen do stage area
         (jgit/git-add repo "answer.txt")
         (jgit/git-add repo "README.md")
         ; novy stav repa
         (println "Repository status: " (jgit/git-status repo))
 
         ; provedeme commit vsech zmen
         (jgit/git-commit repo "The Answer to the Ultimate Question of Life, the Universe, and Everything")
         ; konecny stav repa
         (println "Repository status: " (jgit/git-status repo))
    )
    (delete-directory directory-name))
 
(defn -main
    "Funkce zavolana po zadani prikazu 'lein run'."
    [& args]
    (git-test-6 repository-url directory-name))

9. Repositář s demonstračními příklady

Všech šest dnes popsaných demonstračních příkladů bylo, podobně jako v předchozích částech tohoto seriálu, uloženo do Git repositáře dostupného na adrese https://github.com/tisnik/clojure-examples. V tabulce zobrazené pod tímto odstavcem naleznete na zdrojové kódy jednotlivých příkladů přímé odkazy:

Naklonování celého repositáře zajistí příkaz:

git clone http://github.com/tisnik/clojure-examples.git
Cloning into 'clojure-examples'...
remote: Counting objects: 638, done.
remote: Compressing objects: 100% (48/48), done.
Receiving objects: 100% (638/638), 101.89 KiB | 141.00 KiB/s, done.
remote: Total 638 (delta 30), reused 0 (delta 0), pack-reused 560
Resolving deltas: 100% (248/248), done.
Checking connectivity... done.

10. Odkazy na předchozí části seriálu

Stalo se již zvykem uvést odkazy na všechny předchozí části tohoto seriálu. Tento zvyk samozřejmě dodržíme i dnes:

  1. Leiningen: nástroj pro správu projektů napsaných v Clojure
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/
  2. Leiningen: nástroj pro správu projektů napsaných v Clojure (2)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-2/
  3. Leiningen: nástroj pro správu projektů napsaných v Clojure (3)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-3/
  4. Leiningen: nástroj pro správu projektů napsaných v Clojure (4)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-4/
  5. Leiningen: nástroj pro správu projektů napsaných v Clojure (5)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-5/
  6. Leiningen: nástroj pro správu projektů napsaných v Clojure (6)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-6/
  7. Programovací jazyk Clojure a databáze (1.část)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/
  8. Pluginy pro Leiningen
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/
  9. Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/
  10. Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/
  11. Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk
    http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk/
  12. Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (2)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-2/
  13. Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (dokončení)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-dokonceni/
  14. Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
    http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/
  15. Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (2)
    http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-2/
  16. Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (3)
    http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-3/

11. Odkazy na Internetu

  1. Seriál o Gitu: 1. díl – Git – Historie a principy
    http://www.itnetwork.cz/git-tutorial-historie-a-principy
  2. 2. díl – Git – Instalace a vytvoření repositáře
    http://www.itnetwork.cz/git-tutorial-instalace-a-stazeni-repositare
  3. 3. díl – Git – Základy
    http://www.itnetwork.cz/git-tutorial-zaklady
  4. 4. díl – Git – Zkoumání historie
    http://www.itnetwork.cz/git-tutorial-historie
  5. 5. díl – Git – Rozděluj a panuj
    http://www.itnetwork.cz/git-tutorial-vetve
  6. 6. díl – Git – práce se vzdáleným repositářem
    http://www.itnetwork.cz/git-prace-se-vzdalenym-repositarem
  7. Building User Interfaces with Seesaw (slajdy k přednášce)
    http://darevay.com/talks/clo­jurewest2012/#/title-slide
  8. Seesaw na GitHubu
    https://github.com/daveray/seesaw
  9. Seesaw API Documentation
    http://daveray.github.io/seesaw/
  10. Seesaw wiki
    https://github.com/davera­y/seesaw/wiki
  11. seesaw-repl-tutorial.clj
    https://gist.github.com/da­veray/1441520
  12. Témata o Seesaw na Google groups
    https://groups.google.com/fo­rum/#!forum/seesaw-clj
  13. Threading macro (dokumentace k jazyku Clojure)
    https://clojure.github.io/clo­jure/clojure.core-api.html#clojure.core/->
  14. Understanding the Clojure → macro
    http://blog.fogus.me/2009/09/04/un­derstanding-the-clojure-macro/
  15. Clisk
    https://github.com/mikera/clisk
  16. clojars: net.mikera/clisk
    https://clojars.org/net.mikera/clisk
  17. clojure.inspector
    http://clojure.github.io/clo­jure/clojure.inspector-api.html
  18. Clisk: wiki
    https://github.com/mikera/clisk/wiki
  19. Dokumentace vygenerovaná pro knihovnu core.matrix
    https://cloojure.github.i­o/doc/core.matrix/index.html
  20. Size and Dimensionality
    https://groups.google.com/fo­rum/#!topic/numerical-clojure/zebBCa68eTw/discussion
  21. Towards core.matrix for Clojure?
    https://clojurefun.wordpres­s.com/2013/01/05/towards-core-matrix-for-clojure/
  22. The Clojure Toolbox
    http://www.clojure-toolbox.com/
  23. Neanderthal
    http://neanderthal.uncomplicate.org/
  24. Hello world project
    https://github.com/uncompli­cate/neanderthal/blob/mas­ter/examples/hello-world/project.clj
  25. vectorz-clj
    https://github.com/mikera/vectorz-clj
  26. vectorz – Examples
    https://github.com/mikera/vectorz-clj/wiki/Examples
  27. gloss
    https://github.com/ztellman/gloss
  28. HTTP client/server for Clojure
    http://www.http-kit.org/
  29. Array Programming
    https://en.wikipedia.org/wi­ki/Array_programming
  30. Discovering Array Languages
    http://archive.vector.org­.uk/art10008110
  31. no stinking loops – Kalothi
    http://www.nsl.com/
  32. Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
    http://www.vector.org.uk/
  33. APL Interpreters
    http://www.vector.org.uk/?a­rea=interpreters
  34. APL_(programming_language
    http://en.wikipedia.org/wi­ki/APL_(programming_langu­age
  35. APL FAQ
    http://www.faqs.org/faqs/apl-faq/
  36. APL FAQ (nejnovější verze)
    http://home.earthlink.net/~swsir­lin/apl.faq.html
  37. A+
    http://www.aplusdev.org/
  38. APLX
    http://www.microapl.co.uk/
  39. FreeAPL
    http://www.pyr.fi/apl/index.htm
  40. J: a modern, high-level, general-purpose, high-performance programming language
    http://www.jsoftware.com/
  41. K, Kdb: an APL derivative for Solaris, Linux, Windows
    http://www.kx.com
  42. openAPL (GPL)
    http://sourceforge.net/pro­jects/openapl
  43. Parrot APL (GPL)
    http://www.parrotcode.org/
  44. Learning J (Roger Stokes)
    http://www.jsoftware.com/hel­p/learning/contents.htm
  45. Rosetta Code
    http://rosettacode.org/wiki/Main_Page
  46. Why APL
    http://www.acm.org/sigapl/whyapl.htm
  47. java.jdbc API Reference
    https://clojure.github.io/java.jdbc/
  48. Hiccup
    https://github.com/weavejester/hiccup
  49. Clojure Ring na GitHubu
    https://github.com/ring-clojure/ring
  50. A brief overview of the Clojure web stack
    https://brehaut.net/blog/2011/rin­g_introduction
  51. Getting Started with Ring
    http://www.learningclojure­.com/2013/01/getting-started-with-ring.html
  52. Getting Started with Ring and Compojure – Clojure Web Programming
    http://www.myclojureadven­ture.com/2011/03/getting-started-with-ring-and-compojure.html
  53. Unit Testing in Clojure
    http://nakkaya.com/2009/11/18/unit-testing-in-clojure/
  54. Testing in Clojure (Part-1: Unit testing)
    http://blog.knoldus.com/2014/03/22/tes­ting-in-clojure-part-1-unit-testing/
  55. API for clojure.test – Clojure v1.6 (stable)
    https://clojure.github.io/clo­jure/clojure.test-api.html
  56. Leiningen: úvodní stránka
    http://leiningen.org/
  57. Leiningen: Git repository
    https://github.com/techno­mancy/leiningen
  58. leiningen-win-installer
    http://leiningen-win-installer.djpowell.net/
  59. Clojure 1: Úvod
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/
  60. Clojure 2: Symboly, kolekce atd.
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/
  61. 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/
  62. 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/
  63. 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/
  64. Clojure 6: Podpora pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/
  65. Clojure 7: Další funkce pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/
  66. 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/
  67. 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/
  68. Clojure 10: Kooperace mezi Clojure a Javou
    http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/
  69. Clojure 11: Generátorová notace seznamu/list comprehension
    http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/
  70. 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/
  71. Clojure 13: Překlad programů z Clojure do bajtkódu JVM II:
    http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/
  72. Clojure 14: Základy práce se systémem maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/
  73. Clojure 15: Tvorba uživatelských maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/
  74. Clojure 16: Složitější uživatelská makra
    http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/
  75. Clojure 17: Využití standardních maker v praxi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/
  76. Clojure 18: Základní techniky optimalizace aplikací
    http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/
  77. Clojure 19: Vývojová prostředí pro Clojure
    http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/
  78. 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/
  79. Clojure 21: ClojureScript aneb překlad Clojure do JS
    http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/
Našli jste v článku chybu?
Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

Lupa.cz: Teletext je „internetem hipsterů“

Teletext je „internetem hipsterů“

Vitalia.cz: 9 největších mýtů o mase

9 největších mýtů o mase

DigiZone.cz: „Black Friday 2016“: závěrečné zhodnocení

„Black Friday 2016“: závěrečné zhodnocení

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Vitalia.cz: Paštiky plné masa ho zatím neuživí

Paštiky plné masa ho zatím neuživí

Měšec.cz: Air Bank zruší TOP3 garanci a zdražuje kurzy

Air Bank zruší TOP3 garanci a zdražuje kurzy

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

Vitalia.cz: Spor o mortadelu: podle Lidlu falšovaná nebyla

Spor o mortadelu: podle Lidlu falšovaná nebyla

Vitalia.cz: Proč vás každý zubař posílá na dentální hygienu

Proč vás každý zubař posílá na dentální hygienu

Podnikatel.cz: Zavře krám u #EET Malá pokladna a Teeta?

Zavře krám u #EET Malá pokladna a Teeta?

Vitalia.cz: „Připluly“ z Německa a možná obsahují jed

„Připluly“ z Německa a možná obsahují jed

Měšec.cz: U levneELEKTRO.cz už reklamaci nevyřídíte

U levneELEKTRO.cz už reklamaci nevyřídíte

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

Podnikatel.cz: Podnikatelům dorazí varování od BSA

Podnikatelům dorazí varování od BSA

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

120na80.cz: Na ucho teplý, nebo studený obklad?

Na ucho teplý, nebo studený obklad?

Podnikatel.cz: Udávání kvůli EET začalo

Udávání kvůli EET začalo

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?

Vitalia.cz: Mondelez stahuje rizikovou čokoládu Milka

Mondelez stahuje rizikovou čokoládu Milka