Obsah
1. Enlive – výkonný šablonovací systém pro jazyk Clojure
3. Přístup použitý v knihovně Enlive
4. První demonstrační příklad: aplikace jednoduché šablony
6. Druhý demonstrační příklad: výběr tagů na základě jejich třídy a ID
7. Snippety použitelné pro výpis sekvencí do HTML stránky
8. Třetí demonstrační příklad: použití snippetu pro výpis seznamu, explicitní selektory
9. Repositář s dnešními demonstračními příklady
10. Odkazy na předchozí části tohoto seriálu
1. Enlive – výkonný šablonovací systém pro jazyk Clojure
Při popisu tvorby serverových aplikací s využitím programovacího jazyka Clojure jsme se seznámili s dvojicí důležitých a v mnoha projektech i užitečných knihoven. První knihovna se jmenuje Clojure Ring a jejím hlavním úkolem je zajistit čtení a zpracování požadavků přicházejících od klienta a následně odeslat odpověď serveru zpět klientovi. Díky jasně vymezenému úkolu (od requestu k response), který má tato knihovna zajišťovat, bylo možné provést její návrh čistě funkcionálně a bez nutnosti návrhu a implementace složitého a rozsáhlého API, o čemž jsme se ostatně mohli přesvědčit na několika demonstračních příkladech. Serverové aplikace, které mají nějakým způsobem komunikovat s webovým prohlížečem na straně klienta, však musí dokázat dynamicky generovat HTML stránky (popř. poskytovat data pro tyto stránky, například ve formátu JSON). V tomto případě si již s možnostmi nabízenými knihovnou Clojure Ring nevystačíme, což je korektní, protože generování obsahu vlastně nemá nic společného se zpracováním požadavků a odpovídáním na ně (Clojure Ring se nesnaží o napodobení některých monstrózních webových frameworků).
Pro dynamické generování HTML stránek na straně serveru v programovacím jazyce Clojure lze využít hned několik knihoven, které se od sebe odlišují způsobem, jakým je „předepsána“ výsledná podoba stránky. Jedna z možností spočívá ve využití připravených šablon HTML stránek, do nichž se pouze na určená místa doplňují dynamicky generovaná data. Jedná se pravděpodobně o nejpoužívanější postup, který byl nejprve implementován v PHP a později se rozšířil i do dalších programovacích jazyků a jejich frameworků (JSP atd. atd.). Použití šablon HTML stránek samozřejmě přináší mnohé výhody, například možnost oddělení práce designera stránek od programátora, ovšem ve skutečnosti existuje ještě další způsob, který je podporován v knihovně s názvem Hiccup. Tato knihovna totiž obsahuje několik funkcí, které na svém vstupu dostanou běžný vektor či seznam jazyka Clojure a na základě dat uložených v tomto vektoru/listu vytvoří korektní podobu HTML stránky. Na první pohled sice tento postup může vypadat složitě, ve skutečnosti je však v mnoha případech velmi efektivní, zejména ve chvíli, kdy je prakticky celý design stránek umístěn v samostatných CSS.
Jen pro připomenutí způsobu, jakým se s knihovnou Hiccup pracuje, se podívejme na příklad, kde se DSL (doménově specifický jazyk) podporovaný knihovnou Hiccup používá. Jedná se o jednoduchý program, který po svém spuštění vytvoří novou HTML stránku uloženou do souboru nazvaného „test.html“. Tato stránka bude obsahovat tabulku s hodnotami faktoriálu. Vidíme, že funkci hiccup.page/xhtml se předává vektor obsahující symbolicky zapsanou kostru stránky; uvnitř samozřejmě můžeme použít i programový kód (což není vlastnost knihovny Hiccup, ale homoikonického jazyka Clojure):
(ns htmltest2.core (:gen-class)) (require '[hiccup.page :as page]) (defn fact [n] (apply * (range 1 (inc n)))) (defn html-page [] (page/xhtml [:head [:title "Hiccup test #2"] [:meta {:name "Generator" :content "Clojure"}] [:meta {:http-equiv "Content-type" :content "text/html; charset=utf-8"}] ] [:body [:h1 "Hiccup test #2"] [:table [:tr [:th "n"] [:th "n!"]] (for [n (range 0 20)] [:tr [:td n] [:td (fact n)]]) ] ])) (defn -main [& args] (spit "test.html" (html-page)))
2. Běžné šablonovací systémy
Zcela odlišný způsob zvolili autoři knihovny Enlive, jejímž stručným popisem se budeme zabývat dnes. Namísto návrhu doménově specifického jazyka kombinujícího programový kód (výše se jedná o výpočet faktoriálu) se statickou částí představovanou symboly :head, :body, :h1, :div atd., je knihovna Enlive založena na HTML šablonách, které se na základě zadaných selektorů (v mnoha ohledech podobných selektorům používaným v CSS) transformují do podoby výsledné HTML stránky. Ovšem šablony v podání knihovny Enlive se v jednom ohledu liší od šablon, které můžeme znát například z různých frameworků pro programovací jazyky PHP, Python (Cheetah), Javu (JSP: JavaServer Pages, JSTL: JavaServer Pages Standard Tag Library) atd. Například ve zmíněných frameworcích Cheetah a JSP (JSTL) se přímo v šabloně kombinuje statický HTML kód se značkami šablonovacího systému či přímo s programovým kódem tak, jak to známe již z prvních verzí PHP.
Podívejme se na příklady, jak takové šablony kombinující statické HTML a „dynamickou“ část měněnou šablonovacím systémem mohou vypadat (příklady byly použity v dokumentaci pro framework Cheetah):
<html> <head><title>$title</title></head> <body> <table> #for $client in $clients <tr> <td>$client.surname, $client.firstname</td> <td><a href="mailto:$client.email">$client.email</a></td> </tr> #end for </table> </body> </html>
<html> <head><title><%=title%></title></head> <body> <table> <% for client in clients: %> <tr> <td><%=client['surname']%>, <%=client'[firstname']%></td> <td><a href="mailto:<%=client['email']%>"> <%=client['email']%></a></td> </tr> <%end%> </table> </body> </html>
3. Přístup použitý v knihovně Enlive
Naproti tomu se v knihovně Enlive jako šablona použije zcela běžná HTML stránka, kde pouze musíme zajistit, aby se ty tagy, jejichž obsah se má změnit, daly jednoznačně najít pomocí selektoru. Nejjednodušší je použití ID prvků/tagů, existují však i další možnosti, o nichž se dále zmíníme. Toto je příklad šablony pro Enlive:
<html> <head><title>jakýkoli titulek, který se změní</title></head> <body> <table id="clients"> <tr id="client"> <td id="name">vyplní se později</td> <td id="address"><a href="">i adresa se vyplní později</a></td> </tr> </table> </body> </html>
Jak je patrné, tak největším rozdílem mezi původními dvěma šablonami a šablonou poslední je fakt, že v poslední šabloně (určené pro knihovnu Enlive) nenajdeme žádnou speciální značku ani vkládaný kód. Tuto šablonu lze vytvořit v jakémkoli nástroji pro tvorbu HTML stránek a může ji vytvořit designér prakticky bez konzultace s vývojářem (výjimkou jsou ID u prvků, ale ani to by v tomto případě nebylo nutné, jak uvidíme za chvíli). Dokonce ani není nutné nechávat ty tagy, jejichž obsah se má měnit, prázdné, což je opět výhoda – designér totiž může vyzkoušet například i to, zda se do daného místa na stránce skutečně všechny požadované údaje vejdou, samotná šablona se použije jako mockup atd. atd.
4. První demonstrační příklad: aplikace jednoduché šablony
Před zdlouhavým vysvětlováním, jak přesně se šablona transformuje na výslednou HTML stránku, si ukažme funkční demonstrační příklad. Kostra příkladu se vytvoří jednoduše nám již známým příkazem:
lein new app enlive1
Do projektového souboru se přidá knihovna Enlive:
(defproject enlive1 "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"] [enlive "1.1.1"]] :main ^:skip-aot enlive1.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Do adresáře resources (to je důležité a nesmíme na to zapomenout!) se přidá šablona, což je běžná a ničím zvláštní HTML stránka:
<html> <head> <title>Testovaci stranka</title> <meta name="Author" content="Pavel Tisnovsky"> <meta name="Generator" content="vim"> </head> <body> <h1>Testovaci stranka</h1> <div> Text v prvnim odstavci. </div> <div> Text ve druhem odstavci. </div> </body> </html>
Nejdůležitější je samozřejmě vlastní zdrojový kód, kde se provádí transformace šablony na výslednou HTML stránku:
(ns enlive1.core (:gen-class)) (require '[net.cgrand.enlive-html :as html]) (html/deftemplate test-page "test.html" [data-for-page] [:title] (html/content (:title data-for-page)) [:h1] (html/content (:title data-for-page)) [:div] (html/content (:paragraph data-for-page))) (def new-data {:title "Zcela novy titulek stranky" :paragraph "xyzzy" }) (defn -main [& args] (println (reduce str (test-page new-data))))
Tento zdrojový kód obsahuje jednu funkci (-main), jednu mapu navázanou na jméno new-data a konečně deklaraci transformace šablony, kterou jsme nazvali test-page. Tato část (jak jste si pravděpodobně všimli, jedná se o makro a nikoli o funkci) je nejdůležitější, protože je v ní deklarováno:
- Obsah všech tagů <title> nahraď daty, která najdeš v předané mapě pod klíčem :title (ovšem tento tag bude na stránce umístěn jen jedenkrát, a to konkrétně v hlavičce).
- Obsah všech tagů <h1> nahraď stejným obsahem. Zde konkrétně se bude jednat o řetězec „Zcela novy titulek stranky“ a tag se taktéž vyskytuje pouze jednou.
- Obsah všech tagů <div> nahraď daty, která najdeš v předané mapě pod klíčem :paragraph. Konkrétně budou nahrazeny obsahy obou odstavců.
Ještě jednodušeji by bylo možné šablonu nadeklarovat takto (nyní bez dynamicky předávaných dat):
(html/deftemplate test-page "test.html" [neni-zapotrebi] [:title] (html/content "A jeste jiny titulek stranky") [:h1] (html/content "Tak tak, dalsi titule") [:div] (html/content "Novy obsah odstavce"))
Navíc si povšimněte transformace výsledku šablony test-page na řetězec – jednoduše spojíme celou sekvenci postupnou aplikací funkce str. Po spuštění získáme následující výstup:
<html> <head> <title>Zcela novy titulek stranky</title> <meta content="Pavel Tisnovsky" name="Author" /> <meta content="vim" name="Generator" /> </head> <body> <h1>Zcela novy titulek stranky</h1> <div>xyzzy</div> <div>xyzzy</div> </body> </html>
5. Další typy selektorů
V předchozím příkladu jsme používali velmi jednoduché selektory typu [:title] či [:div] (vždy se jedná o vektory). K dispozici jsou však i další možnosti, jak vybrat ty tagy, s nimiž se má manipulovat:
# | Selektor | Význam |
---|---|---|
1 | [:div] | všechny elementy <div> |
2 | [:title] | všechny elementy <title> (tento element se vyskytuje jen jedenkrát) |
3 | [:div.danger] | všechny elementy <div> s třídou „danger“ |
4 | [:div#summary] | všechny elementy <div> s ID „summary“ (opět by se mělo jednat jen o jediný element) |
5 | [:div :span] | výběr vnitřního tagu <span> umístěného v elementu <div> |
6 | [:div.menu :ul :li :span] | kombinace předchozích dvou možnosti |
7 | [:table#userlist :tr :td] | kombinace předchozích dvou možnosti (zde praktičtější) |
Možností výběrů elementů je ještě více, o některých z nich se zmíníme příště.
6. Druhý demonstrační příklad: výběr tagů na základě jejich třídy a ID
Ve druhém demonstračním příkladu budou elementy (tagy) vybírány na základě jejich třídy a popř. ID (což je mnohem praktičtější). Projektový soubor vypadá následovně:
(defproject enlive2 "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"] [enlive "1.1.1"]] :main ^:skip-aot enlive2.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Šablona umístěná v adresáři resources se odlišuje od šablony, s níž jsme se setkali v prvním příkladu. Povšimněte si toho, že některé odstavce (<div>) mají přiřazeno ID a některé zase třídu či třídy:
<html> <head> <title>Testovaci stranka</title> <meta name="Author" content="Pavel Tisnovsky"> <meta name="Generator" content="vim"> </head> <body> <h1>Testovaci stranka</h1> <div id="paragraph1"> Text v prvnim odstavci. </div> <div id="paragraph2"> Text ve druhem odstavci. </div> <div class="paragraphs"> Text ve tretim odstavci. </div> <div class="classX, paragraphs"> Text ve ctvrtem odstavci. </div> </body> </html>
Vlastní zdrojový kód používá v makru html/deftemplate odlišné typy selektorů. První odstavec je vybrán podle svého ID „paragraph1“, druhý odstavec taktéž, kdežto další selektor zafunguje na odstavce se třídou „paragraphs“:
(ns enlive2.core (:gen-class)) (require '[net.cgrand.enlive-html :as html]) (html/deftemplate test-page "test.html" [data-for-page] [:title] (html/content (:title data-for-page)) [:h1] (html/content (:title data-for-page)) [:div#paragraph1] (html/content (:paragraph1 data-for-page)) [:div#paragraph2] (html/content (:paragraph2 data-for-page)) [:div.paragraphs] (html/content (:paragraphs data-for-page)) ) (def new-data {:title "Zcela novy titulek stranky" :paragraph1 "xyzzy" :paragraph2 "" :paragraphs "42" }) (defn -main [& args] (println (reduce str (test-page new-data))))
Zajímavé se bude podívat na výsledek, především na to, zda poslední selektor vybere i odstavec, k němuž jsou přiřazeny dvě třídy:
<html> <head> <title>Zcela novy titulek stranky</title> <meta content="Pavel Tisnovsky" name="Author" /> <meta content="vim" name="Generator" /> </head> <body> <h1>Zcela novy titulek stranky</h1> <div id="paragraph1">xyzzy</div> <div id="paragraph2"></div> <div class="paragraphs">42</div> <div class="classX, paragraphs">42</div> </body> </html>
Vidíme, že šablona pracuje korektně (tedy alespoň zatím :-).
7. Snippety použitelné pro výpis sekvencí do HTML stránky
V obou předchozích demonstračních příkladech se provádělo nahrazení obsahu explicitně zadaných elementů (tagů) nějakými skalárními daty. V praxi by se například mohlo jednat o políčko se jménem přihlášeného uživatele, políčko s celkovou cenou nákupu atd. Ovšem v mnoha aplikacích musíme umět pracovat i se sekvencí dat. Může se například jednat o požadavek zobrazení seznamu uživatelů, zobrazení tabulky se zbožím (nákupním košíkem) atd. V tradičně pojatých šablonovacích systémech se v tomto případě používají programové smyčky, ať již zapsané explicitně (viz druhou kapitolu s ukázkami) nebo s využitím nějakých speciálních značek (v JSTL se například používá speciální značka <c:forEach>). Ovšem v knihovně Enlive tuto možnost nemáme, a to z toho prostého důvodu, že šablonou je běžný HTML soubor. Jak tedy implementovat například požadavek na zobrazení seznamu herců v nějaké divadelní hře? Řešením jsou takzvané snippety, u nichž se specifikuje počáteční a koncový element v HTML a poté již snippet dokáže opakovat tu část HTML stránky, která je uvnitř specifikovaných elementů.
8. Třetí demonstrační příklad: použití snippetu pro výpis seznamu, explicitní selektory
Použití jednoduchého snippetu bude ukázáno v dnešním třetím a současně i posledním demonstračním příkladu, který by po svém spuštění měl vypsat herecké obsazení v divadelní hře „Vražda v salonním coupé“. V reálné aplikaci by se tato data načetla z databáze či přenesla z nějakého jiného systému, my si pro jednoduchost vystačíme s vektorem deklarovaným přímo ve zdrojovém kódu.
Vytvoření kostry demonstračního příkladu:
lein new app enlive3
Projektový soubor třetího demonstračního příkladu se nijak zvláště neodlišuje od obou předchozích projektových souborů:
(defproject enlive3 "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"] [enlive "1.1.1"]] :main ^:skip-aot enlive3.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Šablona je ovšem odlišná – máme zde „obalový“ odstavec s ID nastaveným na „roles“, v němž se nachází další odstavec s ID „role“. Tento odstavec bude ve výsledné HTML stránce zopakován tolikrát, kolik jmen herců do transformačního makra předáme:
<html> <head> <title>Testovaci stranka</title> <meta name="Author" content="Pavel Tisnovsky"> <meta name="Generator" content="vim"> </head> <body> <h1>Hra <span></span></h1> <div id="roles"> <div id="role"> <span id="actor">herec</span> <span id="character">postava</span> </div> </div> <div>Pokracovani</div> </body> </html>
Zdrojový kód demonstračního příkladu obsahuje tabulku (vektor) s rolemi a dále pak datovou strukturu s titulkem divadelní hry a referencí na právě zmíněnou tabulku s rolemi:
(ns enlive3.core (:gen-class)) (require '[net.cgrand.enlive-html :as html]) (def roles [ {:actor-name "Zdeněk Svěrák" :character "inspektor Trachta "} {:actor-name "Petr Brukner" :character "praktikant Hlaváček"} {:actor-name "Miloň Čepelka" :character "praktikant Hlaváček"} {:actor-name "Bořivoj Penc" :character "továrník Bierhanzel"} {:actor-name "Jaroslav Weigel" :character "továrník Bierhanzel"} {:actor-name "Jan Hraběta" :character "továrník Meyer"} {:actor-name "Václav Kotek" :character "steward"} {:actor-name "Genadij Rumlena" :character "steward"}]) (def vrazda-v-salonnim-coupe {:title "Vražda v salonním coupé" :roles roles })
Nyní následuje důležitější část. Nejprve snippet, v němž je deklarováno, který element a případné podelementy se budou opakovat. Deklarováno je, že opakovat se bude jen odstavec s ID nastaveným na „role“, pravidla pro vyplňování daty (selektor+způsob naplnění) již známe:
(html/defsnippet one-record "test.html" {[:div#role] ; zacatek [:div#role]} ; konec [record] [:span#actor] (html/content (:actor-name record)) [:span#character] (html/content (:character record)))
Vlastní deklarace transformace šablony se taktéž změnila, a to kvůli poslednímu řádku, kterým je deklarováno (zjednodušeně řečeno) opakování elementů umístěných v odstavci s ID nastaveným na „roles“:
(html/deftemplate test-page "test.html" [data-for-page] [:title] (html/content (:title data-for-page)) [:h1 :span] (html/content (:title data-for-page)) [:div#roles] (html/content (map one-record (:roles data-for-page))) ; vnitrek odstavce bude duplikovan ) (defn -main [& args] (println (reduce str (test-page vrazda-v-salonnim-coupe))))
Výsledek běhu demonstračního příkladu (povšimněte si opakování IDček):
<html> <head> <title>Vražda v salonním coupé</title> <meta content="Pavel Tisnovsky" name="Author" /> <meta content="vim" name="Generator" /> </head> <body> <h1>Hra <span>Vražda v salonním coupé</span></h1> <div id="roles"><div id="role"> <span id="actor">Zdeněk Svěrák</span> <span id="character">inspektor Trachta </span> </div><div id="role"> <span id="actor">Petr Brukner</span> <span id="character">praktikant Hlaváček</span> </div><div id="role"> <span id="actor">Miloň Čepelka</span> <span id="character">praktikant Hlaváček</span> </div><div id="role"> <span id="actor">Bořivoj Penc</span> <span id="character">továrník Bierhanzel</span> </div><div id="role"> <span id="actor">Jaroslav Weigel</span> <span id="character">továrník Bierhanzel</span> </div><div id="role"> <span id="actor">Jan Hraběta</span> <span id="character">továrník Meyer</span> </div><div id="role"> <span id="actor">Václav Kotek</span> <span id="character">steward</span> </div><div id="role"> <span id="actor">Genadij Rumlena</span> <span id="character">steward</span> </div></div> <div>Pokracovani</div> </body> </html>
O způsobech vylepšení tohoto příkladu se zmíníme příště.
9. Repositář s dnešními demonstračními příklady
Všechny tři dnes zmíněné demonstrační příklady byly, podobně jako v předchozích částech tohoto seriálu, uloženy 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 demonstračních příkladů přímé odkazy:
10. Odkazy na předchozí části tohoto seriálu
- Leiningen: nástroj pro správu projektů napsaných v Clojure
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/ - 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/ - 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/ - 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/ - 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/ - 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/ - Programovací jazyk Clojure a databáze (1.část)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/ - Pluginy pro Leiningen
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/ - 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/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/ - 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/ - 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/ - 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/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/ - 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/ - 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/ - Programovací jazyk Clojure a práce s Gitem
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/ - Programovací jazyk Clojure a práce s Gitem (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/ - Programovací jazyk Clojure – triky při práci s řetězci
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/ - Programovací jazyk Clojure – triky při práci s kolekcemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/ - Programovací jazyk Clojure – práce s mapami a množinami
http://www.root.cz/clanky/programovaci-jazyk-clojure-prace-s-mapami-a-mnozinami/ - Programovací jazyk Clojure – základy zpracování XML
http://www.root.cz/clanky/programovaci-jazyk-clojure-zaklady-zpracovani-xml/ - Programovací jazyk Clojure – testování s využitím knihovny Expectations
http://www.root.cz/clanky/programovaci-jazyk-clojure-testovani-s-vyuzitim-knihovny-expectations/ - Programovací jazyk Clojure – některé užitečné triky použitelné (nejenom) v testech
http://www.root.cz/clanky/programovaci-jazyk-clojure-nektere-uzitecne-triky-pouzitelne-nejenom-v-testech/
11. Odkazy na Internetu
- Clojure Cookbook: Templating HTML with Enlive
https://github.com/clojure-cookbook/clojure-cookbook/blob/master/07_webapps/7–11_enlive.asciidoc - An Introduction to Enlive
https://github.com/swannodette/enlive-tutorial/ - Enlive na GitHubu
https://github.com/cgrand/enlive - Expectations: příklady atd.
http://jayfields.com/expectations/ - Expectations na GitHubu
https://github.com/jaycfields/expectations - Lein-expectations na GitHubu
https://github.com/gar3thjon3s/lein-expectations - Testing Clojure With Expectations
https://semaphoreci.com/blog/2014/09/23/testing-clojure-with-expectations.html - Clojure testing TDD/BDD libraries: clojure.test vs Midje vs Expectations vs Speclj
https://www.reddit.com/r/Clojure/comments/1viilt/clojure_testing_tddbdd_libraries_clojuretest_vs/ - Testing: One assertion per test
http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html - Rewriting Your Test Suite in Clojure in 24 hours
http://blog.circleci.com/rewriting-your-test-suite-in-clojure-in-24-hours/ - Clojure doc: zipper
http://clojuredocs.org/clojure.zip/zipper - Clojure doc: parse
http://clojuredocs.org/clojure.xml/parse - Clojure doc: xml-zip
http://clojuredocs.org/clojure.zip/xml-zip - Clojure doc: xml-seq
http://clojuredocs.org/clojure.core/xml-seq - Parsing XML in Clojure
https://github.com/clojuredocs/guides - Clojure Zipper Over Nested Vector
https://vitalyper.wordpress.com/2010/11/23/clojure-zipper-over-nested-vector/ - Understanding Clojure's PersistentVector implementation
http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation - Understanding Clojure's PersistentHashMap (deftwice…)
http://blog.higher-order.net/2009/09/08/understanding-clojures-persistenthashmap-deftwice.html - Assoc and Clojure's PersistentHashMap: part ii
http://blog.higher-order.net/2010/08/16/assoc-and-clojures-persistenthashmap-part-ii.html - Ideal Hashtrees (paper)
http://lampwww.epfl.ch/papers/idealhashtrees.pdf - Clojure home page
http://clojure.org/ - Clojure (downloads)
http://clojure.org/downloads - Clojure Sequences
http://clojure.org/sequences - Clojure Data Structures
http://clojure.org/data_structures - The Structure and Interpretation of Computer Programs: 2.2.1 Representing Sequences
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-15.html#%_sec2.2.1 - The Structure and Interpretation of Computer Programs: 3.3.1 Mutable List Structure
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-22.html#%_sec3.3.1 - Clojure – Functional Programming for the JVM
http://java.ociweb.com/mark/clojure/article.html - Clojure quick reference
http://faustus.webatu.com/clj-quick-ref.html - 4Clojure
http://www.4clojure.com/ - ClojureDoc (rozcestník s dokumentací jazyka Clojure)
http://clojuredocs.org/ - Clojure (na Wikipedia EN)
http://en.wikipedia.org/wiki/Clojure - Clojure (na Wikipedia CS)
http://cs.wikipedia.org/wiki/Clojure - SICP (The Structure and Interpretation of Computer Programs)
http://mitpress.mit.edu/sicp/ - Pure function
http://en.wikipedia.org/wiki/Pure_function - Funkcionální programování
http://cs.wikipedia.org/wiki/Funkcionální_programování - Čistě funkcionální (datové struktury, jazyky, programování)
http://cs.wikipedia.org/wiki/Čistě_funkcionální - Clojure Macro Tutorial (Part I, Getting the Compiler to Write Your Code For You)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-i-getting.html - Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html - Clojure Macro Tutorial (Part III: Syntax Quote)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html - Tech behind Tech: Clojure Macros Simplified
http://techbehindtech.com/2010/09/28/clojure-macros-simplified/ - Fatvat – Exploring functional programming: Clojure Macros
http://www.fatvat.co.uk/2009/02/clojure-macros.html - Eulerovo číslo
http://cs.wikipedia.org/wiki/Eulerovo_číslo - List comprehension
http://en.wikipedia.org/wiki/List_comprehension - List Comprehensions in Clojure
http://asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html - Clojure Programming Concepts: List Comprehension
http://en.wikibooks.org/wiki/Clojure_Programming/Concepts#List_Comprehension - Clojure core API: for macro
http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/for - cirrus machina – The Clojure for macro
http://www.cirrusmachina.com/blog/comment/the-clojure-for-macro/ - Riastradh's Lisp Style Rules
http://mumble.net/~campbell/scheme/style.txt - Dynamic Languages Strike Back
http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html - Scripting: Higher Level Programming for the 21st Century
http://www.tcl.tk/doc/scripting.html - Java Virtual Machine Support for Non-Java Languages
http://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html - Třída java.lang.String
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html - Třída java.lang.StringBuffer
http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuffer.html - Třída java.lang.StringBuilder
http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html - StringBuffer versus String
http://www.javaworld.com/article/2076072/build-ci-sdlc/stringbuffer-versus-string.html - Threading macro (dokumentace k jazyku Clojure)
https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/-> - Understanding the Clojure → macro
http://blog.fogus.me/2009/09/04/understanding-the-clojure-macro/ - clojure.inspector
http://clojure.github.io/clojure/clojure.inspector-api.html - The Clojure Toolbox
http://www.clojure-toolbox.com/ - Unit Testing in Clojure
http://nakkaya.com/2009/11/18/unit-testing-in-clojure/ - Testing in Clojure (Part-1: Unit testing)
http://blog.knoldus.com/2014/03/22/testing-in-clojure-part-1-unit-testing/ - API for clojure.test – Clojure v1.6 (stable)
https://clojure.github.io/clojure/clojure.test-api.html - 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:
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/ - Clojure.org: Vars and the Global Environment
http://clojure.org/Vars - Clojure.org: Refs and Transactions
http://clojure.org/Refs - Clojure.org: Atoms
http://clojure.org/Atoms - Clojure.org: Agents as Asynchronous Actions
http://clojure.org/agents - Transient Data Structureshttp://clojure.org/transients