2013年3月10日日曜日

[Clojure]PegDownとJavaFXでMarkdownを表示する

JavaFXにはHTMLをレンダリングしてくれる WebView というコンポーネントがあるようです。

JavaのMarkdownプロセッサ PegDown と WebView を利用して Markdownファイルを画面に表示してみます。

;; leiningenでAOTコンパイルするファイルを指定
:aot [markdown-viewer.App]
;; App.clj
(ns markdown-viewer.App
  (:import javafx.application.Application
           javafx.scene.Scene
           javafx.scene.control.Label
           javafx.scene.web.WebView
           javafx.stage.Stage
           javafx.stage.FileChooser
           javafx.stage.FileChooser$ExtensionFilter
           [org.pegdown PegDownProcessor Extensions])
  (:gen-class
   :extends javafx.application.Application))

(defn md->html [^String source]
  (let [parser (PegDownProcessor. Extensions/ALL)]
    (.markdownToHtml parser source)))

(defn make-md-file-chooser ^FileChooser []
  (let [fc (FileChooser.)]
    (.setTitle fc "select Markdown file")
    (-> fc .getExtensionFilters
        (.add (FileChooser$ExtensionFilter. "Markdown" ["*.md" "*.markdown"])))
    fc))

(defn load-html [^WebView wview ^String html]
  (.loadContent (.getEngine wview) html))

(defn load-md [wview md]
  (load-html wview (md->html md)))

(defn -start [this ^Stage stage]
  (let [wview (WebView.)
        fc (make-md-file-chooser)
        ;; ファイル選択
        file (.showOpenDialog fc stage)]
    (when file
      (.setScene stage (Scene. wview 750 500))
      (load-md wview (slurp file))
      (.show stage))))
;; core.clj
(ns markdown-viewer.core
  (require markdown-viewer.App)
  (:gen-class))

(defn -main [& args]
  (javafx.application.Application/launch markdown_viewer.App args))

2013年3月6日水曜日

[Clojure]動的にライブラリを追加する

nREPL経由でClojureを使っていると、再起動させずにライブラリを読み込みたいと思うことがあります。 pomegranate というライブラリを使うと、動的にライブラリを取得してクラスパスに追加してくれます。

leiningenのprofile.cljやproject.cljにライブラリを追加します。

;; :dependenciesに追加
[com.cemerick/pomegranate "0.0.13"]

READMEにある例は以下のようになっています。

(use '[cemerick.pomegranate :only (add-dependencies)])

;; Maven CentralとClojarsをレポジトリとして指定し、incanterを取得
(add-dependencies
 :coordinates '[[incanter "1.5.0-SNAPSHOT"]]
 ;; proxyも指定可能
 ;; :proxy {:host "x.x.x.x" :port 8080}
 :repositories (merge cemerick.pomegranate.aether/maven-central
                      {"clojars" "http://clojars.org/repo"}))

;; Incanterを使ってみる
(use '[incanter core charts])
(doto (function-plot sin -4 4 :y-label "y" :series-label "sin" :legend true)
  (add-function cos -4 4 :series-label "cos")
  view)

[Clojure]Cloverageでカバレッジ計測

Clojureのカバレッジ計測用ライブラリ Cloverage を使ってみます。

leiningenのプラグインとして利用できるので、profile.cljの:pluginsにプラグインを追加します。

;; ~/.lein/profile.clj の :plugins に追加
[lein-cloverage "1.0.2"]

カバレッジの計測対象となるプロジェクトを作成します。

> lein new cloverage-test

プログラムを作成します。

;; src/cloverage_test/core.clj
(ns cloverage-test.core)

(defn fizzbuzz [n]
  (case (mod n 15)
    0 "fizzbuzz"
    (3 6 9 12) "fizz"
    (5 10) "buzz"
    (str n)))

(defn run [end]
  (mapv fizzbuzz (range 1 (inc end))))

テストコードを作成します。

;; test/cloverage_test/core_test.clj
(ns cloverage-test.core-test
  (:use clojure.test
        cloverage-test.core))

(deftest fizzbuzz-test
  (testing "run"
    (is (= ["1" "2" "fizz"] (run 3)))))

テスト+カバレッジ計測を実行します。(lein cloverage)

 > lein cloverage
Test namespaces:  (cloverage-test.core-test)
Performance warning, cloverage_test/core.clj:3 - case has int tests, but tested expression is not primitive.
Loaded  cloverage-test.core  .
Instrumented namespaces.

Testing cloverage-test.core-test

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.
Ran tests.
Produced output in /home/kurohuku/project/cloverage-test/target/coverage .
HTML: file:///home/kurohuku/project/cloverage-test/target/coverage/index.html

以下のようなHTMLが出力されます。

テストコードを追加してすべての行が実行するようにしてみます。

;; test/cloverage_test/core_test.clj
(ns cloverage-test.core-test
  (:use clojure.test
        cloverage-test.core))

(deftest fizzbuzz-test
  (testing "run"
    (is (= ["1" "2" "fizz" "4" "buzz"
            "fizz" "7" "8" "fizz" "buzz"
            "11" "fizz" "13" "14" "fizzbuzz"]
           (run 15)))))

2013年3月5日火曜日

[Clojure]LWJGLをでOpenGL

LWJGLでOpenGLの画面を表示してみます。 Javaで書くのと大差無いです。多分。

;; dependenciesに追加
[org.lwjgl/lwjgl "2.7.1"]
[org.lwjgl/lwjgl-util "2.7.1"]
[org.lwjgl/lwjgl-native-platform "2.7.1"]
(import '[org.lwjgl.opengl DisplayMode Display GL11])

(def width 640)
(def height 480)
(def display-mode (DisplayMode. width height))

(defn draw []
  (GL11/glClear GL11/GL_COLOR_BUFFER_BIT)
  (GL11/glBegin GL11/GL_LINES)
  (GL11/glColor3d 1.0 0.0 0.0)
  (GL11/glVertex3d 1.0 1.0 0.0)
  (GL11/glVertex3d (- width 1) (- height 1) 0.0)
  (GL11/glEnd)
  (GL11/glFlush))

(defn start []
  (Display/setDisplayMode display-mode)
  (Display/setTitle "Hello")
  (Display/create)
  (GL11/glEnable GL11/GL_CULL_FACE)
  (GL11/glCullFace GL11/GL_BACK)
  (GL11/glMatrixMode GL11/GL_PROJECTION)
  (GL11/glLoadIdentity)
  (GL11/glOrtho 0 width 0 height 0 1)
  (GL11/glMatrixMode GL11/GL_MODELVIEW)
  (while (not (Display/isCloseRequested))
    (draw)
    (Display/update))
  (Display/destroy))

; (start)

CやC++でOpenGLを書く必要に迫られたら、プロトタイプをClojureで書いてみることもできそうです。