31. března 2012

Změna syntax highlightingu a konvence kódu


Změna syntax highlightingu
Když jsem začínal psát tenhle blog, řešil jsem, jak prezentovat ukázky kódu, tedy syntax highlighting. Tehdy jsem zvolil řešení, které jsem dost často vídal na jiných blozích - SyntaxHighlighter. Řešení je to sice pěkné, ale bohužel pro Clojure neobsahuje oficiální brush a ten který byl k dispozici neoficiálně, nepokrýval plně syntaxi Clojure.

Shodou okolností, tento rok mám takové malé jubileum - už deset let jsem uživatelem Linuxu a protože hned na počátku jsem řešil klasické linuxové dilema, jestli programovat v Vi(m)u nebo v Emacsu a tehdy jsem zvolil Vim (a dodones nelituju); můžu zároveň říct, že jsem i desetiletý uživatel Vimu.

No, zpátky k syntaxi.Vim obsahuje funkci na převod kódu do HTML:
  • v textové verzi se zadá příkaz :TOhtml,
  • v GUI verzi je to v menu Syntax -> Convert to HTML.
Pro úplnost bych ještě doplnil, že Vim neumí syntaxi Clojure sám od sebe, ale je potřeba "doinstalovat" plugin VimClojure.
Změna code convention
Když už jsem řešil změnu syntax highlightingu (protože jsem to musel ručně poměnit u všech publikovaných postů), rozhodl jsem se změnit i code convention - to, jak budu zapisovat ukázky kódu. Sympatická mi přijde konvence použitá v knize The Joy of Clojure, která spočívá v tom, že se:
  • píše čistý Clojure kód,
  • nepíše se výzva REPLu, nebo příkazového řádku a
  • výpisy na standard output se vypisují za příkaz jako komentáře.
Výhodou téhle konvence je, že kód lze rovnou bez úprav zkopírovat a spustit ho v REPLu nebo vložit do skriptu a zároveň je vidět, co kód dělá (jeho výstup).

Takže místo:
user=> (def my-ref (ref "immutable data"))
#'user/my-ref
user=> my-ref
#<Ref@467d8ddd: "immutable data">
user=> @my-ref
"immutable data"
user=> (deref my-ref)
"immutable data"

vypadá kód takto:
(def my-ref (ref "immutable data"))
; #'user/my-ref
my-ref
; #<ref@18352d8: "immutable data">
@my-ref
; "immutable data"
(deref my-ref)
; "immutable data"
To je celkem přehledný, ne?

27. října 2011

Zemřel John McCarthy, tvůrce Lispu

V pondělí 24. října zemřel ve věku 84 let vynálezce Lispu John McCarthy. Je zajímavé, že McCarthy Lisp pouze navrhl - v roce 1958 publikoval článek Recursive Functions of Symbolic Expressions and Their Computation by Machine. Jazyk samotný byl později implementován Stevem Russellem.

Zajímavé také je, že McCarthy původně používal  M-expressions (meta expressions) v hranatých závorkách, které se ovšem dají přeložit na klasické "lispovské" S-expressions (symbolic expressions). Když byl ale Lisp implementován, začali programátoři používat právě s-expressions a tak McCarthy od používání m-expressions upustil.

McCarthy se do historie nezapsal pouze jako tvůrce Lispu, ale i mnoha dalšími počiny, např. vynálezem garbage collection (mmj. právě kvůli problémům ohledně Lispu), nebo zavedením termínu Artificial Intelligence.

16. srpna 2011

ThoughtWorks Radar zmiňuje Clojure

Firmu ThoughtWorks znám hlavně protože zde pracuje můj oblíbený SW guru Martin Fowler. Nedávno vyšel jejich Technology Radar, který zmiňuje "rozvíjející se technologie a trendy, které ovlivňují dnešní trh".



Pro tento blog je podstatné, že je zde třikrát zmíněno Clojure. Jednak jako samotný jazyk:

"Clojure is a dynamic, functional language that runs on the JVM. Although its roots are in Lisp, one of the oldest computer languages, it also embodies many modern programming concepts, including lazy evaluation and advanced concurrency abstractions. Clojure has spawned a vibrant community of programmers who are contributing a rich set of frameworks and tools. One example of these is Midje, an innovative spin on unit testing and mocking frameworks."

Clojure se v sekci Languages nachází v kruhu Assess, to znamená "Worth exploring with the goal of understanding how it will affect your enterprise.".


Dále je v sekci Interesting Tools uveden framework Midje, "nástroj pro čitelné testy v Clojure". A konečně je Clojure zmíněno v souvislosti s cloud platformou Heroku, kam bylo přidáno jako jeden z jazyků.

Z trochu jiného úhlu pohledu píšu o Radaru, na svém blogu o softwarovém inženýrství, SoftWare Samuraj.

15. srpna 2011

Testování v Clojure

Ačkoliv Rich Hickey říká, že nepíše unit testy, přece jenom do Clojure zahrnul "framework" pro unit testy. Já sám, naopak, jsem již léty TDD infikován a testy píšu rád. Takže, jak se to dělá v Clojure? Nejprve natáhneme knihovnu clojure.test:
(ns my-tests (:use clojure.test))
; nil

Aserce (tvrzení)

Základem testů je makro is:
(is (= 2 (+ 1 1)))
; true
(is (odd? 1))
; true
(is (even? 1) "truth about one")
; 
; FAIL in clojure.lang.PersistentList$EmptyList@1 (NO_SOURCE_FILE:30)
; truth about one
; expected: (even? 1)
;   actual: (not (even? 1))
; false
Více assertions/parametrů se dá testovat pomocí makra are:
(are [x y] (= 42 (+ x y))
     21 21
     20 22
     42 0)
; true
Vyhození výjimky se dá otestovat pomocí funkce thrown?:
(is (thrown? ArithmeticException (/ 42 0)))
; #<ArithmeticException java.lang.ArithmeticException: Divide by zero>
(is (thrown? ArithmeticException (/ 42 42)))
; 
; FAIL in clojure.lang.PersistentList$EmptyList@1 (NO_SOURCE_FILE:48)
; expected: (thrown? ArithmeticException (/ 42 42))
;   actual: nil
; nil

Definice testů

OK, to byly tvrzení (assertions). Jak definuji test? Jedna z možností je makro with-test:
(with-test
    (defn add [x y]
        (+ x y))
    (is (= 42 (add 21 21)))
    (is (= 42 (add 20 22)))
    (is (= 42 (add 42 0))))
Druhou možností je použít makro deftest. Jeho výhodou je, že vytváří funkci (v našem případě ultimate-addition), kterou lze zavolat z libovolného namespace. To umožňuje mít testy v samostatném souboru tak, jak jsme z unit testů zvyklí.
(deftest ultimate-addition
    (is (= 42 (add 21 21)))
    (is (= 42 (add 20 22)))
    (is (= 42 (add 42 0))))

Spuštění testů

Máme definované dva testy (a šest asercí). Jak je spustíme? Testy v aktuálním namespace odpálíme funkcí run-tests:
(run-tests)
;
; Testing my-tests
;
; Ran 2 tests containing 6 assertions.
; 0 failures, 0 errors.
; {:type :summary, :pass 6, :test 2, :error 0, :fail 0}
Testy v jiném namespace spustíme obdobně:
(run-tests 'some.namespace 'some.other.namespace)

Automatizace testů

Tak. Konec srandiček! Velký kluci buildujou (a spouští testy) Leiningenem. Prvně vytvoříme projekt příkazem lein new lein-tests:

Vytvoření a layout projektu

Test first! Napíšeme testy (soubor core.clj v adresáři test):
(ns lein-tests.test.core
  (:use [lein-tests.core])
  (:use [clojure.test]))

(deftest split-line-test
  (is (= ["foo" "bar"]
         (split-line "foo;bar" #";")))
  (is (= ["foo" "bar"]
         (split-line "foo,bar" #", ?")))
  (is (= ["foo" "bar"]
         (split-line "foo, bar" #", ?"))))

(deftest get-phone-test
  (is (= "123456789"
         (get-phone "123456789;Guido")))
  (is (= ""
         (get-phone ";Guido"))))
A napíšeme (testované) funkce (soubor core.clj v adresáři src):
(ns lein-tests.core
  (:use [clojure.string :only (split)]))

(defn split-line [line separator]
  (split line separator))

(defn get-phone [line]
  (first (split-line line #";")))
No a na závěr testy spustíme příkazem lein test. Nádhera!

Spuštění testů

13. srpna 2011

Změna domény: clojure.cz

Tak je to už sedm měsíců, co píšu Sometimes Clojure. Včera jsem se jen tak z rozmaru podíval, jestli je volná doména clojure.cz. Byla. Tak jsem si ji vzal. Zatím se mi zdá, že jsem jediný, kdo o Clojure v Česku píše, tak co. Třeba jednou vznikne komunitní web, nebo něco. Ale teď je moje! My precious!! :-)

11. srpna 2011

Nazdar světe! říká ClojureScript

Tak jsem se neudržel a ClojureScript si vyzkoušel. Následuje popis (jednoho zápasu), jak si vyrobit Hello, world! v ClojureScriptu. Vzhledem k tomu, že ClojureScript je zatím v alpha verzi a Windows (kde jsem to musel z časových důvodů vyzkoušet) tradičně hází vývojářům klacky pod nohy :-/ se instalace, kompilace a vyzkoušení triviálního příkladu protáhlo na několik hodin. Nicméně zvítězil jsem a tady je výsledek.

Nebudu se zabývat instalací ClojureScriptu - je dobře popsána ve wiki projektuWindows instalace je trochu dramatičtější. Navíc v případě Windows je problém, pokud se kompilace provádí v cestě s mezerami (Documents and Settings apod.), je při optimalizovaném překladu vyhozena výjimka.

Tak, máme nainstalováno? Spustíme z příkazové řádky příkaz cljsc (ClojureScript compiler):
C:\clojure-clojurescript\samples\my-hello>cljsc
Usage: "cljsc <file-or-dir> > out.js"
       "cljsc <file-or-dir> {:optimiztions :advanced} > out.js"
No. Co/k čemu ten ClojureScript vlastně je? ClojureScript je dialekt Clojure (spíš podmnožina). Nejdůležitější je jeho kompilátor, který umožňuje zkompilovat Clojure(Script) do JavaScriptu. Pokud by někoho zajímaly filozofické důvody pro vznik ClojureScriptu, jsou uvedeny ve wiki na stránce Rationale (odůvodnění). V podstatě jde asi o to, dostat Clojure i na jinou platformu než JVM, v tomto případě JavaScript VM.

ClojureScript kompilátor generuje JavaScript, který (záměrně) odpovídá konvenci JavaScriptové knihovny Google Closure. Důvod je zřejmý - (Google) Closure Compiler. Tím se vysvětlují dva způsoby použití kompilátoru cljsc:
  • cljsc <file-or-dir> > out.js spustí pouze ClojureScript kompilátor a výsledný soubor "slinkuje" s knihovnou Closure Library.
  • cljsc <file-or-dir> {:optimiztions :advanced} > out.js dělá totéž, plus ještě následně prožene výsledný kód Closure Compilerem, který kód zoptimalizuje a vytvoří jeden kompaktní soubor.
Takže, pojďme se podívat na ten příklad. Vytvořím soubor hello.cljs. Metadata ^:export u definice funkce říkají, aby název výsledné funkce nebyl kompilátorem minifikovaný.
(ns hello)

(defn ^:export greet [n]
    (str "Hello, " n "!"))
Následně ho zkompiluju:
cljsc hello.cljs {:optimizations :advanced} > hello.js
A výsledný kód zavolám v prohlížeči:
<html>
<head>
    <title>ClojureScript</title>
    <script src="hello.js" type="text/javascript">
</script>
</head>
<body>
    <script type="text/javascript">
            alert(hello.greet("ClojureScript"));
    </script>
</body>
</html>
A výsledek?


Uf! Byla to dřina. :-|

Když to vezmu prakticky, tak zatím ClojureScript moc použitelný není. Problém jsou hlavně chybějící nástroje. Pokud ale jednou bude zaintegrován například do Leiningenu nebo Mavenu, tak si dokážu představit, že třeba ve spojení s Compojure půjde vytvořit kompletní webovou (klient/server) aplikaci pouze v Clojure. To by bylo komfortní.

10. srpna 2011

PragPub píše o ClojureScriptu

V uplynulých dnech se mojí (Google Reader) čtečkou prohnala smršť zpráviček a anoncí o ClojureScriptu. Nevím, jestli to není jen hype, který se kumuluje kolem CoffeeScriptu. Navíc ClojureScript je již nějaký čas součástí knihovny clojure-contrib.

Každopádně aktuální číslo mého oblíbeného e-časopisu PragPub obsahuje článek o ClojureScriptu. Kromě HTML jsou k dispozici i formáty mobi, epub a PDF.