Enlive – výkonný šablonovací systém pro jazyk Clojure (dokončení)

Pavel Tišnovský 24. 9. 2015

V dnešním článku o jazyce Clojure a o knihovnách, které jsou pro tento jazyk vytvořeny, dokončíme popis knihovny Enlive. Zabývat se budeme vytvářením tabulek z předložené šablony a taktéž selektory pro získání zvolených informací z HTML stránek. Enlive je totiž možné použít i pro „vyzobávání“ dat.

Obsah

1. Enlive – výkonný šablonovací systém pro jazyk Clojure (dokončení)

2. Vytvoření tabulky v HTML s využitím snippetu

3. Použití knihovny Enlive pro získávání dat z HTML stránek

4. Příklad enlive5 – použití funkcí html-resource a select

5. Příklad enlive6 – threading makro jako cesta k čitelnějšímu zdrojovému kódu

6. Příklad enlive7 – příklad použití speciální formy doto

7. Další typy selektorů nabízené knihovnou Enlive

8. Příklad enlive8 – použití :> a (attr=) ve funkci select

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

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

11. Odkazy na Internetu

1. Enlive – výkonný šablonovací systém pro jazyk Clojure (dokončení)

V předchozí části seriálu o programovacím jazyce Clojure i o knihovnách, které mohou zjednodušit a současně i zlevnit vývoj aplikací vytvářených v tomto programovacím jazyku, jsme se seznámili s některými principy, na nichž je postavena knihovna pojmenovaná Enlive. Tuto knihovnu je možné použít několika způsoby: jak pro generování dynamických HTML stránek s využitím HTML šablony a sady funkcionálně zapsaných transformačních pravidel (v nichž jsou použity takzvané selektory), tak i pro „vyzobávání“ dat z existujících HTML stránek. Například je relativně jednoduché programově načíst úvodní stránku Roota a následně z ní získat nadpisy všech článků, zpráviček atd. Právě s touto poměrně zajímavou (a pro některé aplikace i velmi praktickou) problematikou se seznámíme v navazujících kapitolách, nejprve však dokončíme problematiku takzvaných snippetů.

2. Vytvoření tabulky v HTML s využitím snippetu

V posledním demonstračním příkladu, který byl popsán na samotném konci předchozí části seriálu, byly použity takzvané „snippety“ umožňující v generované HTML stránce opakovat elementy (s jinými daty). Připomeňme si, že u každého snippetu se nějakým selektorem specifikuje počáteční a koncový element v HTML šabloně a poté již snippet dokáže opakovat tu část HTML stránky, která se nachází uvnitř specifikovaných elementů. Tento postup můžeme využít i pro tvorbu tabulek, což je s velkou pravděpodobností nejčastější způsob zobrazení obsahu nějaké sekvence, tj. v pojetí Clojure typicky seznamu či vektoru. Právě tímto způsobem vytvořený snippet využijeme v dnešním prvním demonstračním příkladu, v němž se vytvoří HTML stránka obsahující herecké obsazení v divadelní hře „Vražda v salonním coupé“.

Kostra projektu demonstračního příkladu se vygeneruje jednoduše:

lein new app

Projektový soubor je nutné upravit takovým způsobem, aby se při spuštění aplikace mohlo pracovat i s knihovnou Enlive:

(defproject enlive4 "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 enlive4.core
    :target-path "target/%s"
    :profiles {:uberjar {:aot :all}})

Následuje ukázka šablony uložené v adresáři resources. Povšimněte si, že šablona je oproti předchozím příkladům upravena. Především v ní můžeme nalézt základ HTML tabulky, tabulka samotná má ID nastaveno na „roles“, jediný řádek tabulky pak má ID nastaveno na „role“. Na tomto řádku se nachází dvě buňky, první má ID „actor“ a druhá „character“. Tabulka je tak vlastně samopopisná:

<html>
    <head>
        <title>Testovaci stranka</title>
        <meta name="Author" content="Pavel Tisnovsky">
        <meta name="Generator" content="vim">
    </head>
    <body>
        <h1>Hra <span></span></h1>
        <table id="roles">
            <tr id="role">
                <td id="actor">herec</td>
                <td id="character">postava</td>
            </tr>
        </table>
        <div>Pokracovani</div>
    </body>
</html>

Zdrojový kód demonstračního příkladu uložený v souboru src/enlive4/core.clj:

(ns enlive4.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
    })
 
(html/defsnippet one-record "test.html"
    {[:#role]     ; zacatek
     [:#role]}    ; konec
    [record]
    [:#actor]      (html/content (:actor-name record))
    [:#character]  (html/content (:character record)))
 
(html/deftemplate test-page "test.html"
    [data-for-page]
    [:title]       (html/content (:title data-for-page))
    [:h1 :span]    (html/content (:title data-for-page))
    [:#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))))

Po spuštění tohoto příkladu by se měla na standardním výstupu objevit následující HTML stránka:

<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>
        <table id="roles"><tr id="role">
                <td id="actor">Zdeněk Svěrák</td>
                <td id="character">inspektor Trachta  </td>
            </tr><tr id="role">
                <td id="actor">Petr Brukner</td>
                <td id="character">praktikant Hlaváček</td>
            </tr><tr id="role">
                <td id="actor">Miloň Čepelka</td>
                <td id="character">praktikant Hlaváček</td>
            </tr><tr id="role">
                <td id="actor">Bořivoj Penc</td>
                <td id="character">továrník Bierhanzel</td>
            </tr><tr id="role">
                <td id="actor">Jaroslav Weigel</td>
                <td id="character">továrník Bierhanzel</td>
            </tr><tr id="role">
                <td id="actor">Jan Hraběta</td>
                <td id="character">továrník Meyer</td>
            </tr><tr id="role">
                <td id="actor">Václav Kotek</td>
                <td id="character">steward</td>
            </tr><tr id="role">
                <td id="actor">Genadij Rumlena</td>
                <td id="character">steward</td>
            </tr></table>
        <div>Pokracovani</div>
    </body>
</html>

Povšimněte si toho, že formát výstupu není zcela přesný (uzavírací tag pro řádek tabulky není oddělen od otevíracího tagu následujícího řádku), nicméně základní struktura šablony zůstala zachována.

3. Použití knihovny Enlive pro získávání dat z HTML stránek

Knihovnu Enlive lze použít i pro získávání dat z HTML stránek. S využitím funkce net.cgrand.enlive-html/html-resource je totiž možné načíst stránku a provést její zpracování do interní podoby, v níž je stránka reprezentována formou stromu, kde jednotlivé uzly mají přiřazené atributy, poduzly a popř. i obsah (s podobným formátem jsme se již setkali při zpracování XML). Jedná se tedy o obdobu DOMu, což mj. znamená, že pro získávání dat se nepoužívá klasický parsing či regulární výrazy, ale takzvané selektory vzdáleně připomínající XPath (ne syntaxí, ale sémantikou). Druhou důležitou funkcí je funkce nazvaná net.cgrand.enlive-html/select, která na základě zadaného selektoru dokáže vrátit odpovídající uzel či sekvenci uzlů. S vrácenými daty lze provádět operace typu „získej n-tý prvek sekvence“, „získej data uložená v atributu :content“ apod. Některé z těchto možností si ukážeme v demonstračních příkladech.

V trojici příkladů bude použita tato HTML stránka, která bude sloužit jako vstup:

<html>
    <head>
        <title>Test page</title>
        <meta name="Author" content="Pavel Tisnovsky">
        <meta name="Generator" content="vim">
    </head>
    <body>
        <h1>Lorem Ipsum</h1>
        <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a
        diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam
        viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent
        et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt
        congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed
        arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet,
        consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis,
        pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id
        magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra
        tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices
        accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at
        malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis
        parturient montes, nascetur ridiculus mus. In rutrum accumsan
        ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</div>
        <h1>Second paragraph</h1>
        <div>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut
        tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper
        ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi
        diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec
        pretium volutpat, arcu ante placerat erat, non tristique elit urna et
        turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et
        orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam,
        elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis
        pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod
        ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo
        sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at
        massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies.
        Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor,
        viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam
        sagittis nisi dui.</div>
        <h1>Third paragraph</h1>
    </body>
</html>

4. Příklad enlive5 – použití funkcí html-resource a select

V demonstračním příkladu nazvaném enlive5 je použita funkce net.cgrand.enlive-html/html-resource, která dokáže načíst stránku uloženou jak na lokálním disku, tak i na zadaném URL. Po načtení je stránka zparsována a převedena do výše zmíněné stromové body, která má v tomto konkrétním případě tvar (každý tag obsahuje své symbolické jméno, množinu atributů, obsah a pod-uzly):

({:tag :html,
  :attrs nil,
  :content
  ("\n    "
   {:tag :head,
    :attrs nil,
    :content
    ("\n        "
     {:tag :title, :attrs nil, :content ("Test page")}
     "\n        "
     {:tag :meta,
      :attrs {:content "Pavel Tisnovsky", :name "Author"},
      :content nil}
     "\n        "
     {:tag :meta,
      :attrs {:content "vim", :name "Generator"},
      :content nil}
     "\n    ")}
   "\n    "
   {:tag :body,
    :attrs nil,
    :content
    ("\n        "
     {:tag :h1, :attrs nil, :content ("Lorem Ipsum")}
     "\n        "
     {:tag :div,
      :attrs nil,
      :content
      ("Lorem ipsum ....
       .............
       .............")}
     "\n        "
     {:tag :h1, :attrs nil, :content ("Second paragraph")}
     "\n        "
     {:tag :div,
      :attrs nil,
      :content
      ("Vivamus fermentum....
       .............
       .............")}
     "\n        "
     {:tag :h1, :attrs nil, :content ("Third paragraph")}
     "\n    ")}
   "\n\n\n")})

Poté je použita funkce net.cgrand.enlive-html/select pro získání obsahu tagu „title“ umístěného v tagu „head“ a n-tého tagu „h1“ umístěného uvnitř tagu „body“. Výběr tagů se provádí s využitím selektorů, které mají vždy tvar vektoru (to jsme si již ostatně řekli minule). Vrácena je vždy sekvence, i když může být prázdná či může obsahovat jen jediný tag (což je první případ).

Následuje výpis zdrojového kódu demonstračního příkladu:

(ns enlive5.core
    (:use net.cgrand.enlive-html))
 
(defn load-html-page
    "Nacteni testovaci stranky umistene v podadresari './resources'."
    []
    (html-resource "test.html"))
 
(defn print-tag-content
    "Vypis textoveho obsahu vybraneho tagu."
    [tag]
    (println (clojure.string/join (get tag :content))))
 
(defn print-title
    "Vyber titulku stranky, tj. textu uzavreneho do <title></title>."
    [html-page]
    (print-tag-content (first (select html-page [:head :title]))))
 
(defn print-h1
    "Vyber n-teho nadpisu, kde cislovani zacina od jednicky."
    [html-page n]
    (print-tag-content (nth (select html-page [:body :h1]) (dec n))))
 
(defn -main
    "Vstupni bod do aplikace."
    [& args]
    (let [html-page (load-html-page)]
          (print-title html-page)
          (print-h1 html-page 1)
          (print-h1 html-page 2)
          (print-h1 html-page 3)))

Po spuštění tohoto příkladu by se na výstupu měly objevit tyto čtyři textové řádky:

Test page
Lorem Ipsum
Second paragraph
Third paragraph

Vidíme, že skutečně došlo k výběru a výpisu titulku stránky i všech tří nadpisů uvedených uvnitř tagu <h1>.

5. Příklad enlive6 – threading makro jako cesta k čitelnějšímu zdrojovému kódu

Zdrojový kód předchozího demonstračního příkladu není v žádném případě dokonalý, a to mj. i z toho důvodu, že se v něm vyskytuje volání funkcí, kterým se předává výsledek jiných funkcí. Jedná se o vnořené formy, které nejsou příliš čitelné a trošku dělají Clojure (a nepřímo i LISPu) špatnou reklamu tím, že se zbytečně nadužívají kulaté závorky. Ostatně se podívejme sami na ona zmiňovaná volání:

(print-tag-content (first (select html-page [:head :title]))))
(print-tag-content (nth (select html-page [:body :h1]) (dec n))))

Vylepšení zdrojového kódu je v tomto případě více než snadné, protože lze použít již v tomto seriálu několikrát zmiňované threading makro zapisované symbolem ->. Díky tomuto makru se předchozí dvě formy mohou přepsat na:

(-> html-page
    (select [:head :title])
    first
    print-tag-content))
 
(-> html-page
    (select [:body :h1])
    (nth (dec n))
    print-tag-content))

(rozdělení na více řádků je samozřejmě nepovinné).

Funkčně identická podoba předchozího demonstračního příkladu vypadá s použitím threading makra takto:

(ns enlive6.core
    (:use net.cgrand.enlive-html))
 
(defn load-html-page
    "Nacteni testovaci stranky umistene v podadresari './resources'."
    []
    (html-resource "test.html"))
 
(defn print-tag-content
    "Vypis textoveho obsahu vybraneho tagu."
    [tag]
    (-> tag
        :content
        clojure.string/join
        println))
 
(defn print-title
    "Vyber titulku stranky, tj. textu uzavreneho do <title></title>."
    [html-page]
    (-> html-page
        (select [:head :title])
        first
        print-tag-content))
 
(defn print-h1
    "Vyber n-teho nadpisu, kde cislovani zacina od jednicky."
    [html-page n]
    (-> html-page
        (select [:body :h1])
        (nth (dec n))
        print-tag-content))
 
(defn -main
    "Vstupni bod do aplikace."
    [& args]
    (let [html-page (load-html-page)]
          (print-title html-page)
          (print-h1 html-page 1)
          (print-h1 html-page 2)
          (print-h1 html-page 3)))

6. Příklad enlive7 – příklad použití speciální formy doto

Zdrojový kód je možné vylepšit ještě dalším způsobem. Podívejme se na funkci -main:

(defn -main
    "Vstupni bod do aplikace."
    [& args]
    (let [html-page (load-html-page)]
          (print-title html-page)
          (print-h1 html-page 1)
          (print-h1 html-page 2)
          (print-h1 html-page 3)))

Programátora by zde mělo zaujmout především to, že hodnota navázaná na lokální symbol html-page je použita při volání dalších čtyř funkcí a to příhodně jako první parametr (což není náhoda, takto jsem si ony volané funkce schválně upravil). Jedná se tedy o opakující se kód, který není příliš přehledný a navíc opět oplývá zbytečně velkým množstvím kulatých závorek. V tomto případě je náprava snadná, protože stačí použít speciální formu doto a přepsat funkci -main následujícím způsobem:

(defn -main
    "Vstupni bod do aplikace."
    [& args]
    (doto (load-html-page)
          (print-title)
          (print-h1 1)
          (print-h1 2)
          (print-h1 3)))

Tato forma nejprve zavolá první funkci load-html-page a její výsledek postupně předá dalším čtyřem funkcím (jako první parametr).

Funkčně identická podoba předchozích dvou demonstračních příkladů vypadá s použitím threading makra a speciální formy doto takto:

(ns enlive7.core
    (:use net.cgrand.enlive-html))
 
(defn load-html-page
    "Nacteni testovaci stranky umistene v podadresari './resources'."
    []
    (html-resource "test.html"))
 
(defn print-tag-content
    "Vypis textoveho obsahu vybraneho tagu."
    [tag]
    (-> tag
        :content
        clojure.string/join
        println))
 
(defn print-title
    "Vyber titulku stranky, tj. textu uzavreneho do <title></title>."
    [html-page]
    (-> html-page
        (select [:head :title])
        first
        print-tag-content))
 
(defn print-h1
    "Vyber n-teho nadpisu, kde cislovani zacina od jednicky."
    [html-page n]
    (-> html-page
        (select [:body :h1])
        (nth (dec n))
        print-tag-content))
 
(defn -main
    "Vstupni bod do aplikace."
    [& args]
    (doto (load-html-page)
          (print-title)
          (print-h1 1)
          (print-h1 2)
          (print-h1 3)))

7. Další typy selektorů nabízené knihovnou Enlive

Knihovna Enlive programátorům nabízí velké množství různých selektorů, které jsou popsány na stránce http://cgrand.github.io/en­live/syntax.html. S jejich využitím je například možné nalézt ty tagy, které obsahují zadaný atribut či atributy, hledat na základě hodnot atributů atd. atd. V tabulce umístěné pod tímto odstavcem jsou některé z těchto selektorů zmíněny:

# Funkce Význam
1 (attr? attribute-keyword*) tagy obsahující zadaný atribut či atributy
2 (attr= (attribute-keyword value)*) tagy obsahující atributy se specifikovanými hodnotami
3 (attr-has (attribute-keyword value)*) lze zadat více hodnot atributů hledaných tagů
4 (attr-starts (attribute-keyword value)*) hodnota atributu začíná na řetězec
5 (attr-ends (attribute-keyword value)*) hodnota atributu končí na řetězec
6 (attr-contains (attribute-keyword value)*) hodnota atributu obsahuje podřetězec
7 (nth-child stride? offset) dokáže vybrat synovské pod-uzly
8 (nth-last-child stride? offset) dtto, ale určení pod-uzlu probíhá opačně
9 node :> text-node získání textu (content) tagu

8. Příklad enlive8 – použití :> a (attr=) ve funkci select

V dnešním posledním demonstračním příkladu jsou použity selektory představované funkcí (attr=) a dále pak zápisem :>. První z těchto selektorů je použit pro nalezení informace o generátoru stránky:

(-> html-page
    (select [(attr= :name "Generator")])
    first
    :attrs
    :content
    println))

Druhý selektor je vlastně zkratkou pro získání textu uloženého v tagu, tedy obsahu tagu:

(-> html-page
    (select [:div :> text-node])
    first
    println))

Dále se vyberou všechny tagy obsahující zadaný atribut „name“:

(select html-page [(attr? :name)]

Podívejme se na celý zdrojový kód:

(ns enlive8.core
    (:use net.cgrand.enlive-html))
 
(defn load-html-page
    "Nacteni testovaci stranky umistene v podadresari './resources'."
    []
    (html-resource "test.html"))
 
(defn print-tag-content
    "Vypis textoveho obsahu vybraneho tagu."
    [tag]
    (-> tag
        :content
        clojure.string/join
        println))
 
(defn print-title
    "Vyber titulku stranky, tj. textu uzavreneho do <title></title>."
    [html-page]
    (-> html-page
        (select [:head :title])
        first
        print-tag-content))
 
(defn print-h1
    "Vyber n-teho nadpisu, kde cislovani zacina od jednicky."
    [html-page n]
    (-> html-page
        (select [:body :h1])
        (nth (dec n))
        print-tag-content))
 
(defn print-first-paragraph
    "Vyber *obsahu* prvniho odstavce."
    [html-page]
    (-> html-page
        (select [:div :> text-node])
        first
        println))
 
(defn print-generator
    "Vyber a vypis generatoru nacteneho z metainformaci."
    [html-page]
    (-> html-page
        (select [(attr= :name "Generator")])
        first
        :attrs
        :content
        println))
 
(defn print-meta-tag
    [tag]
    (let [attrs (:attrs tag)]
        (println (:name attrs) " -> " (:content attrs))))
 
(defn print-all-metatags
    "Vyber a vypis vsech metainformaci."
    [html-page]
    (doseq [tag (select html-page [(attr? :name)])]
        (print-meta-tag tag)))
 
(defn -main
    "Vstupni bod do aplikace."
    [& args]
    (doto (load-html-page)
          (print-title)
          (print-h1 1)
          (print-h1 2)
          (print-h1 3)
          (print-first-paragraph)
          (print-generator)
          (print-all-metatags)))

Po spuštění tohoto příkladu by se na standardním výstupu měl objevit text:

widgety

Test page
Lorem Ipsum
Second paragraph
Third paragraph
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a
        diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam
        viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent
        et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt
        congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed
        arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet,
        consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis,
        pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id
        magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra
        tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices
        accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at
        malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis
        parturient montes, nascetur ridiculus mus. In rutrum accumsan
        ultricies. Mauris vitae nisi at sem facilisis semper ac in est.
vim
Author  ->  Pavel Tisnovsky
Generator  ->  vim

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

Všech pět dnes zmíněný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 demonstračních příkladů přímé odkazy:

Příklady z předchozího týdne (jen pro úplnost):

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

  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 (2)
    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/
  17. Programovací jazyk Clojure a práce s Gitem
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/
  18. Programovací jazyk Clojure a práce s Gitem (2)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/
  19. Programovací jazyk Clojure – triky při práci s řetězci
    http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/
  20. Programovací jazyk Clojure – triky při práci s kolekcemi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/
  21. Programovací jazyk Clojure – práce s mapami a množinami
    http://www.root.cz/clanky/programovaci-jazyk-clojure-prace-s-mapami-a-mnozinami/
  22. Programovací jazyk Clojure – základy zpracování XML
    http://www.root.cz/clanky/programovaci-jazyk-clojure-zaklady-zpracovani-xml/
  23. Programovací jazyk Clojure – testování s využitím knihovny Expectations
    http://www.root.cz/clanky/programovaci-jazyk-clojure-testovani-s-vyuzitim-knihovny-expectations/
  24. 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/
  25. Enlive – výkonný šablonovací systém pro jazyk Clojure
    http://www.root.cz/clanky/enlive-vykonny-sablonovaci-system-pro-jazyk-clojure/

11. Odkazy na Internetu

  1. Syntax pro selektory
    http://cgrand.github.io/en­live/syntax.html
  2. Clojure Cookbook: Templating HTML with Enlive
    https://github.com/clojure-cookbook/clojure-cookbook/blob/master/07_webapps/7–11_enlive.asciidoc
  3. An Introduction to Enlive
    https://github.com/swannodette/enlive-tutorial/
  4. Enlive na GitHubu
    https://github.com/cgrand/enlive
  5. Expectations: příklady atd.
    http://jayfields.com/expectations/
  6. Expectations na GitHubu
    https://github.com/jaycfi­elds/expectations
  7. Lein-expectations na GitHubu
    https://github.com/gar3thjon3s/lein-expectations
  8. Testing Clojure With Expectations
    https://semaphoreci.com/blog/2014/09/23/tes­ting-clojure-with-expectations.html
  9. Clojure testing TDD/BDD libraries: clojure.test vs Midje vs Expectations vs Speclj
    https://www.reddit.com/r/Clo­jure/comments/1viilt/cloju­re_testing_tddbdd_librari­es_clojuretest_vs/
  10. Testing: One assertion per test
    http://blog.jayfields.com/2007/06/tes­ting-one-assertion-per-test.html
  11. Rewriting Your Test Suite in Clojure in 24 hours
    http://blog.circleci.com/rewriting-your-test-suite-in-clojure-in-24-hours/
  12. Clojure doc: zipper
    http://clojuredocs.org/clo­jure.zip/zipper
  13. Clojure doc: parse
    http://clojuredocs.org/clo­jure.xml/parse
  14. Clojure doc: xml-zip
    http://clojuredocs.org/clojure.zip/xml-zip
  15. Clojure doc: xml-seq
    http://clojuredocs.org/clo­jure.core/xml-seq
  16. Parsing XML in Clojure
    https://github.com/clojuredocs/guides
  17. Clojure Zipper Over Nested Vector
    https://vitalyper.wordpres­s.com/2010/11/23/clojure-zipper-over-nested-vector/
  18. Understanding Clojure's PersistentVector implementation
    http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation
  19. Understanding Clojure's PersistentHashMap (deftwice…)
    http://blog.higher-order.net/2009/09/08/understanding-clojures-persistenthashmap-deftwice.html
  20. Assoc and Clojure's PersistentHashMap: part ii
    http://blog.higher-order.net/2010/08/16/assoc-and-clojures-persistenthashmap-part-ii.html
  21. Ideal Hashtrees (paper)
    http://lampwww.epfl.ch/pa­pers/idealhashtrees.pdf
  22. Clojure home page
    http://clojure.org/
  23. Clojure (downloads)
    http://clojure.org/downloads
  24. Clojure Sequences
    http://clojure.org/sequences
  25. Clojure Data Structures
    http://clojure.org/data_structures
  26. 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
  27. 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
  28. Clojure – Functional Programming for the JVM
    http://java.ociweb.com/mar­k/clojure/article.html
  29. Clojure quick reference
    http://faustus.webatu.com/clj-quick-ref.html
  30. 4Clojure
    http://www.4clojure.com/
  31. ClojureDoc (rozcestník s dokumentací jazyka Clojure)
    http://clojuredocs.org/
  32. Clojure (na Wikipedia EN)
    http://en.wikipedia.org/wiki/Clojure
  33. Clojure (na Wikipedia CS)
    http://cs.wikipedia.org/wiki/Clojure
  34. SICP (The Structure and Interpretation of Computer Programs)
    http://mitpress.mit.edu/sicp/
  35. Pure function
    http://en.wikipedia.org/wi­ki/Pure_function
  36. Funkcionální programování
    http://cs.wikipedia.org/wi­ki/Funkcionální_programová­ní
  37. Čistě funkcionální (datové struktury, jazyky, programování)
    http://cs.wikipedia.org/wi­ki/Čistě_funkcionální
  38. 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
  39. Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html
  40. Clojure Macro Tutorial (Part III: Syntax Quote)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html
  41. Tech behind Tech: Clojure Macros Simplified
    http://techbehindtech.com/2010/09/28/clo­jure-macros-simplified/
  42. Fatvat – Exploring functional programming: Clojure Macros
    http://www.fatvat.co.uk/2009/02/clo­jure-macros.html
  43. Eulerovo číslo
    http://cs.wikipedia.org/wi­ki/Eulerovo_číslo
  44. List comprehension
    http://en.wikipedia.org/wi­ki/List_comprehension
  45. List Comprehensions in Clojure
    http://asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html
  46. Clojure Programming Concepts: List Comprehension
    http://en.wikibooks.org/wi­ki/Clojure_Programming/Con­cepts#List_Comprehension
  47. Clojure core API: for macro
    http://clojure.github.com/clo­jure/clojure.core-api.html#clojure.core/for
  48. cirrus machina – The Clojure for macro
    http://www.cirrusmachina.com/blog/com­ment/the-clojure-for-macro/
  49. Riastradh's Lisp Style Rules
    http://mumble.net/~campbe­ll/scheme/style.txt
  50. Dynamic Languages Strike Back
    http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html
  51. Scripting: Higher Level Programming for the 21st Century
    http://www.tcl.tk/doc/scripting.html
  52. Java Virtual Machine Support for Non-Java Languages
    http://docs.oracle.com/ja­vase/7/docs/technotes/gui­des/vm/multiple-language-support.html
  53. Třída java.lang.String
    http://docs.oracle.com/ja­vase/7/docs/api/java/lang/Strin­g.html
  54. Třída java.lang.StringBuffer
    http://docs.oracle.com/ja­vase/7/docs/api/java/lang/Strin­gBuffer.html
  55. Třída java.lang.StringBuilder
    http://docs.oracle.com/ja­vase/7/docs/api/java/lang/Strin­gBuilder.html
  56. StringBuffer versus String
    http://www.javaworld.com/ar­ticle/2076072/build-ci-sdlc/stringbuffer-versus-string.html
  57. Threading macro (dokumentace k jazyku Clojure)
    https://clojure.github.io/clo­jure/clojure.core-api.html#clojure.core/->
  58. Understanding the Clojure → macro
    http://blog.fogus.me/2009/09/04/un­derstanding-the-clojure-macro/
  59. clojure.inspector
    http://clojure.github.io/clo­jure/clojure.inspector-api.html
  60. The Clojure Toolbox
    http://www.clojure-toolbox.com/
  61. Unit Testing in Clojure
    http://nakkaya.com/2009/11/18/unit-testing-in-clojure/
  62. Testing in Clojure (Part-1: Unit testing)
    http://blog.knoldus.com/2014/03/22/tes­ting-in-clojure-part-1-unit-testing/
  63. API for clojure.test – Clojure v1.6 (stable)
    https://clojure.github.io/clo­jure/clojure.test-api.html
  64. Leiningen: úvodní stránka
    http://leiningen.org/
  65. Leiningen: Git repository
    https://github.com/techno­mancy/leiningen
  66. leiningen-win-installer
    http://leiningen-win-installer.djpowell.net/
  67. Clojure 1: Úvod
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/
  68. Clojure 2: Symboly, kolekce atd.
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/
  69. 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/
  70. 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/
  71. 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/
  72. Clojure 6: Podpora pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/
  73. Clojure 7: Další funkce pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/
  74. 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/
  75. 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/
  76. Clojure 10: Kooperace mezi Clojure a Javou
    http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/
  77. Clojure 11: Generátorová notace seznamu/list comprehension
    http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/
  78. 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/
  79. 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/
  80. Clojure 14: Základy práce se systémem maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/
  81. Clojure 15: Tvorba uživatelských maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/
  82. Clojure 16: Složitější uživatelská makra
    http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/
  83. Clojure 17: Využití standardních maker v praxi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/
  84. Clojure 18: Základní techniky optimalizace aplikací
    http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/
  85. Clojure 19: Vývojová prostředí pro Clojure
    http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/
  86. 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/
  87. Clojure 21: ClojureScript aneb překlad Clojure do JS
    http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/
  88. Clojure.org: Vars and the Global Environment
    http://clojure.org/Vars
  89. Clojure.org: Refs and Transactions
    http://clojure.org/Refs
  90. Clojure.org: Atoms
    http://clojure.org/Atoms
  91. Clojure.org: Agents as Asynchronous Actions
    http://clojure.org/agents
  92. Transient Data Structureshttp://clojure.or­g/transients
Našli jste v článku chybu?
Podnikatel.cz: Byla finanční manažerka, teď cvičí jógu

Byla finanční manažerka, teď cvičí jógu

DigiZone.cz: RRTV: licence pro Šlágr TV

RRTV: licence pro Šlágr TV

Podnikatel.cz: Letáky? Lidi zuří, ale ony stále fungují

Letáky? Lidi zuří, ale ony stále fungují

Lupa.cz: Patička e-mailu závazná jako vlastnoruční podpis?

Patička e-mailu závazná jako vlastnoruční podpis?

Podnikatel.cz: Znáte už 5 novinek k #EET

Znáte už 5 novinek k #EET

Vitalia.cz: Nová vakcína proti chřipce se aplikuje nosem

Nová vakcína proti chřipce se aplikuje nosem

Vitalia.cz: Tesco nabízí desítky tun jídla zdarma

Tesco nabízí desítky tun jídla zdarma

Podnikatel.cz: Noví úředníci na finančáku za miliony

Noví úředníci na finančáku za miliony

Vitalia.cz: Tradiční čínská medicína a rakovina

Tradiční čínská medicína a rakovina

Podnikatel.cz: Udělali jsme velkou chybu, napsal Čupr

Udělali jsme velkou chybu, napsal Čupr

Lupa.cz: Proč jsou firemní počítače pomalé?

Proč jsou firemní počítače pomalé?

Měšec.cz: TEST: Vyzkoušeli jsme pražské taxikáře

TEST: Vyzkoušeli jsme pražské taxikáře

DigiZone.cz: DVB-T2 ověřeno: seznam TV zveřejněn

DVB-T2 ověřeno: seznam TV zveřejněn

DigiZone.cz: Nova opět stahuje „milionáře“

Nova opět stahuje „milionáře“

120na80.cz: Galerie: Čínští policisté testují českou minerálku

Galerie: Čínští policisté testují českou minerálku

DigiZone.cz: Technisat připravuje trojici DAB

Technisat připravuje trojici DAB

Vitalia.cz: Tahák, jak vyzrát nad zápachem z úst

Tahák, jak vyzrát nad zápachem z úst

Root.cz: Hořící telefon Samsung Note 7 zapálil auto

Hořící telefon Samsung Note 7 zapálil auto

Vitalia.cz: Jsou vegani a vyrábějí nemléko

Jsou vegani a vyrábějí nemléko

Podnikatel.cz: ČSSZ posílá přehled o důchodovém kontě

ČSSZ posílá přehled o důchodovém kontě